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

C# EmguCV关闭摄像头问题:窗口关闭后仍持续捕获人脸

解决摄像头无法停止及Dispose后空引用异常的问题

你遇到的两个问题其实是关联的核心问题导致的:没有移除Application.Idle事件的订阅,使得即使摄像头被暂停/释放,ProcessFrame方法仍会被持续触发,最终引发空引用异常。

问题根源拆解

当你订阅Application.Idle += ProcessFrame后,只要应用程序处于空闲状态,这个事件就会不断调用ProcessFrame方法。哪怕你调用Pause()或Stop(),事件订阅依然存在,ProcessFrame还是会尝试从_cameraCapture获取帧;而调用Dispose()后_cameraCapture被释放为null,此时QueryFrame()自然会抛出空引用异常。

分步解决方案

  1. 先切断事件触发源:停止摄像头前必须移除Application.Idle的事件订阅,这是解决问题的核心。
  2. 按顺序执行停止/释放:先移除事件,再停止摄像头,最后按需释放资源。
  3. 添加窗口关闭防护:防止用户直接关闭窗口时,摄像头仍在后台运行。
  4. 增强方法安全性:在ProcessFrame中增加空值判断,避免意外报错。

修改后的代码示例

1. 调整停止按钮点击事件逻辑

private void btnStopCamera_Click(object sender, EventArgs e)
{
    // 第一步:移除Idle事件订阅,彻底停止ProcessFrame的触发
    Application.Idle -= ProcessFrame;

    // 第二步:安全停止并释放摄像头
    if (_cameraCapture != null && _cameraCapture.IsOpened)
    {
        _cameraCapture.Stop();
        _cameraCapture.Dispose();
        _cameraCapture = null; // 显式置空,避免后续误操作
    }

    this.Close();
    faceManipulate fm = new faceManipulate();
    fm.Show();
}

2. 添加窗口关闭事件处理

在窗体构造函数中订阅FormClosing事件,确保用户直接关窗口时也能停止摄像头:

public VideoSurveilance()
{
    InitializeComponent();
    this.FormClosing += VideoSurveilance_FormClosing;
    Run();
}

private void VideoSurveilance_FormClosing(object sender, FormClosingEventArgs e)
{
    // 窗口关闭时自动执行停止逻辑
    Application.Idle -= ProcessFrame;
    if (_cameraCapture != null)
    {
        if (_cameraCapture.IsOpened)
            _cameraCapture.Stop();
        _cameraCapture.Dispose();
        _cameraCapture = null;
    }
}

3. 增强ProcessFrame方法的安全性

void ProcessFrame(object sender, EventArgs e)
{
    // 先判断摄像头是否有效,避免空引用
    if (_cameraCapture == null || !_cameraCapture.IsOpened)
        return;

    Mat frame = _cameraCapture.QueryFrame();
    // 额外判断帧是否为空(比如摄像头意外断开时)
    if (frame == null)
        return;

    Mat smoothedFrame = new Mat();
    CvInvoke.GaussianBlur(frame, smoothedFrame, new Size(3, 3), 1);
    
    // 记得释放Mat对象,避免内存泄漏
    smoothedFrame.Dispose();
    frame.Dispose();
}

额外注意事项

  • 原代码中没有释放Mat对象,长期运行会导致内存泄漏,上面的代码已经补充了这部分逻辑。
  • 每次操作摄像头前先检查_cameraCapture.IsOpened,可以避免很多无效调用的异常。

内容的提问来源于stack exchange,提问作者scarlet pro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:06:25