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 :)