在 PyQt5 中传递 cv2 图像问题

Posted

技术标签:

【中文标题】在 PyQt5 中传递 cv2 图像问题【英文标题】:pass cv2 image issue in PyQt5 【发布时间】:2020-06-10 13:43:24 【问题描述】:

我对 pyQt5 并不陌生。当我尝试在函数 pyCharm 中传递图像时,退出代码为 -1073740791 (0xC0000409)。

用 cmd 表示:

_grayImage = _imageToCanny
NameError: name '_imageToCanny' is not defined

似乎如果我在同一个函数中加载带有 imread 的图像,它就可以工作。但是,如果我在不同的函数中加载图像(使用全局),它会说变量为空或给我这个错误。

    def doCanny(self):
        global _imageToCanny, _grayImage, _edgeResult
        global _lowerThreshold, _upperThreshold
        #_grayImage = cv2.imread("test.jpg")
        _grayImage = _imageToCanny
        _grayImage = cv2.cvtColor(_grayImage, cv2.COLOR_BGR2GRAY)
        blurred = cv2.GaussianBlur(_grayImage, (3, 3), 0)
        _edgeResult = cv2.Canny(blurred, _lowerThreshold, 200)
        self.displayImageX(_edgeResult)

代码如下:

'''

import sys
import cv2
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.uic import loadUi


class testWin(QMainWindow):
    _imageToCanny = None
    _grayImage = None
    _edgeResult = None
    _lowerThreshold = 100
    _upperThreshold = 200
    _boolX2 = True
    _boolX3 = False
    _boolXFree = False
    _xKernel = 3
    _yKernel = 3

    def __init__(self):
        super(testWin, self).__init__()
        loadUi("dlgCannyV2.ui", self)
        self.activateSlotPointer()
        self.setUI()

    def initVariable(self):
        global _imageToCanny, _grayImage, _edgeResult
        global _lowerThreshold, _upperThreshold
        global _boolX2, _boolX3, _boolXFree
        global _xKernel, _yKernel
        self._imageToCanny = None
        self._grayImage = None
        self._edgeResult = None
        self._lowerThreshold = 100
        self._upperThreshold = 200
        self._boolX2 = True
        self._boolX3 = False
        self._boolXFree = False
        self._xKernel = 3
        self._yKernel = 3

    def activateSlotPointer(self):
        # VIEWER POINTER
        self.viewerCanny = self.findChild(QtWidgets.QLabel, 'viewerCanny')
        # BTN POINTER
        self.BTN_accept = self.findChild(QtWidgets.QPushButton, 'canny_btnAccept')
        self.BTN_cancel = self.findChild(QtWidgets.QPushButton, 'canny_btnCancel')
        self.BTN_tryAuto = self.findChild(QtWidgets.QPushButton, 'canny_btnTryAuto')
        # SLIDER POINTER
        self.SLD_LowerValue = self.findChild(QtWidgets.QSlider, 'canny_sldLowThreshold')
        self.SLD_UpperValue = self.findChild(QtWidgets.QSlider, 'canny_sldUpperThreshold')
        # LBL POINTER
        self.LBL_lowerValue = self.findChild(QtWidgets.QLabel, 'canny_lbLowThreshold')
        self.LBL_upperValue = self.findChild(QtWidgets.QLabel, 'canny_lblUpperThreshold')
        # LBL POINTER
        self.RAD_X2 = self.findChild(QtWidgets.QRadioButton, 'canny_chkX2')
        self.RAD_X3 = self.findChild(QtWidgets.QRadioButton, 'canny_chkX3')
        self.RAD_XFREE = self.findChild(QtWidgets.QRadioButton, 'canny_chkXFree')

    def setUI(self):
        self.setWindowTitle("test PyQt5 with MAtPlotlib")
        global _lowerThreshold, _upperThreshold
        # Button -> Function
        self.BTN_accept.clicked.connect(self.doAccept)
        self.BTN_cancel.clicked.connect(self.doCancel)
        self.BTN_tryAuto.clicked.connect(self.doTryAuto)
        # Slider -> Function
        self.SLD_LowerValue.setProperty('maximum', 500)
        self.SLD_LowerValue.valueChanged.connect(self.setLowerThreshold)
        self.SLD_LowerValue.setValue(self._lowerThreshold)
        self.SLD_UpperValue.setProperty('maximum', 500)
        self.SLD_UpperValue.valueChanged.connect(self.setUpperThreshold)
        self.SLD_UpperValue.setValue(self._upperThreshold)
        # Label -> Function
        self.LBL_lowerValue.setText(str(self._lowerThreshold))
        self.LBL_upperValue.setText(str(self._upperThreshold))
        # RadioButton -> Function
        self.RAD_X2.setChecked(False)
        self.RAD_X3.setChecked(False)
        self.RAD_XFREE.setChecked(True)

    def setImage(self, image=None):
        global _imageToCanny, _grayImage, _edgeResult
        _imageToCanny = image
        _grayImage = _imageToCanny.copy()
        _edgeResult = _imageToCanny.copy()
        self.displayImageX(_imageToCanny)

    def doAccept(self):
        pass

    def doCancel(self):
        self.close()

    def doTryAuto(self):
        pass

    def setLowerThreshold(self):
        global _lowerThreshold,_upperThreshold
        _lowerThreshold = self.SLD_LowerValue.value()
        _upperThreshold = self.SLD_UpperValue.value()
        self.LBL_lowerValue.setText(str(_lowerThreshold))
        self.doCanny()

    def setUpperThreshold(self):
        global _lowerThreshold,_upperThreshold
        _lowerThreshold = self.SLD_LowerValue.value()
        _upperThreshold = self.SLD_UpperValue.value()
        self.LBL_upperValue.setText(str(_upperThreshold))
        self.doCanny()

    def x2Select(self):
        if self.RAD_X2.setChecked(False):
            self.RAD_X2.setChecked(True)
            self.RAD_X3.setChecked(False)
            self.RAD_XFREE.setChecked(False)

    def x3Select(self):
        if self.RAD_X3.setChecked(False):
            self.RAD_X3.setChecked(True)
            self.RAD_X2.setChecked(False)
            self.RAD_XFREE.setChecked(False)

    def xFreeSelect(self):
        if self.RAD_XFREE.setChecked(False):
            self.RAD_Xq.setChecked(False)
            self.RAD_X2.setChecked(False)
            self.RAD_XFREE.setChecked(True)

        # function from:
        # https://www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/
        #

    ##################################
    #
    #   CANNY PROCESSING
    #
    ##################################

    def doCanny(self):
        global _imageToCanny, _grayImage, _edgeResult
        global _lowerThreshold, _upperThreshold
        #_grayImage = cv2.imread("test.jpg")
        _grayImage = _imageToCanny
        _grayImage = cv2.cvtColor(_grayImage, cv2.COLOR_BGR2GRAY)
        blurred = cv2.GaussianBlur(_grayImage, (3, 3), 0)
        _edgeResult = cv2.Canny(blurred, _lowerThreshold, 200)
        self.displayImageX(_edgeResult)

    ##################################
    #
    #   GRAPHIC ENGINE
    #
    ##################################

    def testImage(self):
        pixmap = QPixmap('test.jpg')
        self.viewerCanny.setPixmap(pixmap)
        # self.resize(pixmap.width(), pixmap.height())

    def displayImageX(self, image):
        qformat = QImage.Format_Indexed8
        if len(image.shape) == 3:  # rows[0],cols[1],channels[2]
            if (image.shape[2]) == 4:
                qformat = QImage.Format_RGBA8888
            else:
                qformat = QImage.Format_RGB888
        img = QImage(image, image.shape[1], image.shape[0], image.strides[0], qformat)
        # BGR > RGB
        img = img.rgbSwapped()
        self.viewerCanny.setPixmap(QPixmap.fromImage(img))
        self.viewerCanny.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)



app = QApplication(sys.argv)
win = testWin()
image = cv2.imread("test.jpg", cv2.IMREAD_ANYCOLOR)
win.setImage(image)
win.show()
sys.exit(app.exec_())

'''

