将视频文件推入矢量时矢量内存不足?

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 是的,这是一个错字。已纠正。

以上是关于将视频文件推入矢量时矢量内存不足?的主要内容,如果未能解决你的问题,请参考以下文章

Pinecone矢量数据库介绍

如何在不因内存不足而导致应用程序崩溃的情况下擦除矢量元素?

GIS当中矢量数据、影像数据、地形数据等常见数据格式的介绍

带有 PDF 矢量图像的资产目录不会为 iOS 导出 @3x 分辨率

如何把JPG文件转为SHP文件,

ArcGIS超级工具SPTOOLS-按属性裁剪,矢量数据批量裁剪,矢量数据批量合库