1

我使用下面的代码从相机读取每一帧并将其推送到向量。我这样做是为了稍后处理向量中所有收集的帧。

我使用下面的代码从相机收集帧。但是在 2005 帧之后,代码会引发以下错误。

OpenCV 错误:OutOfMemoryError 中的内存不足(无法分配 921604 字节),文件 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;
 }
4

3 回答 3

5

就像错误提示的那样,您可能内存不足。如果每帧是 640*480(即非常低的分辨率),则 2005 * 640 * 480 * 3(每像素字节数)= 1,847,808,000(即在连续块中分配 1.8GB 的​​ RAM)。

同样,每次向量必须调整自身大小时,它都需要进行足够大的分配以容纳新数据,然后将旧数据复制到新向量,然后释放旧分配,从而有效地将所需的内存量加倍。

于 2013-05-07T13:05:49.477 回答
2

如错误所述,您的程序已达到操作系统为您的进程保留的 RAM 限制。你可以做一些事情来减少这个问题:

1 -将图像编码为更紧凑的格式,例如 .jpg。这将减少帧使用的内存。

2 -将缓冲区保存在磁盘上。由于这可能很慢,并且您不想丢失帧速率,因此您可能需要在生产者/消费者方案中使用新线程。

3 - 降低图像的分辨率。我不知道您的具体用例,但缩小的图像可能适用于许多计算机视觉算法。无需存储所有颜色信息。

4 - 只存储图像的有趣点:这是计算机视觉社区中非常常见的方法。同样,我不知道您要完成什么,但也许您可以对每一帧的图像进行一些预处理并仅存储相关点?也许您需要一些预处理算法的 GPU 实现来保持实时帧速率。

请记住,即使您显着减少每帧存储的内存量,您最终仍然会耗尽内存。如果不将信息保存在磁盘上,这几乎可以保证。

于 2013-05-07T13:14:24.443 回答
2

原始帧大小很大。您通常应该预先分配至少 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),以便编码器可以赶上。

于 2013-05-07T13:24:10.167 回答