我正在使用Emgu OpenCV从网络摄像头获取图像,并希望使用WPF Image控件将其可视化。
因此,我需要将图像从Mat转换为与Image控件兼容的图像。因此,我从Emgu示例中学习了此类:

public static class BitmapSourceConvert
{
    /// <summary>
    /// Delete a GDI object
    /// </summary>
    /// <param name="o">The poniter to the GDI object to be deleted</param>
    /// <returns></returns>
    [DllImport("gdi32")]
    private static extern int DeleteObject(IntPtr o);

    /// <summary>
    /// Convert an IImage to a WPF BitmapSource. The result can be used in the Set Property of Image.Source
    /// </summary>
    /// <param name="image">The Emgu CV Image</param>
    /// <returns>The equivalent BitmapSource</returns>
    public static BitmapSource ToBitmapSource(IImage image)
    {
        using (System.Drawing.Bitmap source = image.Bitmap)
        {
            IntPtr ptr = source.GetHbitmap(); //obtain the Hbitmap
            BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                ptr,
                IntPtr.Zero,
                Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

            DeleteObject(ptr); //release the HBitmap
            return bs;
        }
    }
}


这对于小图像(例如640 x 480)来说就像是一种魅力。使用任务管理器时(我在Windows 8上),我看到使用的内存在增加和减少。工作正常。

但是,当使用较大的图像(如1920x1080)时,应用程序会在短时间内崩溃,但出现异常,表明没有更多的内存。再次查看任务管理器时,我看到内存消耗上升,一次下降,然后上升直到引发异常。
感觉垃圾收集器的工作频率不足以释放所有空间。

因此,我尝试通过在函数中的某处添加GC.Collect()来手动启动垃圾收集器。并且它再次起作用。即使图像较大。

我认为手动调用垃圾收集器既不是好的样式也不是高性能。谁能在不调用GC.Collect()的情况下提示如何解决此问题?

最佳答案

最后,我认为问题在于,垃圾收集器不知道映像的大小,因此无法计划合理的时间表。我找到了方法

GC.AddMemoryPreasure(long bytesAllocated)
GC.RemoveMemoryPreasure(long bytesAllocated)


这些方法告诉垃圾收集器何时分配和释放了较大的非托管对象,以便垃圾收集器可以更好地计划其调度。

以下代码可以正常工作,没有任何内存问题:

    public static BitmapSource ToBitmapSource(IImage image)
    {
        using (System.Drawing.Bitmap source = image.Bitmap)
        {
            IntPtr ptr = source.GetHbitmap(); //obtain the Hbitmap
            long imageSize = image.Size.Height*image.Size.Width*4; // 4 bytes per pixel
            GC.AddMemoryPressure(imageSize);
            BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                ptr,
                IntPtr.Zero,
                Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

            DeleteObject(ptr); //release the HBitmap
            GC.RemoveMemoryPressure(imageSize);
            return bs;
        }
    }

10-07 20:25