3

我是 C++ 新手,我正在尝试创建一个 cv::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)中,图像是黑色的,带有红色条纹。有人可以给一些建议吗?

4

2 回答 2

1

列表格式是一个 STL 容器,这意味着您需要记住一些事项才能使用它。push_back()是向容器添加实例的首选方法,就像使用迭代器是访问列表元素的首选方法一样。如果您尝试将列表的一个元素直接设置为cv::Mat()您正在处理的 a),那么 a) 您需要确切知道列表对每个实例执行的包装类型,以便您可以自己正确地执行此操作,并且 b)您首先违背了使用 STL 容器的目的,即抽象出列表的详细信息。

您不一定需要frame.clone()在代码中使用该调用,因为这会创建图像的深层副本并占用宝贵的资源。我知道我过去使用std::vector<cv::Mat>过,而不必为向量中的每个元素制作深拷贝,所以我假设你应该能够将 Mat 本身传递给一个列表。请参阅有关 STL 列表的 C++ 文档

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

于 2012-07-15T18:55:46.973 回答
0

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

listMatOutput.push_back(frame.clone());

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

于 2012-07-13T23:55:52.483 回答