在 C# 中使用 EmguCV 时需要注意的一些问题

第一次使用 EmguCV 处理图像问题,使用过程中总是莫名其妙的闪退,程序崩溃,或者内存泄漏。

刚开始以为是EmguCV那些地方用的不对,后来发现可能更是因为 PictureBox用的不好。

罗列注意事项一两点。希望能保住遇到同样问题的童鞋们。

EmguCV 是 OpenCV在.Net平台上的一个包,详见 http://www.emgu.com/wiki/index.php/Main_Page

我用的EmguCV 版本是 NuGet中的v3.4.3.3016


故障1:

“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

An unhandled exception of type 'System.AccessViolationException' occurred in System.Drawing.dll

多半因为没有及时Dispose掉不用的缓存,或者持续引用导致GC都清理不掉部分缓存。


故障2:

程序闪退

多半因为调用EmguCV时出错,建议在适当的地方添加 Try Catch.


收获 和 注意事项

1.频繁设置PictureBox时,释放上一次缓存。

(参考:https://stackoverflow.com/questions/1831732/c-sharp-picturebox-memory-releasing-problem

 1         public static void ClearAndSetImage(PictureBox dest, Bitmap src)
 2         {
 3             if (dest == null) return;
 4             
 5             if (dest.Image != null)
 6                 dest.Image.Dispose();     //释放上次的图片
 7 
 8             if (src == null)
 9             {
10                 dest.Image = null;
11             }
12             else
13             {
14                 dest.Image = new Bitmap(src); // 设置本次图片
15                 src.Dispose();
16             }
17         }

 

2.调用EmguCV的Mat输出Image时,转换为Image再输出Bitmap

  这点,我没有仔细考究,只是在网上发现类似的对策,使用后,效果良好,就没再仔细验证。

  (参考原著:https://blog.csdn.net/oHuanCheng/article/details/81451909

        public static Bitmap Crop(Bitmap src, Rectangle rect)
        {
            Image<Bgr, Byte> img = new Image<Bgr, byte>(src);

            //Check Crop area
            //crop数据超出范围也会触发Emgu的错误,导致程序闪退。

            if (rect.X > img.Width) rect.X = img.Width-1;
            if (rect.Y > img.Height) rect.Y = img.Height-1;
            if (rect.X + rect.Width > img.Width) rect.Width = img.Width - rect.X;
            if (rect.Y + rect.Height > img.Height) rect.Height = img.Height - rect.Y;
            
            Mat crop = new Mat(img.Mat, rect);

            //转换为Image输出Bitmap
            Image<Bgr, Byte> outImg = crop.ToImage<Bgr, Byte>();
            
//使用 new Bitmap 切断和outImg间的关系 Bitmap rtn
= new Bitmap(outImg.Bitmap); return rtn; }

 

3. 使用 new Bitmap() 来切断引用

      Bitmap.clone() 是效率高的浅复制,共享图片bit

      new Bitmap() 是效率低占内存多的深复制,和被拷贝的对象间没有指引关系。

      使用 new Bitmap() 后,资源可以被GC有效回收,或者手动Dispose不会报错。

      实例代码见第一条和第二条中的应用。

4. 对可能出现 EmguCV 错误的地方进行捕获 

            Image<Bgr, Byte> img = new Image<Bgr, byte>(input).Resize(400, 400, Emgu.CV.CvEnum.Inter.Linear, true);
            //Convert the image to grayscale and filter out the noise
            UMat uimage = new UMat();
            try
            {
                // 这句话不稳定,有时会报错  OpenCV: OpenCL error CL_OUT_OF_RESOURCES (-5)
                // C#捕获失败会导致程序闪退
                // 添加捕获后,可保证程序持续运行,第二次执行是好的。
                CvInvoke.CvtColor(img, uimage, ColorConversion.Bgr2Gray);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Print(ex.Message);
            }

 

5. 程序长时间运行后,依然会莫名其妙的崩溃,问题持续查找中。

 TBD

其他参考链接:

https://blog.csdn.net/liukun0928/article/details/71516020

猜你喜欢

转载自www.cnblogs.com/jiceberg420/p/10636137.html