Ask Your Question

Revision history [back]

click to hide/show revision 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();
}

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();
}