I’m trying to get up and running using OpenFrameworks, but running into some trouble.
I have a usb webcam that can capture video at 200 FPS. The resolution is 320x200, and is monochrome. It uses the DirectShow backend which underneath is using an MJPEG stream.
For example, the below code (opencv - python, but works as well in c++) validates that I can capture at this frame rate using this hardware on this PC:
import time
import cv2
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
time.sleep(1)
frames = []
start = time.time()
for i in range(1000):
ret, frame = cap.read()
frames.append(frame)
end = time.time()
print(f"{end-start} seconds to read 1000 frames")
However, the below code using OpenFrameworks can’t seem to break above ~30FPS. Am I missing some needed configuration? Is OpenFrameworks not capable of reading from the underlying MJPEG stream?
void ofApp::setup(){
grabber.setDeviceID(0);
grabber.setVerbose(true);
grabber.initGrabber(320, 200);
int grabW = grabber.getWidth();
int grabH = grabber.getHeight();
grabber.setDesiredFrameRate(200);
printf("asked for 320 by 200 - actual size is %i by %i", grabW, grabH);
}
//--------------------------------------------------------------
void ofApp::update(){
grabber.update(); // call this once per update
if (grabber.isFrameNew()) {
// This code is only executing at ~30FPS <------------------------------------
; // do computer vision / process the pixels
}
}
My output when running the app:
SETUP: Setting up device 0
SETUP: USB webcam
SETUP: Couldn't find preview pin using SmartTee
SETUP: Default Format is set to 320 by 200
SETUP: trying requested format RGB24 @ 320 by 200
SETUP: trying format RGB24 @ 320 by 200
SETUP: trying format RGB32 @ 320 by 200
SETUP: trying format RGB555 @ 320 by 200
SETUP: trying format RGB565 @ 320 by 200
SETUP: trying format YUY2 @ 320 by 200
SETUP: trying format YVYU @ 320 by 200
SETUP: trying format YUYV @ 320 by 200
SETUP: trying format IYUV @ 320 by 200
SETUP: trying format UYVY @ 320 by 200
SETUP: trying format YV12 @ 320 by 200
SETUP: trying format YVU9 @ 320 by 200
SETUP: trying format Y411 @ 320 by 200
SETUP: trying format Y41P @ 320 by 200
SETUP: trying format Y211 @ 320 by 200
SETUP: trying format AYUV @ 320 by 200
SETUP: trying format Y800 @ 320 by 200
SETUP: trying format Y8 @ 320 by 200
SETUP: trying format GREY @ 320 by 200
SETUP: trying format OTHER @ 320 by 200
SETUP: Capture callback set
SETUP: Device is setup and ready to capture.
asked for 320 by 200 - actual size is 320 by 200
I recently added MJPG support to VideoInput which is what OF uses. I think this might be fixed in the nightly builds. download | openFrameworks ( bottom of this page )
You may still need to force it in a bit of a hacky way ( see here - only try if the nightly build doesn’t solve it as is ):
Before you do any of that you might want to add. ofSetVerticalSync(false); to ofApp::setup just incase that’s the issue.
Hey @theo ! Thank you very much for the suggestions. I first tried your ofSetVerticalSync(false) advice, but this didn’t seem to change the behavior of the update().
I then went ahead and downloaded the nightly build, and ran the code. Same behavior.
After adding the line of code you suggested, (the setRequestedMediaSubType call), the setup output looks better as it does seem to be selecting the MJPEG mode:
***** VIDEOINPUT LIBRARY - 0.2000 *****
SETUP: Setting up device 0
SETUP: USB webcam
SETUP: Couldn't find preview pin using SmartTee
SETUP: Default Format is set to 320 by 200
SETUP: trying requested format MJPG @ 320 by 200
SETUP: Capture callback set
SETUP: Device is setup and ready to capture.
asked for 320 by 200 - actual size is 320 by 200
However, I’m still seeing 30ish ms between frames in update(), which would be about 30FPS.
Below is the code I have now. I’m definitely setting the desired frame rate, so I’m not sure at all what it could be:
void ofApp::setup() {
grabber.setVerbose(true);
grabber.setDeviceID(0);
grabber.setDesiredFrameRate(200);
ofSetFrameRate(200);
grabber.setup(320, 200);
//ofSetVerticalSync(false);
int grabW = grabber.getWidth();
int grabH = grabber.getHeight();
printf("asked for 320 by 200 - actual size is %i by %i", grabW, grabH);
}
//--------------------------------------------------------------
void ofApp::update() {
grabber.update(); // call this once per update
if (grabber.isFrameNew()) {
cout << GetTickCount() << endl;
; // do computer vision / process the pixels
}
}
I also even tried removing the isFrameNew() check, but I still am seeing 30fps.