【问题标题】:How to fix this Out OF Memory Exception when Processing a video using EmguCV QueryGrayFrame()使用 EmguCV QueryGrayFrame() 处理视频时如何解决此内存不足异常
【发布时间】:2017-04-23 01:07:10
【问题描述】:

我已经研究了一段时间,但我仍然找不到问题的根源。

首先,请注意所有视频均为 15 秒,总共 450 帧。框架稍后会调整为 50x50。

使用 EmguCv,我正在使用以下例程来获取视频的所有帧:

public void PopulateAllFrames()
    {
        int FramesCount = 0;

        try
        {                 
            FramesCount = (int)capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_COUNT);

            for (int i = 0; i < FramesCount; i++)
            {
                var frame = capture.QueryGrayFrame(); // Error here
                var resized = frame.Resize(ImageWidth, ImageHeight, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                AllFrames.Add(resized.Copy());
            }

            capture.Dispose();
            GC.Collect();
        }
        catch (Exception ex)
        { }
    }

当我在按钮点击上加载任何视频时,上述工作正常:

private void SelectAVideo_Click(object sender, EventArgs e)
{
    try
    {
        OpenFileDialog OpenFile = new OpenFileDialog();

        if (OpenFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {            
            OriginalVideo = new MyVideo(OpenFile.FileName, true);

            OriginalVideo.PopulateAllFrames();     
    }
    catch (Exception ex)
    {}
}

但当我加载包含 25 个视频的目录时,它对某些视频不起作用。通过的视频每次都是相同的视频,“错误”的视频也每次都是相同的:

private void LoadDirectory_Click(object sender, EventArgs e)
{ 
    try
    {
        using (var fbd = new FolderBrowserDialog())
        {
            DialogResult result = fbd.ShowDialog();

            if (result == DialogResult.OK && fbd.SelectedPath != null)
            {
                AllVideos = new List<MyVideo>();

                AllVideosFileNames = Directory.GetFiles(fbd.SelectedPath).ToList();

                for (int i = 0; i < AllVideosFileNames.Count(); i++) // loop the rest of the videos, start from the 5th video and till the end
                 {
                    MyVideo CurrentVideo = new MyVideo(AllVideosFileNames[i], false);
                    CurrentVideo.PopulateAllFrames();
                    AllVideos.Add(CurrentVideo);

                 } 
    }
    catch (Exception ex)
    { }
}

每当我点击QueryGrayFrame() 时,我都会收到OutOfMemoryException,每次我执行时都在同一组视频上,即使我只加载了 10 个视频。并且没有模式(意味着错误不会仅在最后 10 个索引上弹出......等)。知道视频真的很小,如果我单独加载这些视频中的任何一个,它都可以正常工作。

我该如何解决这个问题?

【问题讨论】:

  • 如果您在处理之前随机化视频列表,是否仍然会发生在相同的视频上?
  • 您的 frame 变量实现了 IDisposable 但您不处置它。与resized 相同。
  • @Evk 我不知道该告诉你什么 :) 一旦我添加了 frame.Dispose()resized.Dispose() 一切都按预期工作!
  • 由于视频格式使用的压缩算法,视频文件很小。当您拉出所有帧时,您将撤消该压缩并以最原始的格式处理视频。例如,一个 15 秒长、30 fps 的 720p 视频作为一个文件可能只有几兆字节,但将所有图像拉出来,突然间你正在处理 1,244,160,000 字节(1.24 GB)的数据。因此,如果您在使用它们后不Dispose 帧,那么您会将所有这些数据存储在内存中。
  • 参考数学:1280 像素宽度 * 720 像素高度 * 每像素 3 个通道 * 15 秒 * 30 帧每秒 = 1,244,160,000 字节(假设每个通道 8 位)。

标签: c# video out-of-memory video-capture emgucv


【解决方案1】:

如 cmets 中所述,我只需要 .Dispose() 我的变量,因为我的视频很小,所以我没有想到这一点。事实证明,它们仍然占用了大量内存。这样做解决了问题:

for (int i = 0; i < FramesCount; i++)
        {
            var frame = capture.QueryGrayFrame(); // Error here
            var resized = frame.Resize(ImageWidth, ImageHeight, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
            AllFrames.Add(resized.Copy());
            frame.Dispose();
            resized.Dispose();
        } 

【讨论】:

  • 太棒了!谢谢你:)
猜你喜欢
  • 2014-07-20
  • 2013-10-13
  • 2012-05-11
  • 1970-01-01
  • 2010-10-15
  • 1970-01-01
  • 2017-06-18
  • 1970-01-01
  • 2011-04-13
相关资源
最近更新 更多