在 wxPython 面板中加载新图像时,Matplotlib RectangleSelector 消失

Matplotlib RectangleSelector disappears when new image loaded in wxPython panel

我在 wxPython 面板中有一张图像,我想通过使用 Matplotlib RectangleSelector 选择来编辑它。我有一个 Image_Viewer class 来绘制图像。我有一个 Editor class,其中包含 RectangleSelector 功能。 Editor 继承自 Image_Viewer。最后,控制面板包含文件选择器按钮。该程序以通过 Image_Viewer 绘制函数加载的默认图像开始。我可以很好地使用 RectangleSelector。但是当我加载一个新图像时,它也通过 Image_Viewer 绘制函数加载,所有与 RectangleSelector 的连接都消失了。

我已尽力减少代码,但整个代码是多选项卡式笔记本的一部分,因此存在 wx.lib.agw.aui 和其他可能的特性。

import os
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import wx
import wx.lib.agw.aui as aui
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.widgets import RectangleSelector
from matplotlib.patches import Rectangle

# ------------------variables-------------------
# Base path
pth = os.path.dirname(os.path.abspath('__file__'))
# folder for gui graphics
gui_graphics = pth + '/gui_graphics'
# temp file for initial image handling
img_pth = os.path.join(pth, "tmp_img.png")
# Folders, subfolders for processed images
all_cats = pth + '/Cats'
new_cats = all_cats + '/new_cats'

min_img_wndw = 295      # min size of top panels
img_y, img_x = 64, 64   # raw cat size

class Image_Viewer(wx.Panel):
    def __init__(self, parent):
        super(Image_Viewer, self).__init__(parent)
        #load image
        im_pth = new_cats + '/av_cat'
        files = os.listdir(im_pth)
        im_pths = [os.path.join(im_pth, im_name) for im_name in files]
        try:
            self.img = max(im_pths, key=os.path.getctime)
            self.image = cv.imread(self.img)
        except:
            self.image = np.zeros((img_x, img_y), np.uint8)

        self.figure = Figure()
        self.draw(self.image)

    def draw(self, image):
        plt.close(self.figure)
        self.figure.clf()
        self.axes = self.figure.add_axes([0, 0, 1, 1])
        self.axes.axis('off')
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.EXPAND)
        self.SetSizer(self.sizer)
        self.axes.imshow(image, cmap='gray', vmin=0, vmax=255)
        self.canvas.draw()

class Editor(Image_Viewer):
    def __init__(self, parent):
        super(Editor, self).__init__(parent)

        self.RS = RectangleSelector(self.axes, self.on_click,
                                    drawtype='box', useblit=True,
                                    button=[1, 3],  # don't use middle button
                                    minspanx=5, minspany=5,
                                    spancoords='pixels',
                                    interactive=True)
        #self.canvas.draw()
        cid = self.canvas.mpl_connect('MouseEvent', self.on_click)
        print(cid)

    def on_click(self, eclick, erelease):
        print("You clicked")
        'eclick and erelease are the press and release events'
        x1, y1 = eclick.xdata, eclick.ydata
        x2, y2 = erelease.xdata, erelease.ydata
        w = int(x2-x1)
        h = int(y2 - y1)

class control_Panel(wx.Panel):
    def __init__(self, parent, image_panel):     #, image_panel, terminal_panel
        wx.Panel.__init__(self, parent=parent)
        #self.panel = wx.Panel(self, -1, size=(580, 180))
        self.screen = image_panel

        self.pth = os.path.dirname(os.path.abspath('__file__'))
        fileDlgBtn = wx.Button(self, label="Get Cats")
        fileDlgBtn.Bind(wx.EVT_BUTTON, self.OnOpen)

    def OnOpen(self, event):
        with wx.FileDialog(self, "Open image file", wildcard="PNG files (*.png)|*.png",
                           style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return     # the user changed their mind

            # Proceed loading the file chosen by the user
            pathname = fileDialog.GetPath()
            image = cv.imread(pathname)
            self.screen.draw(image)

class explorer_panel(wx.Panel):
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        bSplitter = wx.SplitterWindow(self)
        image_panel = Editor(bSplitter)
        panelThree = control_Panel(bSplitter, image_panel)  

        bSplitter.SplitHorizontally(image_panel, panelThree)
        bSplitter.SetSashGravity(0.5)

        bSplitter.SetMinimumPaneSize(min_img_wndw)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(bSplitter, 1, wx.EXPAND)
        self.SetSizer(sizer)

class Main(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(
            self, 
            parent = None, 
            title = "Borges Infinite Image", 
            size = (600,550)
            )
        self.SetIcon(wx.Icon(gui_graphics + '/Abe.png'))

        panel = wx.Panel(self)
        notebook = aui.AuiNotebook(panel)
        explorer = explorer_panel(notebook)
        notebook.AddPage(explorer, 'Explorer')
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5)
        panel.SetSizer(sizer)

if __name__ == "__main__":
    app = wx.App()
    frame = Main()
    frame.Show()
    app.MainLoop()

我无法测试你的代码,因为我没有安装 wx atm,但我很确定你的问题源于你每次加载新图片时都创建了一个新图形和新 canvas。

我相信你应该创建一个 Figure 和一组坐标轴,然后用新图片替换这些坐标轴的内容

例如

class Image_Viewer(wx.Panel):
    def __init__(self, parent):
        (...)

        self.figure = Figure()
        self.axes = self.figure.add_axes([0, 0, 1, 1])
        self.axes.axis('off')
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.EXPAND)
        self.SetSizer(self.sizer)
        self.draw(self.image)

    def draw(self, image):
       self.axes.cla()
       self.axes.imshow(image, cmap='gray', vmin=0, vmax=255)
       self.canvas.draw()