Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

I'm sorry for long but done too fast answer... I hope it's useful.

Your code looks OK (even if should be cleaned), I think your issue is coming from the camera. More in details, maybe your camera has some automatic exposure adjustment. When low light condition AUTO_EXPOSURE increases shutter time or camera gain. Because, in any case your frame rate is max(wantedFps,1/shutter_time) if camera increases shutter time the fps might decrease.

You can easily test this case, pointing a light in front of your camera so it will become saturated. If I'm right your frame rate should increase.

Not all web cams has exposure control. You can test it using CV_CAP_PROP_AUTO_EXPOSURE and/or CV_CAP_PROP_EXPOSURE

It should be (my change from cams and driver)

  • to disable auto exposure: cap.set(CV_CAP_PROP_AUTO_EXPOSURE,-1);
  • to set wanted exposure: cap.set(CV_CAP_PROP_EXPOSURE,divider); where divider reduce in some way the max shutter time. Maybe 0 uses max shutter
  • to open camera driver interface: cap.set(CV_CAP_PROP_SETTINGS, -1); this will pop up a window from driver

Remember that using VideoCapture cap1(CV_CAP_DSHOW + device); you will can the DirectShow driver. DSHOW gives you more control on capture controls param. (Some CV_CAP_PROPs doesn't work with default VFW driver).

At the end keep in mind that the calling cap >> frame you will wait for an available frame. You wont to be surprised if loop time for

while(1){
    cap >> frame;
    if (waitKey(5) >= 0)
        break;
}

has same duration of simpler

while(1){
    cap >> frame;
}

This is because 5ms is short time, in the mean time the camera is preparing the frame so you can spend time to do something (as is in 1st case) instead of waiting for the camera (as in in 2nd case). Exactly you can do something up to 1/fps seconds without loosing !

If you spend more time to do things the readTime will reduce because the image is always ready. This doesn't mean that cam is grabbing faster but just you are loosing frames

here is my function to measure loopTime and readTime. In my case they are both fixed at 30fps

int MeasureFps(int device = CV_CAP_DSHOW + 0)
{
    Mat frame;
    cout << "Opening device " << to_string(device) <<"..."<< endl;
    VideoCapture cap(device);
    if (!cap.isOpened())
    {
        cout << "Problem opening streams!" << endl;
        return -1;
    }
    int maxFrames = 100;
    cout << "Wait while grabbing " << to_string(maxFrames) << "frames..." << endl;

    double capprop;
    capprop = cap.get(CV_CAP_PROP_AUTO_EXPOSURE);
    capprop = cap.get(CV_CAP_PROP_EXPOSURE);
    cap.set(CV_CAP_PROP_AUTO_EXPOSURE,-1); //disable. doesn't works for all cams
    cap.set(CV_CAP_PROP_EXPOSURE,0);       //default. doesn't works for all cams
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    cap.set(CV_CAP_PROP_FPS, 300000.0);   //very high to catch the maximum
    cap.set(CV_CAP_PROP_SETTINGS, -1);    //pop up the driver window 
    cap >> frame; //grab 1st frame to initialize all chain
    int64 t0, t1, r0, readTicks;
    int tickFreq = cv::getTickFrequency();
    int numberOfFrames = 0;
    readTicks = 0;
    t0 = cv::getTickCount();
    while (numberOfFrames<maxFrames)
    {
        r0 = cv::getTickCount();
        cap >> frame;
        readTicks += (cv::getTickCount() - r0);
        numberOfFrames++;
        /*
        if (frame.empty()) continue;
        imshow("frame", frame);
        */
        if (waitKey(5) >= 0)
            break;
    }
    t1 = cv::getTickCount();
    double loopTime = (double)(t1 - t0) / tickFreq; // seconds
    double averageLoopTime = loopTime / numberOfFrames; // seconds
    cout << "Loop time: "
        << averageLoopTime * 1000 << "ms"
        << " ~= " << cvRound(1 / averageLoopTime) << "fps" << endl;

    double readTime = (double)readTicks / tickFreq; // seconds;
    double averageReadTime = readTime / numberOfFrames; // seconds
    cout << "Read time: "
        << averageReadTime * 1000 << "ms" << endl;
    cap.release();
    PRESS_ENTER;
    return 0;
}