创建一个小的cv :: Mat列表并迭代它的正确方法是什么?

时间:2012-07-13 03:10:13

标签: c++ opencv stl

我是C ++的新手,我正在尝试创建一个cv :: Mat的列表。

这可以分配相当多的内存,但我只有大约十个小的Mat来加载到列表中。

我制作了这段代码,但不确定它为什么不起作用。

void Utils::getFramesFromVideo(std::string file,std::list<cv::Mat>& listMatOutput) {

    cv::VideoCapture* videoCapture = new cv::VideoCapture(file);

    bool hasImage = false;

    cvNamedWindow("WhileReading", 1);

    do {
        cv::Mat frame;
        hasImage = videoCapture->read(frame);
        if (hasImage) {
            listMatOutput.push_back(frame);
            imshow("WhileReading", frame);
            waitKey(0);//give some time to see the frame (debug)
        }
    } while (hasImage);

    cvNamedWindow("AfterReading", 2);

    for (std::list<Mat>::const_iterator iterator = listMatOutput.begin();
            iterator != listMatOutput.end(); iterator++) {
        imshow("AfterReading", *iterator);
        waitKey(0);//give some time to see the frame (debug)
    }
    videoCapture->release();
}

第一次加载正确显示帧,但在第二个窗口(AfterReading)中,图像为黑色,带有红色条纹。 有人可以请一些建议吗?

2 个答案:

答案 0 :(得分:1)

列表格式是一个STL容器,这意味着您需要记住一些事情来处理它。 push_back()是向容器添加实例的首选方法,就像使用迭代器是访问列表元素的首选方法一样。如果你试图直接将列表的一个元素设置为你正在处理的cv::Mat(),那么a)你需要确切地知道列表对每个实例做了什么样的包装,所以你可以正确地做到这一点你自己,并且b)你首先打败了使用STL容器的目的,即抽象出列表的细节。

您不一定需要在代码中使用frame.clone()调用,因为这会创建图像的深层副本并占用宝贵的资源。我知道我过去曾使用std::vector<cv::Mat>而不必为向量中的每个元素制作深层副本,因此我假设您应该能够将Mat本身传递给列表。咨询the C++ documentation on STL lists

您可能会考虑另一件事,如果内存使用率低和通过列表访问的速度是一个问题,并且您的图像数量很少,则是一个图像指针列表。将您的图片存储为单独的cv::Mat个实例,并创建类型std::list<cv::Mat*>的列表,将图片句柄传递给push_back()个调用。当然,使用这种方法,您的图像将不会是“线程安全的”,因为它们将存储在一个地方,但是从另一个地方调用和处理。我希望这会对你的询问有所启发。

答案 1 :(得分:0)

我尝试了各种各样的事情,比如更改指针或向量以及检查GCC上的代码优化。然后在尝试克隆cv :: Mat后,它起作用了:

listMatOutput.push_back(frame.clone());

如果有人能告诉我原因并提出更好的做法,我会很高兴,所以我可以选择一个比我自己更好的答案。