0

Basics

Trying to capture video from Logitech Brio camera (can support up to 60fps at 1080p -- tested in VLC), but I cannot seem to be able to get higher than 30 fps by using OpenCV VideoCapture.

My System & Settings

Info about what I have and work with:

  • Camera: Logitech Brio
  • Language: python
  • opencv version: 4.0
  • Windows 10 with powershell (this is needed because my main program interacts with other windows-based applications)

Codec-related settings:

  • Fourcc = MJPEG (as other ones don't support the resolutions I need for my camera for some reason)
  • the following code is used to open the camera: cv2.VideoCapture(cv2.CAP_DSHOW + 1)

Some background and Code

I have used a threading approach, as suggested here: OpenCV VideoCapture lag due to the capture buffer

Basically my current code has 2 threads: 1 for the grab() function, and 1 for the retrieve() function and saving the retrieved image as an avi.

the thread that runs the grab() function looks something like this:

def __frame_grab_worker(self, cap, cameraNumber):
    try:
        while(cap.isOpened()):
            # sync with retrieve
            acquired = self._retrievingLock[cameraNumber].acquire()
            try:
                cap.grab()
            finally:
                self._retrievingLock[cameraNumber].release()
            if(self.interrupt == True):
                break
    finally:
        self._cleanupLock.release()

the thread that retrieves the image and saves it looks something like this:

def __record(self, filename, vidWidth, vidHeight, fps, cap, cameraNumber):
    if(self.numberOfCams > 0):
        fourcc = cv2.VideoWriter_fourcc('M','J','P','G')
        out = cv2.VideoWriter(filename, fourcc , fps, (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))))
        while(cap.isOpened()):
            self._retrievingLock[cameraNumber].acquire()
            ret, frame = cap.retrieve()
            self._retrievingLock[cameraNumber].release()
            if ret ==True:
                if(self.recordingFlag==True):
                    out.write(frame)

                cv2.imshow(str(cameraNumber), frame)

                # stop if interrupt flag presented
                if cv2.waitKey(1) & self.interrupt == True:
                    break

        cap.release()
        out.release()
        cv2.destroyAllWindows()

Things I've tried

I profiled my code. In general, between each loop of the while look in __record there is about 0.03 sec delay, which is equal to 30 fps. This is equally split between cap.retrieve() and the write and imshow functions.

I noticed that if I comment out the parts of the code that do any processing on the retrieved image (i.e. out.write(frame) or cv2.imshow(...) ) the time taken for the cap.retrieve() function increases to 0.03 (from previously around 0.15).

So I assume that the problem is to do with either DSHOW with MJPEG not allowing more than 30fps, or a problem with the underlying opencv codes.

I further looked over the opencv codebase (specifically videoio/src/cap_dshow.cpp & videoio/src/cap.cpp) and couldn't find anything useful... I might have missed something.

If anyone has a solution or know anything that could help I would appreciate it Thanks in advance :)

ffarhour
  • 352
  • 4
  • 10
  • What does cap.get(cv2.CAP_PROP_FPS ) gives? have you tried cap.set(cv2.CAP_PROP_FPS, 60)? – api55 Jan 22 '19 at 09:43
  • @api55 thanks for the suggestion. I actually found something very weird now: I have the following code right after I open the camera: `print(cap.get(cv2.CAP_PROP_FPS))` `cap.set(cv2.CAP_PROP_FPS, 60)` `print(cap.get(cv2.CAP_PROP_FPS))` The first print statement gives me `0` and the second gives `60`. Why does the first one give me 0 (even though the camera has already been opened)? hmmm... – ffarhour Jan 24 '19 at 21:26

0 Answers0