在 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()
我在 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()