Emgu.CV+C#中Mat数据频繁损坏的问题求助
问题分析与解决方案
核心原因
你遇到的System.AccessViolationException是因为Emgu.CV的Mat(Mat, Rectangle)构造函数返回的是原Mat的子视图(共享底层内存),而非独立的Mat对象。当原Mat(比如你代码中image.ToImage<Bgr, byte>().Mat这个临时对象)被.NET垃圾回收器回收后,子Mat的底层内存会被释放,后续对该子Mat的操作(比如第二次Save)就会访问无效内存,触发异常。
具体修复步骤
1. 修改Shot类的构造函数,创建独立Mat而非引用
将原构造函数中创建子Mat的逻辑改为克隆指定区域,确保Shot.image拥有独立的内存空间,不再依赖临时Mat的生命周期:
internal class Shot { public Mat image { get; } public int time { get; } public Shot(Bitmap image, Rectangle rect, int time) { // 使用using包裹临时Image/Mat,确保原生内存及时释放 using (var tempImage = image.ToImage<Bgr, byte>()) { var tempMat = tempImage.Mat; // 克隆指定区域的Mat,生成独立对象 this.image = tempMat.Clone(rect); } this.time = time; } private Shot(Mat image, int time) { this.image = image; this.time = time; } public Shot Clone() { return new Shot(image.Clone(), time); } // 新增Dispose方法,手动管理Mat的原生内存 public void Dispose() { image?.Dispose(); } }
2. 手动管理Mat的生命周期,不要完全依赖GC
Emgu.CV的Mat封装了OpenCV的原生内存,.NET GC无法感知原生内存的占用情况,容易出现回收不及时或内存泄漏。你需要:
- 在不再使用
Shot对象时,调用Dispose()方法释放image的原生内存; - 对于循环中创建的
needleMat,同样用using语句包裹,或者使用完后手动调用Dispose():using (var needle = ...) // 创建needle的逻辑 { // 使用needle进行测量操作 } // 离开using块后自动释放needle的原生内存
3. 检查GetPrintscreenMat方法的实现
确保该方法返回的是独立的Mat对象,而非原截图Mat的子视图。如果方法内部使用了Mat(Mat, Rectangle)构造,同样改为Clone(rect)的方式。
验证极端场景
修复后,你的测试代码中两次currentBlackScreen.Save()都能正常执行,因为currentBlackScreen拥有独立的内存空间,不会因为其他对象被回收而失效。
内容的提问来源于stack exchange,提问作者Valter Rönisch
相关产品推荐
相关产品推荐

