wxPython图像占用大量内存

wxPython图像占用大量内存,python,wxpython,Python,Wxpython,我有一个数据项目,它只在不同的目录中生成许多同名的绘图。查看这些图有助于了解数据是否有任何问题,但尝试逐个打开它们或将它们复制到一个目录,重命名它们,然后打开我的标准图像查看器将是一件痛苦的事情 了解了一些wxpythongui编程之后,我决定开发一个应用程序,它将包含这些图像的目录列表,并且我可以用一些箭头按钮幻灯片显示它们。当更多的情节出现时,我可以添加到这个列表中 我让应用程序正常运行,但现在当我加载大约23~3MB的图像时,我的程序内存使用量达到了10GB 代码如下,但简而言之,在显示之

我有一个数据项目,它只在不同的目录中生成许多同名的绘图。查看这些图有助于了解数据是否有任何问题,但尝试逐个打开它们或将它们复制到一个目录,重命名它们,然后打开我的标准图像查看器将是一件痛苦的事情

了解了一些wxpythongui编程之后,我决定开发一个应用程序,它将包含这些图像的目录列表,并且我可以用一些箭头按钮幻灯片显示它们。当更多的情节出现时,我可以添加到这个列表中

我让应用程序正常运行,但现在当我加载大约23~3MB的图像时,我的程序内存使用量达到了10GB

代码如下,但简而言之,在显示之前,我将它们全部加载为wxPython图像,这就是内存增加的地方。通过堆栈在图像之间切换似乎不会使内存进一步攀升。我想可能是我保留了不再需要的资源,但是使用率似乎与图像的大小和数量不成比例

有人能指出我方法中的缺陷吗