这是 dlgCannyV2.ui:

'''

【问题讨论】:

建议:在 /CMD 控制台中运行您的脚本,因为您将获得比数字代码更具描述性的错误消息 1) 提供minimal reproducible example,2) 使用image = cv2.imread("/full/path/of/test.jpg", cv2.IMREAD_ANYCOLOR) 【参考方案1】:

看来主要问题在于环境。我不知道为什么,但它弄乱了全局变量。我重新开始使用一个新的虚拟环境进行了一些测试,现在它可以工作了......

'''

import cv2

class testClass():
    _testVariable = None

    def __init__(self):
      pass

    def setValue(self, value):
        global _testVariable
        _testVariable = value

    def func(self):
      global _testVariable
      _testVariable = 12

    def printValue(self):
        global _testVariable
        print (_testVariable)

#######

test = testClass()
test.func()
test.printValue()
image = cv2.imread("test.jpg")
test.setValue(image)
test.printValue()

'''

【讨论】:

以上是关于在 PyQt5 中传递 cv2 图像问题的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5-QImageQPixmapOpencv与QLabelMatplotlib的互动

PyQt5 不会在标签中显示图片

无法将 Keras Generator 图像传递给人脸识别

复制通过引用方法传递的参数的最佳实践,避免无意中修改参数

OpenCV:自动将窗口大小调整为显示的图像

使用 OpenCV 和 PyQT5 视频播放速度过快