C# EmguCV关闭摄像头问题:窗口关闭后仍持续捕获人脸
解决摄像头无法停止及Dispose后空引用异常的问题
你遇到的两个问题其实是关联的核心问题导致的:没有移除Application.Idle事件的订阅,使得即使摄像头被暂停/释放,ProcessFrame方法仍会被持续触发,最终引发空引用异常。
问题根源拆解
当你订阅Application.Idle += ProcessFrame后,只要应用程序处于空闲状态,这个事件就会不断调用ProcessFrame方法。哪怕你调用Pause()或Stop(),事件订阅依然存在,ProcessFrame还是会尝试从_cameraCapture获取帧;而调用Dispose()后_cameraCapture被释放为null,此时QueryFrame()自然会抛出空引用异常。
分步解决方案
- 先切断事件触发源:停止摄像头前必须移除
Application.Idle的事件订阅,这是解决问题的核心。 - 按顺序执行停止/释放:先移除事件,再停止摄像头,最后按需释放资源。
- 添加窗口关闭防护:防止用户直接关闭窗口时,摄像头仍在后台运行。
- 增强方法安全性:在
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
相关产品推荐
相关产品推荐

