1 | initial version |
This cam doesn't support synchronization between left and right... from specs: L/R shutters don’t synchronize(Max deviation 16.5 ms)
So you will have minimum 15.6 ms of delay between images. To get the best from your cam you could use 2 grabbing threads but it would be really complicated to keep sync.
Considered your hardware I would suggest to use standard grabbing loop with grab()
and retrieve()
sequence instead of >>
or read()
... from the doc: The primary use of the grab()
function is in multi-camera environments, especially when the cameras do not have hardware synchronization
Below is a sample code to grab from 2 cams ans save the mosaic video file
void Main_GrabFrom2CamWriteMosaic()
{
// SELECT CAM ID FOR YOUR CAMS
int camL = 0, camR = 1;
// CHOOSE YOUR BEST DRIVER
int driver = CV_CAP_DSHOW; //use DSHOW or VFW or MSMF
// OPEN THE DEVICES
VideoCapture capL(camL + driver);
VideoCapture capR(camR+ driver);
//check if we succeeded
if (! (capL.isOpened() && capR.isOpened())) {
cerr << "Unable to open the cameras" << endl;
capL.release(); capR.release();
return;
}
//SET SAME SETTINGS ON BOTH CAM
Size frameSize(320, 240);
double fps = 30;
capL.set(CV_CAP_PROP_FRAME_WIDTH, frameSize.width);
capL.set(CV_CAP_PROP_FRAME_HEIGHT, frameSize.height);
capL.set(CV_CAP_PROP_FPS, fps); //desired FPS
capR.set(CV_CAP_PROP_FRAME_WIDTH, frameSize.width);
capR.set(CV_CAP_PROP_FRAME_HEIGHT, frameSize.height);
capR.set(CV_CAP_PROP_FPS, fps); //desired FPS
// GRAB ONCE TO GET FRAME INFO (we'll lost this frames)
Mat imgL, imgR;
if (!(capL.read(imgL) && capR.read(imgR))) {
std::cerr << "Unable to grab from some CAM";
capL.release(); capR.release();
return;
}
if ((imgL.size() != imgR.size()) || (imgL.type() != imgR.type())) {
cerr << "The cameras uses different framesize or type" << endl;
capL.release(); capR.release();
return;
}
// ENSURE RIGHT TYPE AND SIZE
frameSize = imgL.size();
// this will hold images from both cams
Mat frame(Size(2 * frameSize.width, frameSize.height), imgL.type());
// define ROI to compose mosaic
Mat frameL(frame(Rect(0, 0, frameSize.width, frameSize.height)));
Mat frameR(frame(Rect(frameSize.width, 0, frameSize.width, frameSize.height)));
// IN CASE YOU WANT TO SAVE A VIDEO
bool isColor = imgL.type() == CV_8UC3;
CV_Assert(isColor);
double fourcc;
VideoWriter writer;
string VideoName = "../../img/Grab2Cams.avi";
int codec = -1; //-1 to open a query window for the codec
codec = CV_FOURCC('X', 'V', 'I', 'D');
writer.open(VideoName, codec, fps, frame.size(), isColor);
if (!writer.isOpened()) {
cerr << "Could not open the output video for write: " << endl;
capL.release(); capR.release();
return;
}
// THE GRAB LOOP
for (;;)
{
// GRAB THE NEXT FRAME FROM VIDEO CAMERA
if (! (capL.grab() && capR.grab()) ) {
std::cerr << "Unable to grab from one or both cameras";
break;
}
// ENCODE AND RETURN THE JUST GRABBED FRAME
// you can't grab into a ROI
capL.retrieve(imgL);
capR.retrieve(imgR);
if (imgL.empty() || imgR.empty()) {
std::cerr << "Empty frame received from some CAM !";
break;
}
// COMPOSE MOSAIC show and save
imgL.copyTo(frameL);
imgR.copyTo(frameR);
cv::imshow("frame", frame);
writer.write(frame);
if (cv::waitKey(1) >= 0) break;
}
writer.release();
capL.release();
capR.release();
}
2 | No.2 Revision |
This cam doesn't support synchronization between left and right... from specs: L/R shutters don’t synchronize(Max deviation 16.5 ms)
So you will have minimum 15.6 ms of delay between images. To get the best from your cam you could use 2 grabbing threads but it would be really complicated to keep sync.
Considered your hardware I would suggest to use standard grabbing loop with grab()
and retrieve()
sequence instead of >>
or read()
... from the doc: The primary use of the grab()
function is in multi-camera environments, especially when the cameras do not have hardware synchronization
EDIT about transfer rate
You can't get 2 color cams 640x480@30fs on same USB2 port because transfer rate is too high for a single USB2 connection.
For 1 cam you need:
transferRate = 3chan * width * height * fps/BytesForMByte = 3*640*480*30/1024^2 = 26.37MB/s
Because the 2 cams share same USB port your requirement is 52MB/s.
Theoretical max speed for USB2 is 480Mbit/s (60MByte/s). Real speed depends on controller quality, on data packet overhead and if it's shared with other devices (hubs, keyboard, mouse,...). In addition, common USB2 is half duplex so receiving delays transmission and reverse. On my experience, typical transfer rate for USB2 is less than 35MB/s. That's why it doesn't work.
Conclusion: to use a stereo cam on a single USB2 connection we have to reduce data (lower resolution or fps or channels)... let me try to reduce fps:
maxFps <= (maxUsbSpeed * 1024^2) / (cams*3chan*width*height)
maxFps <= (35 * 1024^2) / (2*3*640*480) <= 19fps
Below is a sample code to grab from 2 cams ans and save the mosaic video file
void Main_GrabFrom2CamWriteMosaic()
{
// SELECT CAM ID FOR YOUR CAMS
int camL = 0, camR = 1;
// CHOOSE YOUR BEST DRIVER
int driver = CV_CAP_DSHOW; //use DSHOW or VFW or MSMF
// OPEN THE DEVICES
VideoCapture capL(camL + driver);
VideoCapture capR(camR+ driver);
//check if we succeeded
if (! (capL.isOpened() && capR.isOpened())) {
cerr << "Unable to open the cameras" << endl;
capL.release(); capR.release();
return;
}
//SET SAME SETTINGS ON BOTH CAM
Size frameSize(320, 240);
frameSize(640, 480);
double fps = 30;
15;
capL.set(CV_CAP_PROP_FRAME_WIDTH, frameSize.width);
capL.set(CV_CAP_PROP_FRAME_HEIGHT, frameSize.height);
capL.set(CV_CAP_PROP_FPS, fps); //desired FPS
capR.set(CV_CAP_PROP_FRAME_WIDTH, frameSize.width);
capR.set(CV_CAP_PROP_FRAME_HEIGHT, frameSize.height);
capR.set(CV_CAP_PROP_FPS, fps); //desired FPS
// GRAB ONCE TO GET FRAME INFO (we'll lost this frames)
Mat imgL, imgR;
if (!(capL.read(imgL) && capR.read(imgR))) {
std::cerr << "Unable to grab from some CAM";
capL.release(); capR.release();
return;
}
if ((imgL.size() != imgR.size()) || (imgL.type() != imgR.type())) {
cerr << "The cameras uses different framesize or type" << endl;
capL.release(); capR.release();
return;
}
// ENSURE RIGHT TYPE AND SIZE
frameSize = imgL.size();
// this will hold images from both cams
Mat frame(Size(2 * frameSize.width, frameSize.height), imgL.type());
// define ROI to compose mosaic
Mat frameL(frame(Rect(0, 0, frameSize.width, frameSize.height)));
Mat frameR(frame(Rect(frameSize.width, 0, frameSize.width, frameSize.height)));
// IN CASE YOU WANT TO SAVE A VIDEO
bool isColor = imgL.type() == CV_8UC3;
CV_Assert(isColor);
double fourcc;
VideoWriter writer;
string VideoName = "../../img/Grab2Cams.avi";
int codec = -1; //-1 to open a query window for the codec
codec = CV_FOURCC('X', 'V', 'I', 'D');
writer.open(VideoName, codec, fps, frame.size(), isColor);
if (!writer.isOpened()) {
cerr << "Could not open the output video for write: " << endl;
capL.release(); capR.release();
return;
}
// THE GRAB LOOP
for (;;)
{
// GRAB THE NEXT FRAME FROM VIDEO CAMERA
if (! (capL.grab() && capR.grab()) ) {
std::cerr << "Unable to grab from one or both cameras";
break;
}
// ENCODE AND RETURN THE JUST GRABBED FRAME
// you can't grab into a ROI
capL.retrieve(imgL);
capR.retrieve(imgR);
if (imgL.empty() || imgR.empty()) {
std::cerr << "Empty frame received from some CAM !";
break;
}
// COMPOSE MOSAIC show and save
imgL.copyTo(frameL);
imgR.copyTo(frameR);
cv::imshow("frame", frame);
writer.write(frame);
if (cv::waitKey(1) >= 0) break;
}
writer.release();
capL.release();
capR.release();
}