1

I have a program that involves both pyQt and opencv. I installed opencv with anaconda and installed pyqt separately a while ago. I run anaconda python2.7 on an OSX machine.

The example code is below, it is supposed to have a button that switch on openCV camera, and put the image to self.video_frame, which is a QLable()

from PyQt4 import QtGui
from PyQt4.QtGui import QImage,QPixmap
import PyQt4.QtCore as QtCore
import cv2,sys, time

class QtCapture(QtGui.QWidget):
    def __init__(self, *args):
        self.app = QtGui.QApplication(sys.argv)
        super(QtGui.QWidget, self).__init__()
        self.layout = QtGui.QGridLayout()
        self.w = QtGui.QWidget() # Main gui object
        self.w.setMinimumHeight(480)
        self.capture = None
        self.frame = None
        self.video_frame = QtGui.QLabel()
        self.button_start = QtGui.QPushButton('Camera Connect')
        self.button_start.setFixedWidth(300)
        self.button_start.clicked.connect(lambda: self.start())
        self.w.setLayout(self.layout)

        self.layout.addWidget(self.button_start, 0, 0)   
        self.layout.addWidget(self.video_frame, 0, 1, 16, 1)
        self.w.show()
        print "Init"


    def nextFrameSlot(self):
        try:
            previous_frame = self.current_frame
            ret, self.frame = self.cap.read()
            self.current_frame = self.frame
            frame_diff = cv2.absdiff(self.current_frame, previous_frame)
            qformat= QImage.Format_Indexed8
            if len(self.frame.shape) == 3:
                if self.frame.shape[2] == 4:
                    qformat=QImage.Format_RGBA8888
                else:
                    qformat=QImage.Format_RGB888
            img = QtGui.QImage(self.frame, self.frame.shape[1], self.frame.shape[0], self.frame.strides[0], qformat)
            self.video_frame.setPixmap(QtGui.QPixmap.fromImage(img))
            self.video_frame.setScaledContents(True)
        except Exception, e:
            print "Failed"
            self.timer.stop()


    def start(self):
        print "button_start pressed. "
        try:
            self.cap = cv2.VideoCapture(0)
            self.start_time = time.time()
            self.timer = QtCore.QTimer()
            ret, self.current_frame = self.cap.read()
            self.timer.timeout.connect(self.nextFrameSlot)
            self.timer.start(1./10.)
        except Exception, e:
            print "failed"



    def closeEvent(self, event):
        print "Closing"
        self.deleteLater()

    def deleteLater(self):
        print('closed')
        self.cap.release()
        super(QtGui.QWidget, self).deleteLater()




def main():
    #calibration_pts = getCalibrationCoordinates(cameraChoice)

    sozen = QtCapture()
    sys.exit(sozen.app.exec_())
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

I got the following message along with all other QCocoa classes:

    Class QCocoaMenu is implemented in both 
/Users/myname/anaconda/lib/libQtGui.4.8.7.dylib (0x104a7c150)
 and /Users/myname/anaconda/lib/python2.7/site-packages/cv2/.dylibs/QtGui (0x107b6a120). 
One of the two will be used. Which one is undefined.

The program also crashes with Abort trap: 6.

Please advice if you know what might happen there?

J_yang
  • 2,672
  • 8
  • 32
  • 61
  • The loops of opencv and Qt are being blocked, the solution is to execute the acquisition in another thread and send the image to the main thread and show it. Do not use the windows created by opencv – eyllanesc May 11 '18 at 15:57
  • Hi, thanks for your comment, But I am not sure if that is it. The project was pulled from my Colleague's GitHub, and he is running the Cv2.capture in a qt label without threading. – J_yang May 11 '18 at 20:22
  • when using cv2.destroyAllWindows() I thought you were using cv2.imshow() to show the contents of cv2.capture(), but according to what you comment it seems that it does not. You should not use cv2.destroyAllWindows(), and where is cv2.capture ?, also change self.btn.clicked.connect(exit) to self.btn.clicked.connect(self.close) – eyllanesc May 11 '18 at 20:29
  • @eyllanesc, hi. I edited the question with a code that is more close to the original code with other sliders and image processing removed. This one is suppose to click a start button to switch on the camera reading. The loop is done using a QtCore.QTimer().timeout.connect(self.nextFrameSlot) – J_yang May 11 '18 at 21:01
  • Avoid abuse of try, except, it is better to verify, for example the try-catch can be replaced by an if you verify the capture is open, the try-catch of nextFrameSlot can be replaced by check ret, that value returns if there is a new frame On the other hand deleteLater() is a method of the QWidget that you should not overwrite, in your case it is only necessary to release the capture in closeEvent(), – eyllanesc May 11 '18 at 21:46
  • [cont.] do not overwrite methods that do not know its usefulness, correcting those errors we obtain the following code: https://gist.github.com/eyllanesc/b82683fd946940b2f575ffac716bc696/archive/5f2254ee33df5f8f8ab155ef96d402c3deeb97ec.zip – eyllanesc May 11 '18 at 21:46
  • Thank you very much !! It works finally. Thank you for your advice too. Also it returns the same error if I import cv2 after QtGui and QtCore. To make it works, I have first import PyQt then OpenCV. Which is really strange to me. Any idea why this happens? – J_yang May 13 '18 at 16:35
  • Also, please submit your answer and I can accept it. – J_yang May 13 '18 at 16:35

0 Answers0