我是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)中,图像为黑色,带有红色条纹。 有人可以请一些建议吗?
答案 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());
如果有人能告诉我原因并提出更好的做法,我会很高兴,所以我可以选择一个比我自己更好的答案。