tester
tester

Reputation: 425

How to access 1 webcam with 2 threads

I am using python 3.5 with opencv.

I want to use 2 threads:

To view/capture the video from webcam i am using snippets of code from the following website: opencv video docs

I can capture and save the video using the following code:

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(True):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        out.write(frame)
    else:
        break

out.release()
cv2.destroyAllWindows()

I can view the video using the following code:

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    cv2.imshow('frame',frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cv2.destroyAllWindows()

Each of these pieces of code are in their own functions called capture and display. I then call them in separate threads with pythons threading library as follows:

cap = cv2.VideoCapture(0)
Thread(target=capture).start()
Thread(target=display).start()
cap.release()

I get an error I assume is related to both threads wanting to access the video buffer at the same time.

I understand this can be done without threads but there are other things I would like to do further than can only be done in separate threads.

How can I access the cap video capture from both threads?

Upvotes: 1

Views: 1922

Answers (1)

api55
api55

Reputation: 11420

My flask/django experience is increadibly limited, so I am not sure how to do it for that exactly, but I will answer the question posted directly.

First you need to create a thread-safe object to avoid calling at the same time the read function in different threads.

import cv2
import threading

class VideoCamera(object):
  # filename can be 0 to access the webcam
  def __init__(self, filename):
    self.lock = threading.Lock()
    self.openVideo(filename)

  def openVideo(self, filename):
    self.lock.acquire()
    self.videoCap = cv2.VideoCapture(filename)
    self.lock.release()

With this, you should be able to create an object with a lock and to open safely a video (in case that you want to open another video with the same object).

Now you have 2 options, either you create a thread that updates the frame and stores the current one internally or update do in a thread safe manner the get next frame function. I will do the second one here to show you:

  def getNextFrame(self):
    self.lock.acquire()
    img = None
    # if no video opened return None
    if self.videoCap.isOpened():
      ret, img = self.videoCap.read()
    self.lock.release()
    return img

This way you should be able to access the video cap with 2 frames... however, the frames will be different every time the function is called.

I hope this helps you.

Upvotes: 1

Related Questions