You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的原生内存;
  • 对于循环中创建的needle Mat,同样用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 05:00:20