在wx中使用matplotlib显示numpy数组

1 投票
1 回答
1133 浏览
提问于 2025-04-16 20:32

我有一个很大的numpy数组,形状是(M x N x 3),数据类型是float32。我想把这个图像显示在一个wx.Frame窗口里,并且这个窗口里有一个wx.ScrolledWindow。我希望图像能以100%的大小显示,而且非常重要的是,不能有数据丢失。这些是超高分辨率的X光图像,必须保持浮点值。

到目前为止,wx.Image的功能不太行,因为它只接受8位整数的数组,这样不够用。

PIL图像库也只能处理8位的,显然不够。

目前我找到的唯一合适的库是matplotlib,但我在让matplotlib按我想要的方式显示时遇到了麻烦。这段代码让我接近目标:

class View(wx.Frame):  
    def __init__(self):
        wx.Frame.__init__(self,  
                          parent=None,  
                          title="DICOM Viewer",  
                          size=(1280, 750),  
                          pos=(0,0))  
        self.scroll = wx.ScrolledWindow(self, -1)
        self.figure = plt.Figure()  
        self.canvas = FigureCanvasWxAgg(self.scroll, -1, self.figure)  
        self.axes = Axes(self.figure, [0,1,0,1])       
        self.figure.figimage(ndarray)     
        self.sizer.Add(self.canvas, 1, wx.EXPAND)  
        self.scroll.SetSizer(self.sizer)

figimage函数只会显示原始像素,这正是我想要的,但它只填充wxFrame可视区域,而且速度非常慢。可能是我的wx控件有问题?

一个更好的解决方案是使用imshow,如下所示:

class View(wx.Frame):  
    def __init__(self):
        wx.Frame.__init__(self,  
                          parent=None,  
                          title="DICOM Viewer",  
                          size=(1280, 750),  
                          pos=(0,0))  
        self.scroll = wx.ScrolledWindow(self, -1)  
        self.figure = plt.Figure()  
        self.canvas = FigureCanvasWxAgg(self.scroll, -1, self.figure)  
        self.axes = Axes(self.figure, [0,1,0,1])  
        self.axes = self.figure.add_subplot(111)  
        self.axes.imshow(ndarray)  
        self.sizer.Add(self.canvas, 1, wx.EXPAND)    
        self.scroll.SetSizer(self.sizer)

不过,这样做会在图表周围留出很多空白,还会出现不必要的坐标轴和标签,并且会自动缩放图像以适应可视区域。虽然像素质量还是有的,但需要添加mpl工具栏,还要手动平移,如果平移得太远,可能会失去对图像的控制。

1 个回答

1

我找到了解决办法:

class View(wx.Frame):  
   def __init__(self):
     wx.Frame.__init__(self,  
                      parent=None,  
                      title="DICOM Viewer",  
                      size=(1280, 750),  
                      pos=(0,0))  
     self.scroll = wx.ScrolledWindow(self, -1)
     h, w, r = ndarray.shape
     self.figure = plt.Figure((w/72.0,h/72.0), 72)  #manually determine the figure size in inches
     self.canvas = FigureCanvasWxAgg(self.scroll, -1, self.figure)  
     self.axes = self.figure.add_axes([0.0, 0.0, 1.0, 1.0]) #size of axes to match size of figure
     self.axes.imshow(ndarray) 

关键是手动设置图形的大小,让它和图片的实际大小一致(以英寸为单位),然后把图形的坐标轴也设置成一样的大小。这样就能防止mpl自动调整我的图片大小,以适应可视区域。我还去掉了调整器,因为我手动设置了滚动条的虚拟区域、图形和坐标轴的大小。现在如果能把图形顶部的边距去掉就完美了。

撰写回答