【问题标题】:Creating QPixmaps in a loop uses a high amount of RAM在循环中创建 QPixmap 会占用大量 RAM
【发布时间】:2021-09-22 03:21:30
【问题描述】:

创建 QPixmap 会占用大量 RAM。

我正在循环创建大约 50 个 QLabel,并添加一张照片作为封面图片。

这是我正在使用的代码的一小部分基本部分:

def main(self):
    for i in os.listdir(self.directory) * 10:
        image = QLabel(self.labelArea)
    
        image.setPixmap(QPixmap.fromImage(QImage("{}/{}".format(self.directory , i))))
    

假设当前 RAM 为 1400MB。当我运行上述程序时,它会达到 2500MB。太疯狂了!

第二个代码:

def main():
    for i in os.listdir(self.directory) * 10:
        image = QLabel(self.labelArea)
    
        # image.setPixmap(QPixmap.fromImage(QImage("{}/{}".format(self.directory , i))))

在注释 for 循环的第二行时,RAM 仅达到 1490Mb! (从 1400MB 起)

提供的代码是否有任何问题,或者我在其余代码中搞砸了?

根据要求,最小可重现示例

import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QRect, QSize
from PyQt5.QtGui import QPixmap

def createUi():
    app = QtWidgets.QApplication(sys.argv)
    
    window = QtWidgets.QMainWindow()
    
    imagesArea = QtWidgets.QWidget(window)
    
    window.setCentralWidget(imagesArea)
    
    imagesArea.setGeometry(QRect(0 , 0 , 1980 , 1080))
    
    layout = QtWidgets.QVBoxLayout()
    
    layout.setSpacing(20)
    
    imagesArea.setLayout(layout)
        
    for i in ["sample.jpg"] * 10:
        label = QtWidgets.QLabel()
        
        label.setFixedSize(QSize(400 , 400))
        
        label.setPixmap(QPixmap(i))
        
        label.setScaledContents(True)
        
        layout.addWidget(label)
        
    print("DONE <3")
        
    window.show()
    
    imagesArea.show()
    
    sys.exit(app.exec_())
    
if __name__ == '__main__':
   createUi()

我的目标是在一列中显示所有图像

“my_img.png”的分辨率为 1000x800 像素。

此代码确实使用了 20MB,但最终在 for 循环后下降

如果我说的是 1980x1080 分辨率的图像,那么仅 10 张图像就需要大约 200 MB!

【问题讨论】:

  • 1) 不要使用 QImage 而是直接使用 QPixmap:image.setPixmap(QPixmap("{}/{}".format(self.directory , i))), 2) 每张图片或所有图片的权重是多少?
  • 1) 没有同样的问题 :^) 。 2)大部分都是1980x1080
  • QPixmap 有什么替代品吗?
  • QPixmap 没有替代方案,但我认为您的背景问题可能有替代方案(我认为您有 XY 问题)。是否有必要一次显示加载所有图像?我指出了这一点,因为它们是大图像,因此很容易假设它们将占据整个屏幕(或至少一部分),因此一次加载所有图像没有意义,而是按需加载。如果您需要更多帮助,您必须提供minimal reproducible example 并说明您的基本目标。
  • @0xsapphir3 考虑一下,粗略的说,每张图片一般在内存中每像素占用至少 4个字节(文件格式压缩只是为了存储,什么是屏幕上显示的 未压缩存储在内存中)。您使用的是全高清图片,每张图片转换为大约 8MB。只需 100 多张图像,您就可以轻松获得超过 1GB 的内存。

标签: python python-3.x pyqt pyqt5


【解决方案1】:

感谢@musicamante 和@eyllanesc 帮助我找出答案。

我尝试在 PIL 模块的帮助下调整图像大小,我看起来好像在做这个伎俩(有点慢,但我会考虑)

@eyllanesc 发表评论后的回答更新:

更新答案:

import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QRect, QSize
from PyQt5.QtGui import QPixmap
from PIL import Image , ImageQt

def createUi():
    app = QtWidgets.QApplication(sys.argv)
    
    window = QtWidgets.QMainWindow()
    
    imagesArea = QtWidgets.QWidget(window)
    
    window.setCentralWidget(imagesArea)
    
    imagesArea.setGeometry(QRect(0 , 0 , 1980 , 1080))
    
    layout = QtWidgets.QHBoxLayout()
    
    layout.setSpacing(20)
    
    imagesArea.setLayout(layout)
        
    for i in ["sample.jpg"] * 10:
        label = QtWidgets.QLabel()
        
        label.setFixedSize(QSize(400 , 400))
        
        label.setPixmap(QPixmap(i).scaled(400 , 400))
        
        label.setScaledContents(True)
        
        layout.addWidget(label)
                
    window.show()
    
    imagesArea.show()
    
    sys.exit(app.exec_())
    
if __name__ == '__main__':
   createUi()

【讨论】:

  • 没有必要使用 PIL 来调整图像大小,因为 QPixmap 可以直接做到这一点:label.setPixmap(QPixmap(i).scaled(400 , 400))
  • 这比 PIL.Image.resize() 更快更好
猜你喜欢
  • 1970-01-01
  • 2016-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-23
  • 1970-01-01
相关资源
最近更新 更多