2

我正在尝试在我的 OpenCV 程序中双重缓冲我的 VideoCapture 输出(以减少闪烁)。这是到目前为止的概念:

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

    }

作为一个简单的测试,我将文本 A 或 B 写在框架的中心。但是输出有 A 和 B 重叠 - 好像没有两个单独的帧。我究竟做错了什么?
我已经通过使用 .clone() 运算符提出了一个解决方案,但我知道这种事情在 CPU(?)方面非常昂贵,所以想避免它。希望我们这里有一些 C++ 双缓冲专家。

4

2 回答 2

1

我也有同样的问题。我认为,您在 OpenCV(对我来说是 2.4.9v)实现中发现了一个错误。在 HiGUI 模块 (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;
}

如果 _img->origin == IPL_ORIGIN_TL 从 IplImage 到 cv::Mat 的转换是在没有复制数据的情况下完成的,因为构造函数的声明如下所示:

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

建议的解决方案:

  1. 手动复制抓取的 cv::Mat。
  2. 有人应该向 OpenCV 提交错误。

更新。似乎OpenCV 2.x的文档中的这个注释也是:

注意:OpenCV 1.x 函数 cvRetrieveFrame 和 cv.RetrieveFrame 返回存储在视频捕获结构中的图像。不允许修改或发布图像!您可以使用 cvCloneImage() 复制框架,然后对副本执行任何操作。

于 2012-12-19T06:39:25.010 回答
0

OpenCV 文档不清楚,但此说明也适用于 2.x API:

注意:OpenCV 1.x 函数 cvRetrieveFrame 和 cv.RetrieveFrame 返回存储在视频捕获结构中的图像。不允许修改或发布图像!您可以使用 cvCloneImage() 复制框架,然后对副本执行任何操作。

这意味着 OpenCV 总是使用相同的内存位置来读取相机输入,因此无法避免对 clone() 的调用。

于 2013-05-22T12:19:37.403 回答