PyQt4 video player crashes when moving window
Question: I've written a simple PyQt4 GUI that plays an OpenCV `VideoCapture`. This
requires converting frames from numpy arrays to `QImages`. I'm using OpenCV so
that I can detect circles using my `findCircles` method.

However, when I pass my frames to `findCircles`, the program crashes when the
window is moved. This problem does not occur when I don't search for circles.
I don't understand why this is happening, as I'm under the impression that the
work is being done on a different thread than the GUI since I call
`findCircles` from the `run` method of a `QThread`.

Note that I don't receive a normal error message in the console; Python
crashes like such:

![enter image description here](http://i.stack.imgur.com/gcoCM.png)

[Here](https://onedrive.live.com/redir?resid=C7765FC335ABD69D!20797&authkey=!ABcBXD4-RkP91qk&ithint=video%2cMOV)
is the video file I've been using to test my player. I'm running Python 2.7.6
on Windows 8.1.

    
    
    import sys
    import cv2.cv as cv, cv2
    from PyQt4.Qt import *
    import time
    
    def numpyArrayToQImage(array):
        if array != None:
            height, width, bytesPerComponent = array.shape
            bytesPerLine = bytesPerComponent * width;
            cv2.cvtColor(array, cv.CV_BGR2RGB, array)
            return QImage(array.data, width, height, bytesPerLine, QImage.Format_RGB888)
        return None
    
    def findCircles(frame):
        grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        blurredFrame = cv2.medianBlur(grayFrame, 3)
        circles = cv2.HoughCircles(blurredFrame, cv.CV_HOUGH_GRADIENT, 1, 30, param1=50, param2=30, minRadius=30, maxRadius=35)
    
        if circles is not None: 
            for i in circles[0]:
                cv2.circle(frame, (i[0], i[1]), i[2], (255, 0, 0), 1) # Perimeter
                cv2.circle(frame, (i[0], i[1]), 3, (0, 255, 0), -1) # Center
    
    class VideoThread(QThread):
        frameProcessed = pyqtSignal(QImage)
    
        def __init__(self, video, videoLabel):
            QThread.__init__(self)
            self.video = video
            self.fps = self.video.get(cv.CV_CAP_PROP_FPS)
            self.frameCount = self.video.get(cv.CV_CAP_PROP_FRAME_COUNT)
            self.startingSecond = 0
            self.videoLabel = videoLabel
    
        def run(self):
            clockAtStart = time.clock()
    
            while True:
                runtime = self.startingSecond + (time.clock() - clockAtStart)
                currentFrame = int(runtime * self.fps)
    
                if currentFrame < self.frameCount - 1:
                    self.video.set(cv.CV_CAP_PROP_POS_FRAMES, currentFrame)
                    frame = self.video.read()[1]
                    findCircles(frame) # Removing this line removes the issue
                    self.frameProcessed.emit(numpyArrayToQImage(frame))
                    time.sleep(.02)
                else:
                    break
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
            self.initUI()
    
        @pyqtSlot(QImage)
        def updateVideoLabel (self, image):
            self.videoLabel.setPixmap(QPixmap.fromImage(image))
            self.videoLabel.update()
    
        def initUI(self):
            self.setGeometry(300, 300, 500, 375)
            self.setMinimumHeight(250)
            self.createWidgets()
            self.addWidgets()
    
        def startNewVideo(self):
            self.video = cv2.VideoCapture(unicode(QFileDialog.getOpenFileName(self, "Open video").toUtf8(), encoding="UTF-8"))
            self.videoThread = VideoThread(self.video, self.videoLabel)
            self.videoThread.frameProcessed.connect(self.updateVideoLabel)
            self.playVideoFrom(0)
    
        def playVideoFrom(self, frame):
            self.videoThread.startingSecond = frame / self.videoThread.fps
            self.videoThread.start()
    
        def createWidgets(self):
            self.populateMenuBar()
            self.videoLabel = QLabel()
            self.videoLabel.setStyleSheet('background-color : black;');
    
        def populateMenuBar(self):
            self.menuBar = self.menuBar()
            fileMenu = QMenu('File', self)
            openAction = QAction('Open video...', self)
            openAction.triggered.connect(self.startNewVideo)
            fileMenu.addAction(openAction)
            self.menuBar.addMenu(fileMenu)
    
        def addWidgets(self):
            mainLayout = QVBoxLayout()
            mainLayout.addWidget(self.videoLabel, 1)
            centralWidget = QWidget()
            self.setCentralWidget(centralWidget)
            centralWidget.setLayout(mainLayout)
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        player = MainWindow()
        player.show()
        sys.exit(app.exec_())
    


Answer: I've tested your program, and it crashes when it finds no circles as indicated
in the error message:

    
    
    Traceback (most recent call last):
      File "test_opencv_tkinter.py", line 53, in run
        findCircles(frame) # Removing this line removes the issue
      File "test_opencv_tkinter.py", line 26, in findCircles
        if len(circles) > 0:
    TypeError: object of type 'NoneType' has no len()
    

I've made some changes in the `findCircles(frame)` function, as follows, and
it runs without error, even when I move the window around on the screen.

    
    
    def findCircles(frame):
        grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        blurredFrame = cv2.medianBlur(grayFrame, 3)
        circles = cv2.HoughCircles(grayFrame,cv.CV_HOUGH_GRADIENT,1,20,
                                param1=50,param2=30,minRadius=0,maxRadius=0)
        if circles == None: 
            print "no circles found"
            return
        if len(circles) > 0:
            print "found circles ", len(circles[0])
            for i in circles[0]:
                cv2.circle(frame, (i[0], i[1]), i[2], (255, 0, 0), 1) # Perimeter
                cv2.circle(frame, (i[0], i[1]), 3, (0, 255, 0), -1) # Center
    

