opencv python Multi Threading Video Capture


Question

I am trying to read to 2 Video Files and show them in separate Windows Simultaneously. This is my code:

import threading
import cv2
threadLock=threading.Lock()
class myThread (threading.Thread):
    maxRetries=20
    def __init__(self, threadID, name,video_url):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.video_url=video_url

    def attemptRead(self,cvVideo):
        threadLock.acquire()
        (isRead,cvImage)=cvVideo.read()
        threadLock.release()
        if isRead==False:
            count=1
            while isRead==False and count<myThread.maxRetries:
                threadLock.acquire()
                (isRead,cvImage)=cvVideo.read()
                threadLock.release()
                print self.name+' try no: ',count
                count+=1
        return (isRead,cvImage)

    def run(self):
        print "Starting " + self.name
        windowName = self.name
        cv2.namedWindow(windowName)
        cvVideo = cv2.VideoCapture(self.video_url)


        while True:
            (isRead,cvImage)=self.attemptRead(cvVideo)
            if isRead==False:
                break
            cv2.imshow(windowName,cvImage)
            key=cv2.waitKey(50)
            if key==27:
                break

        cv2.destroyWindow(windowName)
        print self.name + "Exiting"

def main():
    thread1 = myThread(1, "Thread1",'C:/Traffic Pics/Videos/Panjim Capture.mp4')
    thread2 = myThread(2, "Thread2",'C:/Traffic Pics/Videos/Miramar Capture.mp4')

    thread1.start()
    thread2.start()

print "Exiting Main Thread"

if __name__ == '__main__':
    main()

What's happening is that, only the Thread 2 Window is showing. Thread 1 exits after attempting to read the video beyond the max_retries limit(10 in my case). The problem is that although I create separate cvVideo objects, I can't seem to use them simultaneously. What could be the problem?

1
3
4/3/2013 1:03:18 PM

Accepted Answer

*edit: I'll leave the code below, but I guess you have a codec problem? I installed the xvid codec (which is what the sample Megamind.avi is encoded with) and the program works fine with either or both threads running the megamind video. Can you get the megamind video to run in the single threaded version?

Here is an SO post on opencv video codecs in case it helps. Here is the xvid download that I used (k-lite didn't work for me).


The code you wrote basically works for me. For you and anyone else that wants to try, I did the following:

  • applied PEP 8 recommendations
  • removed the unnecessary read attempt code (which also removes the misleading thread re-read warnings after the last frame of a working video)
  • used a video file that perhaps everyone with opencv has
  • removed the thread locking which didn't seem to matter to opencv at least on my system
  • moved a few other little things around

There may be other errors that come up with VideoCapture.read that would make a read_attempt method worthwhile, but I could only find the two errors the docs mention. For those it just returns false which the code already tests for.

import os
import threading

import cv2

my_opencv_path = "C:/opencv2.4.3"
video_path_1 = os.path.join(my_opencv_path, "samples", "cpp", "tutorial_code",
                            "HighGUI", "video-input-psnr-ssim", "video",
                            "Megamind.avi")
video_path_2 = os.path.join(my_opencv_path, "samples", "c", "tree.avi")
assert os.path.isfile(video_path_1)
assert os.path.isfile(video_path_2)


class MyThread (threading.Thread):
    maxRetries = 20

    def __init__(self, thread_id, name, video_url, thread_lock):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.name = name
        self.video_url = video_url
        self.thread_lock = thread_lock

    def run(self):
        print "Starting " + self.name
        window_name = self.name
        cv2.namedWindow(window_name)
        video = cv2.VideoCapture(self.video_url)
        while True:
            # self.thread_lock.acquire()  # These didn't seem necessary
            got_a_frame, image = video.read()
            # self.thread_lock.release()
            if not got_a_frame:  # error on video source or last frame finished
                break
            cv2.imshow(window_name, image)
            key = cv2.waitKey(50)
            if key == 27:
                break
        cv2.destroyWindow(window_name)
        print self.name + " Exiting"


def main():
    thread_lock = threading.Lock()
    thread1 = MyThread(1, "Thread 1", video_path_1, thread_lock)
    thread2 = MyThread(2, "Thread 2", video_path_2, thread_lock)
    thread1.start()
    thread2.start()
    print "Exiting Main Thread"

if __name__ == '__main__':
    main()
4
5/23/2017 12:29:17 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon