Numpy в QImage сбой

Aug 29 2020

Следующий код дает сбой при нажатии кнопки или после нескольких щелчков мышью, когда сигнал испускается из потока и попадает в основной графический интерфейс.

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QThread
import numpy as np
import time
from PyQt5.QtWidgets import QApplication, QDialog, QPushButton, QVBoxLayout


def convert_np_qimage(cv_img , width, height):
    h, w, ch = cv_img.shape
    bytes_per_line = ch * w
    qim = QtGui.QImage(cv_img.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
    print(qim.size())
    return qim

class VideoThread(QThread):
    change_qimage_signal = pyqtSignal(QImage)
    
    def __init__(self):
        super().__init__()

    def run(self):
        print("run")
        width = 1280
        height = 1280
        
        cv_img = np.zeros([height,width,3],dtype=np.uint8)
        cv_img.fill(255)
        print("image shape: ", cv_img.shape)

        qimg = convert_np_qimage(cv_img, width, height)
        self.change_qimage_signal.emit(qimg)
        print("emitted")

        
    def stop(self):
        self.wait()

import sys

class Dialog(QDialog):

    def __init__(self):
        super(Dialog, self).__init__()
        Dialog.resize(self, 640, 480)
        
        button=QPushButton("Click")
        button.clicked.connect(self.startThread)
        
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(button)
        
        
        self.setLayout(mainLayout)
        self.setWindowTitle("QImage Example")
        
    def startThread(self):
        self.thread = VideoThread()
        self.thread.change_qimage_signal.connect(self.getPixmap)
        self.thread.start()      
        
    def getPixmap(self, qimg):
        print("got qimage")
        qpixmap = QPixmap.fromImage(qimg)
        

if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = Dialog()
    sys.exit(dialog.exec_())

Программа не аварийно завершает работу, если для высоты и ширины установлено небольшое число, например 3. Программа также не аварийно завершает работу, если мы конвертируем qimage в qpixmap перед отправкой и меняем тип сигнала на QPixmap. Программа изначально была написана для получения изображений с веб-камеры с помощью opencv. Массив numpy, созданный opencv, также дает сбой для изображений больших размеров.

Используемая ОС - Windows10, версия pyqt - 5.12.3.

Есть идеи, что могло быть причиной аварии?

Ответы

1 eyllanesc Aug 29 2020 at 12:13

В Linux с PyQt5 5.15 я не воспроизводил проблему, но эта ошибка является распространенной и возникает из-за того, что передача «данных» не копирует информацию, а скорее данные совместно используются, поэтому в какой-то момент cv_img и все связанные объекты уничтожаются, включая " data ", поэтому при передаче через сигнал и установке в QLabel, что" data "читается, но в нем больше нет зарезервированной памяти. Решение в этом случае - скопировать «данные»:

qim = QtGui.QImage(
    cv_img.data.tobytes(), w, h, bytes_per_line, QtGui.QImage.Format_RGB888
)

или скопируйте QImage.

return qim.copy()