如何用OpenCVSharp实现基于MOG的运动物体识别?

摘要:效果 动态效果: 实现 运动物体检测是计算机视觉中的一个重要应用,广泛应用于安防监控、交通分析、人机交互等领域。本文将详细介绍如何使用OpenCVSharp中的MOG(Mixture of Gaussians)算法实现运动物体检测,并通过一
效果 动态效果: 实现 运动物体检测是计算机视觉中的一个重要应用,广泛应用于安防监控、交通分析、人机交互等领域。本文将详细介绍如何使用OpenCVSharp中的MOG(Mixture of Gaussians)算法实现运动物体检测,并通过一个完整的WPF应用程序示例展示实际应用。 什么是MOG算法? MOG(Mixture of Gaussians,高斯混合模型)是一种基于背景建模的运动检测算法。它通过对每个像素建立多个高斯分布模型来表示背景,能够有效处理光照变化、树叶摇曳等动态背景干扰。 MOG算法原理 背景建模:为每个像素建立K个高斯分布模型 模型匹配:将当前像素值与已有模型进行匹配 模型更新:根据匹配结果更新模型参数 前景检测:不匹配任何背景模型的像素被标记为前景 ViewModel设计 我们使用MVVM模式设计应用程序,主要包含以下属性和命令: public class MovingObjectDetectionViewModel : BindableBase { // 视频路径 public string VideoPath { get; set; } // 图像显示 public BitmapImage OriginalImage { get; set; } public BitmapImage ProcessedImage { get; set; } // 处理状态 public bool IsProcessing { get; set; } public string StatusMessage { get; set; } // 检测参数 public double DetectionThreshold { get; set; } // 统计信息 public int FrameCount { get; set; } public int DetectedObjectsCount { get; set; } // 命令 public ICommand SelectVideoCommand { get; private set; } public ICommand RunCommand { get; private set; } public ICommand StopCommand { get; private set; } } 主要实现在RunAsync中,我们来学习一下用到了OpenCVSharp的哪些方法。 using var capture = new VideoCapture(VideoPath); // 获取视频信息 int frameWidth = (int)capture.Get(VideoCaptureProperties.FrameWidth); int frameHeight = (int)capture.Get(VideoCaptureProperties.FrameHeight); double fps = capture.Get(VideoCaptureProperties.Fps); int totalFrames = (int)capture.Get(VideoCaptureProperties.FrameCount); 首先可以这样获取视频的一些信息: using var mog = BackgroundSubtractorMOG.Create(); using var frame = new Mat(); using var fg = new Mat(); using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(5, 5)); 遇到了一个新东西Cv2.GetStructuringElement。这行代码是创建一个形态学操作的结构元素(也称为核或卷积核),用于图像处理中的形态学变换。 Cv2.MorphologyEx(fg, fg, MorphTypes.Open, kernel); 这是OpenCVSharp中执行高级形态学操作的函数,支持多种形态学变换类型。 参数说明 第一个参数 fg:输入图像,即经过MOG背景减除后的前景掩码 第二个参数 fg:输出图像,处理后的结果会覆盖原图像 第三个参数 MorphTypes.Open:指定形态学操作类型为开运算 第四个参数 kernel:之前创建的5×5椭圆形结构元素 开运算(Opening Operation)是形态学处理中的一种基本操作,它由腐蚀(Erosion)后跟膨胀(Dilation)两个步骤组成:开运算 = 腐蚀 + 膨胀。 开运算的效果 去除小噪声:消除图像中的孤立白点(小噪声区域) 平滑轮廓:使物体轮廓更加平滑 断开细小连接:轻微分离可能连接在一起的不同物体 保持主要形状:不显著改变物体的大小和基本形状 我们需要大概了解一下腐蚀与膨胀是什么意思。 腐蚀: 膨胀: // 查找轮廓 OpenCvSharp.Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(fg, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple); 又接触到了一个新东西Cv2.FindContours(),这是OpenCV中查找轮廓的核心函数,用于在二值图像中检测物体边界。 参数详解 第一个参数 fg:输入的二值图像(经过形态学处理的前景掩码) 第二个参数 out contours:输出的轮廓数组 第三个参数 out hierarchy:输出的轮廓层次结构 第四个参数 RetrievalModes.External:轮廓检索模式 第五个参数 ContourApproximationModes.ApproxSimple:轮廓近似方法 轮廓检索模式 RetrievalModes.External含义:只检测最外层轮廓 适用场景:运动物体检测,因为我们只关心物体的外部边界 效果:忽略物体内部的孔洞 其他可选模式: RetrievalModes.External // 只检测外轮廓 RetrievalModes.List // 检测所有轮廓,不建立层次关系 RetrievalModes.CComp // 检测所有轮廓,建立两层层次关系 RetrievalModes.Tree // 检测所有轮廓,建立完整的层次树 轮廓近似方法 ContourApproximationModes.ApproxSimple含义:压缩水平、垂直、对角方向的元素,只保留端点 效果:减少轮廓点数,提高处理速度 适用场景:矩形或近似矩形的物体 其他可选方法: ContourApproximationModes.ApproxNone // 保存所有轮廓点 ContrieApproximationModes.ApproxSimple // 压缩轮廓,保留端点 ContourApproximationModes.ApproxTC89L1 // Teh-Chin链逼近算法L1 ContourApproximationModes.ApproxTC89KCOS // Teh-Chin链逼近算法KCOS // 绘制检测到的运动物体 foreach (var contour in contours) { double area = Cv2.ContourArea(contour); if (area > 300) // 过滤掉太小的区域 { currentFrameObjects++; var rect = Cv2.BoundingRect(contour); Cv2.Rectangle(frame, rect, Scalar.Red, 2); } } Cv2.ContourArea()计算轮廓包围的面积 Cv2.BoundingRect()计算轮廓的最小外接矩形 Cv2.Rectangle()绘制矩形 就这样处理每一帧就可以得到上面的效果了。