带有 EmguCV 的 QueryGrayFrame() 上的 SystemOutOfMemoryException

SystemOutOfMemoryException on QueryGrayFrame() with EmguCV

我正在使用此例程将视频的所有帧放入帧数组中:

点击:

private int CompareTwoVideos(string _firstVideoPath, string _secondVideoPath)
        {
            Capture _capture;
            List<Image<Gray, Byte>> FirstALLFrames = new List<Image<Gray, Byte>>();
            // ..

            _capture = new Capture(FirstVideoLocation);

            // get all frames
            FirstALLFrames = GetAllFrames(_capture);

            // do some image processing
            // .. 

            _capture.Dispose();
            return 0;
        }

效用函数:

List<Image<Gray, byte>> GetAllFrames(Capture _capture)
{
    List<Image<Gray, byte>> AllFrames = new List<Image<Gray, byte>>();
    int FramesCount = 0;

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

        for (int i = 0; i < FramesCount - 1; i++)
        {
            AllFrames.Add(_capture.QueryGrayFrame().Resize(ImageWidth, ImageHeight, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR));
        }
    }
    catch (Exception ex)
    {
        // Error pops here
    }

    return AllFrames;
}

第一次点击一切正常。

但是,第二次单击时会弹出错误

有什么想法吗?

我不是 100% 确定你对 "second click" 的意思,但我假设这意味着你 运行 代码直接再次处理另一个视频。

看来你的列表变大了,占用了很多内存(也写成under Exceptions in the List(T) MSDN documentation)。您确实处置了 _capture 对象,但没有处置您的列表。因此,列表中可能仍有引用,这会阻止它被系统正确处理和收集(因此请确保您没有对该列表的任何其他引用)。

此外,替换引用(使用您的 new List() 实例)不会立即释放集合,垃圾收集器处理对象需要一些时间。第二次点击很可能只会导致您的程序使用过多的内存,因为它现在在内存中包含太多完整的视频。您是否监控过您的应用程序内存使用情况?

因此您可以尝试一些事情:

  1. 使用 List.Clear() 方法可能会有所帮助,因为它会消除列表中的值。它不会直接释放分配的内存。这可能会有所帮助,因为垃圾回收可以快速清理列表,但我不确定这对您的情况有多有效。

  2. 确保通过调用 List = null 消除对列表的所有引用。然后通过调用GC.Collect()强制垃圾收集器直接收集垃圾。这会占用资源,因为你调用收集器的那一刻它可能并不完全适合,但特别是如果性能不是问题,这应该不会造成问题。

  3. 最后,尝试处理每一帧,直接丢弃,再处理下一帧。或者尝试分批处理视频(只要有可能)。这将减轻您的记忆负担。