将视频文件推入矢量时矢量内存不足?
Posted
技术标签:
【中文标题】将视频文件推入矢量时矢量内存不足?【英文标题】:Vector insufficient memory while pushing the video file into the vector? 【发布时间】:2013-05-07 12:55:54 【问题描述】:我使用下面的代码从相机读取每一帧并将其推送到向量。我这样做是为了稍后处理向量中所有收集的帧。
我使用以下代码从相机收集帧。但是在 2005 帧之后,代码会抛出以下错误。
OpenCV 错误: Insufficient memory (Failed to allocate 921604 bytes) in OutOfMemoryError,文件 D:\Opencv\modules\core\src\alloc.cpp,第 52 行
下面是我用来收集帧并将其推入向量的代码。
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/contrib/contrib.hpp"
#include <stdio.h>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <stdlib.h>
using namespace std;
using namespace cv;
int main()
VideoCapture capture(0);
if(!capture.isOpened())
return -1;
vector <Mat> frame;
int delay = 10;
int count = 0;
Mat src;
while(true)
capture >> src;
frame.push_back(src.clone());
imshow("VIDEO", src);
if( waitKey( delay ) >= 0) break;
count = count+1;
cout << count << endl;
/* I need to process each frame stored inside the vector*/
destroyWindow("VIDEO");
capture.release();
return 0;
【问题讨论】:
将帧提取到磁盘并 push_back 向量内的文件名。 【参考方案1】:您可能像错误提示的那样内存不足。如果每帧是 640*480(即非常低的分辨率),则 2005 * 640 * 480 * 3(每像素字节数)= 1,847,808,000(即在连续块中分配 1.8GB 的 RAM)。
同样,每次向量必须调整自身大小时,它需要进行足够大的分配以容纳新数据,然后将旧数据复制到新向量,然后解除分配旧分配,有效地使您需要的内存量加倍.
【讨论】:
【参考方案2】:如错误所述,您的程序已达到操作系统为您的进程保留的 RAM 限制。你可以做一些事情来减少这个问题:
1 - Encode the image to a more compact format,例如 .jpg。这将减少框架使用的内存。
2 - Save your buffer on disk。由于这可能很慢,并且您不想丢失帧速率,因此您可能需要在生产者/消费者方案中使用新线程。
3 - 降低图像的分辨率。我不知道您的具体用例,但缩小的图像可能适用于许多计算机视觉算法。无需存储所有颜色信息。
4 - 仅存储图像的有趣点:这是计算机视觉社区中非常常见的方法。同样,我不知道您要完成什么,但也许您可以对每一帧的图像进行一些预处理并仅存储相关点?也许您需要一些 GPU 实现预处理算法以保持实时帧速率。
请记住,即使您显着减少每帧存储的内存量,您最终仍会耗尽内存。如果不将信息保存在磁盘上,这几乎可以保证。
【讨论】:
1 -> 只有拥有硬件加速器才能执行此操作。如果相机以 30 fps 的速度丢帧,则您有 30 毫秒的时间进行编码。 2-> 保存到磁盘。这只会在内存不足时推迟这一点。唯一的解决方案是动态处理。 您是在认真暗示我的回答是错误的吗?对我来说,它清楚地看到你只是在扔回 -1。严肃地说,如果你真的暗示编码图像不是一种选择,那么你真的只是想激怒我。它用于 100% 的任何流服务。您认为您如何能够以 30 FPS 的 10MB 连接观看 FULL HD?我已经在某些应用程序中使用 opencv 编码为 jpeg,没有发现性能下降,仍然以 30FPS 处理。 @Chethan 关于磁盘。将帧保存在磁盘上有什么问题?这显然会为他节省一些 RAM,因为他会将缓冲区的一些内容扔掉。可能使用普通的 7200RPM HD,他将无法以 30FPS 保存所有帧,但它显然会解决他在一段时间内面临的问题(如果需要实时,则未说明)。当然,HD 的内存有限,最终会耗尽,但如果他将这种方法与所有其他解决方案结合起来,这是完全合理的可能性。 @Chethan:30 毫秒是相当多的时间,但是,是的,你最好使用 GPU 来完成繁重的工作。保存到磁盘可能只是推迟不可避免的事情,但你没有足够的 RAM,所以可能足够长的时间来做你需要做的事情。如果不是,除了更改算法之外,您无能为力...【参考方案3】:原始帧尺寸很大。您通常应该预分配至少 2 帧并且少于 4 帧,具体取决于相机源的抖动程度。多媒体系统总是预先分配内存。
所以你通常应该这样做..
for(int i=0; i<NUM_FRAMES; i++
frames.push_back(new Mat()); //handle exceptions from new.
然后使用框架回收
int i=0;
int curr_frame=i;
while(true)
capture >> *(frames[i]);
//show frame
i = (i+1)%NUM_FRAMES;
//process frames[curr_frame]..
您实际上应该在运行中进行处理,最好在单独的线程上进行。因此,您的处理时间必须与相机捕获率大致匹配。也就是说,不应该发生您尚未处理某个帧但被相机覆盖的情况。如果算法的处理时间是可变的,比如在视频编码器中,jitter buffer 会有所帮助。会有足够数量的缓冲区(NUM_FRAMES),这样编码器才能赶上。
【讨论】:
什么?为什么不只是 frames.resize(NUM_FRAMES)?为什么要使用指针向量而不是对象? 你意识到推后很多帧,而不是再次开始推后只会给他带来更多麻烦吧? @IanMedeiros 请仔细阅读我的帖子。我只推送指向预分配对象的指针。它一次具有固定的内存要求 = NUM_FRAMES * 宽度 * 高度 * bits_per_pixel 我真的不明白你是如何在帧向量内推送 Mat 指针 NUM_FRAMES 次的,而不是开始将 src.clone() 推送到期望指针的同一向量中,而 .clone 返回参考。我只能猜测这是一个错字?仅使用 capture >> frames[i] 就足够了。即使这样,代码也可能无法编译,因为 VideoCapture::operator>> 也返回了引用? @IanMedeiros 是的,这是一个错字。已纠正。以上是关于将视频文件推入矢量时矢量内存不足?的主要内容,如果未能解决你的问题,请参考以下文章