【问题标题】: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 向量内的文件名。

标签: c++ opencv image-processing computer-vision


【解决方案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 是的,这是一个错字。已纠正。
    猜你喜欢
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 2014-08-19
    • 2011-09-25
    • 2012-12-14
    • 2014-04-21
    • 1970-01-01
    • 2013-05-26
    相关资源
    最近更新 更多