0

I am developing an application for image acquisition. I am using PyQt4, pydc1394 (libdc1394 Python wrapper for firewire camera) on a MacOS sierra and the camera is AVT Marlin F131B. I managed to write a program that can acquire images from the camera, however, this program crushes after 10min (this time may vary on different computers) returning a Segmentation Fault.

Initially, I was suspecting a memory leak in the pydc1394. However, when I run the code with QThread.emit deactivated, the code runs very well. The problem raises up when I try to connect the main window to the Qthread object.

My code is attached. Do you have any idea about what is going on please?

Thank you

from PyQt4 import QtGui, QtCore
from pydc1394 import DC1394Library, Camera
from threading import Thread
from datetime import datetime as dt
import time, sys, os, cv2
import numpy as np

class AcquisitionThread(QtCore.QThread):
    sig = QtCore.pyqtSignal(object)

    def __init__(self,cam):
        super(AcquisitionThread,self).__init__()

        self._cam = cam
        self._running = True
        self.start()
        print 'acquisition thread initiated'


    def run(self):
        while self._cam.running and self._running:
            frame = self._cam.current_image
            timestamp = frame.timestamp
            image = np.asarray(frame[:,:])
            self.sig.emit(frame)
            now_time = str(dt.now())
        return 

    def terminate(self):
        self._running = False
        print 'acquisition thread terminated'
        self.wait()
        print "Exited with success"

class MainWindow(QtGui.QWidget):
    def __init__(self):
        super(MainWindow,self).__init__()
        self.resize(700,540)
        self.move(300,300)
        self.setWindowTitle("Camera Acquisition")
        self.scene = QtGui.QGraphicsScene(self)
        self.view = QtGui.QGraphicsView(self.scene)
        self.view.setSizeIncrement(2,2)
        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addWidget(self.view)
        self.setLayout(self.vbox)

        #initiate camera
        l = DC1394Library()
        try:
            list_cameras = l.enumerate_cameras()
        except:
            list_cameras = []

        if len(list_cameras) > 0:
            print len(list_cameras), "camera(s) found:"
            for i,c in enumerate(list_cameras):
                print i,"\t",c['guid']
        else:
            print "No camera was found. Program exiting ..."
            sys.exit()
        self._cam = Camera(l,guid = l.enumerate_cameras()[0]['guid'])

        #start camera 
        self._cam.start(interactive=True)
        print "camera started"
        time.sleep(1)

        self.acquisitionThread = AcquisitionThread(self._cam)
        self.acquisitionThread.sig.connect(self.displayImage)

        self.show()

    def displayImage(self,frame):
        timestamp = frame.timestamp
        #print timestamp
        now_time = str(dt.now())

        print now_time,"\t",timestamp
        img = np.asarray(frame[:,:])
        h,w = img.shape
        pix = QtGui.QPixmap(QtGui.QImage(img.tostring(),w,h,QtGui.QImage.Format_RGB888).rgbSwapped())
        self.scene.clear()
        self.scene.addPixmap(pix)
        #print "done displaying"

    def closeEvent(self,event):
        self._cam.stop()
        print "camera stopped"
        self._cam.close()
        print "camera closed"
        self.acquisitionThread.terminate()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    mainWindow = MainWindow()
    sys.exit(app.exec_())
kthouz
  • 411
  • 7
  • 16
  • Can you `import threading` and then print `threading.current_thread().name` inside the `displayImage` method to ensure that the drawing of the image is happening from the main thread? You might also want to consider (temporarily) replacing the `QThread` with a `QTimer` (requires some refactoring to achieve) to see if it is some sort of thread safety issue causing the problem or the actual interaction with the camera. – three_pineapples Dec 09 '16 at 09:04
  • Thank you for your comments @three_pineapples: the threading.current_thread().name prints "MainThread". Using QTimer (instead of QThread), the [program](https://bitbucket.org/cgirabawe/pim/src/ec6f345429aa38142206c2354fb773d1102f8a45/ui.py?at=master&fileviewer=file-view-default) still crushes after 10 min. Which brings me back to square one - issues with the camera communication – kthouz Dec 09 '16 at 15:25
  • @kthouz. Trying creating the `QImage` in the thread, and then emit that. (You can work with `QImage` outside the main thread, but not `QPixmap`). – ekhumoro Dec 09 '16 at 17:12
  • @ekhumoro, still doesn't work but thanks for trying to help – kthouz Dec 09 '16 at 18:48
  • I suspect this is not a Qt problem then, but rather an issue with the camera, camera driver, or pydc1394 library. These are notoriously difficult to debug. Some suggested avenues for further investigation 1) Can you make an Python application that crashes without ever importing Qt. 2) Try it on a Windows system 3) Try working with the camera from other software (either something supplied by AVT, or labview, matlab, etc.). If you can manage to test these scenarios, I think the source of the issue will be narrowed down enough to possibly suggest work arounds. – three_pineapples Dec 10 '16 at 05:09
  • Actually, I have a couple more Qt related suggestions: 1) The data passed to `QImage` needs to exist for the life of the `QImage`. It may be being garbage collected occasionally, leading to the crash. Consider assigning `img.toString()` to an instance attribute to stop it being garbage collected. 2) I believe the correct way to convert between a `QImage` and `QPixmap` is using the `QPixmap.fromImage` method. None of the constructors of `QPixmap` appear to accept a `QImage` directly (it's probably treating it as a `QVariant`) – three_pineapples Dec 10 '16 at 05:23
  • Thanks @three_pineapples. I have another [matlab application](https://github.com/kthouz/PIM_Controller) that runs without any issue. This time I was planning to make a python version to share with our collaborators as python is becoming such a universal programming language. So I am more to say that the issue is within pydc1394. I will try these other approaches you are suggesting and will share the results – kthouz Dec 10 '16 at 20:05

0 Answers0