```

课堂幻灯片(wx.Frame):
定义初始化(自):
wx.Frame.\uuuuu init\uuuuuuuuu(self,None,-1,“幻灯片放映”)
self.display=wx.GetDisplaySize()
self.image\u list=无
self.current=None#保存当前显示的位图
#保存位图的堆栈
self.future=[]
self.pass=[]
self.left=wx.BitmapButton(self,id=101,size=(100,-1),bitmap=wx.ArtProvider.GetBitmap(wx.ART\u返回))
self.left.Enable(False)
self.right=wx.BitmapButton(self,id=102,size=(100,-1),bitmap=wx.ArtProvider.GetBitmap(wx.ART\u前进))
self.right.Enable(False)
self.open=wx.BitmapButton(self,id=103,size=(100,-1),bitmap=wx.ArtProvider.GetBitmap(wx.ART\u FILE\u open))
#测试代码
#png=wx.Image(“set001\u fit\u 001\u 1.png”,wx.BITMAP\u TYPE\u ANY).ConvertToBitmap()
#image=wx.ImageFromBitmap(png)
#image=image.Scale(self.display[0]/1.4,self.display[1]/1.4,wx.image\u-QUALITY\u-HIGH)
#png=wx.BitmapFromImage(图像)
#使图像槽为空
self.img=wx.StaticBitmap(self,-1,size=(self.display[0]/1.4,self.display[1]/1.4))
##主要施胶剂
self.vertSizer=wx.BoxSizer(wx.VERTICAL)
#小尺寸
self.buttonizer=wx.BoxSizer(wx.水平)
#把按钮放在一起
self.buttonizer.Add(self.left,flag=wx.ALIGN\u CENTER)
als.AddLinearSpacer(self.buttonSizer,15)
self.buttonizer.Add(self.right,flag=wx.ALIGN\u CENTER)
#放置箭头并一起打开
self.vertSizer.Add(self.img,flag=wx.ALIGN\u CENTER)
self.vertSizer.Add(self.open,flag=wx.ALIGN\u CENTER)
als.AddLinearSpacer(self.vertSizer,15)
self.vertSizer.Add(self.buttonizer,flag=wx.ALIGN\u CENTER)
als.AddLinearSpacer(self.vertSizer,15)
self.Bind(wx.EVT_按钮,self.onOpen,id=103)
self.Bind(wx.EVT_按钮,self.onLeft,id=101)
self.Bind(wx.EVT_按钮,self.onRight,id=102)
self.setizer(self.vertSizer)
self.vertSizer.Fit(self)
def onOpen(自身、evt):
打印(“打开”)
openFileDialog=wx.FileDialog(self,“打开图像列表”,“打开图像列表”,“列表(*.ls)|*.ls”,wx.FD|Open | wx.FD|u文件必须存在)
如果openFileDialog.showmodel()==wx.ID\u取消:
返回
fileName=str(openFileDialog.GetPath())
打印(文件名)
#将图像列表放入python列表中
图像_列表=[]
f=打开(文件名“r”)
对于f中的行:
image\u list.append(line.rstrip())
f、 关闭()
打印(图像列表)
#将每个图像转换为wx图像
png_列表=[]
对于图像列表中的图像:
png=wx.Image(图像、wx.BITMAP\u类型\u任意)
png_list.append(png)
#存储PNG
打印(图像列表[:-1])
png_列表=png_列表[:-1]
对于png_列表中的png[:-1]:
self.future.append(png)
#显示第一个png
self.current=png_列表[-1]#放入当前缓冲区
png=self.current.Scale(self.display[0]/1.4,self.display[1]/1.4,wx.IMAGE\u QUALITY\u HIGH)
png=wx.BitmapFromImage(png)
self.img.SetBitmap(png)
self.Refresh()
self.right.Enable(True)
def onLeft(自我,evt):
#将当前图像放入未来堆栈,并从过去的堆栈中获取新的当前图像
self.future.append(self.current)
self.current=self.pass.pop()
png=self.current.Scale(self.display[0]/1.4,self.display[1]/1.4,wx.IMAGE\u QUALITY\u HIGH)
png=wx.BitmapFromImage(png)
self.img.SetBitmap(png)
self.Refresh()

如果len(self.pass)根据需要加载它们可能是减少内存使用的最佳方法。或者将当前、下一个和上一个图像保留在内存中,以帮助加快视图之间的切换。或者可以使用缓存实现将
N
最近查看的图像(以及序列中的下一个)保留在内存中。然后,您可以调整
N
的大小,看看哪些功能运行良好,是内存和速度之间的合理折衷


另一个可能的改进是,不要每次需要显示图像时都缩放图像,只需在读取图像时缩放一次,并将其保留在内存(或缓存)中。您可能还想尝试将它们预转换为
wx.bitmap
,因为图像到位图的转换不是一个简单的操作。

图像文件使用压缩,但程序必须保持其未压缩。谢谢!这有助于我获得更多的搜索词。我没有意识到这是事实,所以我要么做一些想象中的记忆技巧,要么根据需要展示它们。后面的唯一问题是,我正在通过sshfs读取图像,这并不是最快的。
class Slide(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Slide Show")

        self.display = wx.GetDisplaySize()

        self.image_list = None
        self.current = None # holds currently displayed bitmap
        # stacks that hold the bitmaps
        self.future = []
        self.past = []


        self.left = wx.BitmapButton(self, id=101, size=(100,-1), bitmap=wx.ArtProvider.GetBitmap(wx.ART_GO_BACK))
        self.left.Enable(False)
        self.right = wx.BitmapButton(self, id=102, size=(100,-1), bitmap=wx.ArtProvider.GetBitmap(wx.ART_GO_FORWARD))
        self.right.Enable(False)
        self.open = wx.BitmapButton(self, id=103, size=(100,-1), bitmap=wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN))

        # Testing code
        #png = wx.Image("set001_fit_001_1.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
        #image = wx.ImageFromBitmap(png)
        #image = image.Scale(self.display[0]/1.4, self.display[1]/1.4, wx.IMAGE_QUALITY_HIGH)
        #png = wx.BitmapFromImage(image)

        # make empty image slot
        self.img = wx.StaticBitmap(self, -1, size=(self.display[0]/1.4, self.display[1]/1.4))


        ## Main sizers
        self.vertSizer = wx.BoxSizer(wx.VERTICAL)

        # sub sizers
        self.buttonSizer = wx.BoxSizer(wx.HORIZONTAL)

        # place buttons together
        self.buttonSizer.Add(self.left, flag=wx.ALIGN_CENTER)
        als.AddLinearSpacer(self.buttonSizer, 15)
        self.buttonSizer.Add(self.right, flag=wx.ALIGN_CENTER)

        # place arrows and open together
        self.vertSizer.Add(self.img, flag=wx.ALIGN_CENTER)
        self.vertSizer.Add(self.open, flag=wx.ALIGN_CENTER)
        als.AddLinearSpacer(self.vertSizer, 15)
        self.vertSizer.Add(self.buttonSizer, flag=wx.ALIGN_CENTER)
        als.AddLinearSpacer(self.vertSizer, 15)

        self.Bind(wx.EVT_BUTTON, self.onOpen, id=103)
        self.Bind(wx.EVT_BUTTON, self.onLeft, id=101)
        self.Bind(wx.EVT_BUTTON, self.onRight, id=102)

        self.SetSizer(self.vertSizer)
        self.vertSizer.Fit(self)

    def onOpen(self, evt):
        print("Opening")
        openFileDialog = wx.FileDialog(self, "Open Image List", "", "", "List (*.ls)|*.ls", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        if openFileDialog.ShowModal() == wx.ID_CANCEL:
            return

        fileName = str(openFileDialog.GetPath())
        print(fileName)

        # put image list in a python list
        image_list = []
        f = open(fileName, 'r')
        for line in f:
            image_list.append(line.rstrip())
        f.close()

        print(image_list)
        # convert every image to wx Image
        png_list = []
        for image in image_list:
            png = wx.Image(image, wx.BITMAP_TYPE_ANY)
            png_list.append(png)

        # store pngs
        print(image_list[::-1])
        png_list = png_list[::-1]
        for png in png_list[:-1]:
            self.future.append(png)

        # display first png
        self.current = png_list[-1] # put into current buffer
        png = self.current.Scale(self.display[0]/1.4, self.display[1]/1.4, wx.IMAGE_QUALITY_HIGH)
        png = wx.BitmapFromImage(png)
        self.img.SetBitmap(png)

        self.Refresh()
        self.right.Enable(True)

    def onLeft(self, evt):
        # put current image into future stack and grab a new current image from past stack
        self.future.append(self.current)
        self.current = self.past.pop()

        png = self.current.Scale(self.display[0]/1.4, self.display[1]/1.4, wx.IMAGE_QUALITY_HIGH)
        png = wx.BitmapFromImage(png)
        self.img.SetBitmap(png)
        self.Refresh()
        if len(self.past) <= 0:
            self.left.Enable(False)

        self.right.Enable(True)

    def onRight(self, evt):
        # put current image into past stack and load in a new image from future stack
        self.past.append(self.current)
        self.current = self.future.pop()

        png = self.current.Scale(self.display[0]/1.4, self.display[1]/1.4, wx.IMAGE_QUALITY_HIGH)
        png = wx.BitmapFromImage(png)
        self.img.SetBitmap(png)
        self.Refresh()

        if len(self.future) <= 0:
            self.right.Enable(False)
        self.left.Enable(True)