2

I'm trying to double buffer my VideoCapture output in my OpenCV program (to reduce flicker). Here's the concept so far:

    Mat frameA, frameB;  //alternating between these two for storage
    VideoCapture cap(0); // open the default camera
    for(;;)
    {
        cap >> frameB; 
        waitKey(30);
        cap >> frameA;
        waitKey(30);


        putText(frameA,SSTR("A"),Point(frameA.cols/2,frameA.rows/2),3,5,CV_RGB(250,200,200));
        putText(frameB,SSTR("B"),Point(frameA.cols/2,frameB.rows/2),3,5,CV_RGB(250,200,200));


        imshow("A",frameA);
        imshow("B",frameB);

        waitKey(30);

    }

as a simple test I write the text A or B in the center of the frame. But the output has A and B overlapping - as if there were not two separate frames. What am I doing wrong?
I have made a solution by using the .clone() operator, but I understand that that sort of thing is horribly expensive in terms of CPU (?) and so would like to avoid it. Hopefully we've got some C++ double buffering experts here.

4

2 に答える 2

1

I have the same problem. I think, you found a bug in OpenCV (2.4.9v for me) implementation. In source of HiGUI module (cap.cpp):

bool VideoCapture::retrieve(Mat& image, int channel)
{
    IplImage* _img = cvRetrieveFrame(cap, channel);
    if( !_img )
    {
        image.release();
        return false;
    }
    if(_img->origin == IPL_ORIGIN_TL)
        image = Mat(_img); << NO COPY
    else
    {
        Mat temp(_img);    << NO COPY
        flip(temp, image, 0); << Here is deep copy done
    }
    return true;
}

in case if _img->origin == IPL_ORIGIN_TL conversion from IplImage to cv::Mat was done WITHOUT copying the data, because declaration of constructor looks like this:

//! converts old-style IplImage to the new matrix; the data is not copied by default
Mat(const IplImage* img, bool copyData=false);

Suggested solution:

  1. copy grabbed cv::Mat manually.
  2. Somebody should submit a bug to OpenCV.

Upd. seems that this note from documentation actual for OpenCV 2.x too:

Note: OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using cvCloneImage() and then do whatever you want with the copy.

于 2012-12-19T06:39:25.010 に答える
0

The OpenCV documentation is not clear, but this note also applies to the 2.x API:

Note: OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using cvCloneImage() and then do whatever you want with the copy.

This means OpenCV uses always the same memory location to read the camera input, so the call to clone() cannot be avoided.

于 2013-05-22T12:19:37.403 に答える