OpenCVSharp:使用MOG进行运动物体识别

效果

动态效果:

实现

运动物体检测是计算机视觉中的一个重要应用,广泛应用于安防监控、交通分析、人机交互等领域。本文将详细介绍如何使用OpenCVSharp中的MOG(Mixture of Gaussians)算法实现运动物体检测,并通过一个完整的WPF应用程序示例展示实际应用。

什么是MOG算法?

MOG(Mixture of Gaussians,高斯混合模型)是一种基于背景建模的运动检测算法。它通过对每个像素建立多个高斯分布模型来表示背景,能够有效处理光照变化、树叶摇曳等动态背景干扰。

MOG算法原理

背景建模:为每个像素建立K个高斯分布模型

模型匹配:将当前像素值与已有模型进行匹配

模型更新:根据匹配结果更新模型参数

前景检测:不匹配任何背景模型的像素被标记为前景

ViewModel设计

我们使用MVVM模式设计应用程序,主要包含以下属性和命令:

csharp 复制代码
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的哪些方法。

csharp 复制代码
 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);

首先可以这样获取视频的一些信息:

csharp 复制代码
      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。这行代码是创建一个形态学操作的结构元素(也称为核或卷积核),用于图像处理中的形态学变换。

csharp 复制代码
     Cv2.MorphologyEx(fg, fg, MorphTypes.Open, kernel);

这是OpenCVSharp中执行高级形态学操作的函数,支持多种形态学变换类型。

参数说明

第一个参数 fg:输入图像,即经过MOG背景减除后的前景掩码

第二个参数 fg:输出图像,处理后的结果会覆盖原图像

第三个参数 MorphTypes.Open:指定形态学操作类型为开运算

第四个参数 kernel:之前创建的5×5椭圆形结构元素

开运算(Opening Operation)是形态学处理中的一种基本操作,它由**腐蚀(Erosion)后跟膨胀(Dilation)**两个步骤组成:开运算 = 腐蚀 + 膨胀。

开运算的效果

去除小噪声:消除图像中的孤立白点(小噪声区域)

平滑轮廓:使物体轮廓更加平滑

断开细小连接:轻微分离可能连接在一起的不同物体

保持主要形状:不显著改变物体的大小和基本形状

我们需要大概了解一下腐蚀与膨胀是什么意思。

腐蚀:

膨胀:

csharp 复制代码
// 查找轮廓
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含义:只检测最外层轮廓

适用场景:运动物体检测,因为我们只关心物体的外部边界

效果:忽略物体内部的孔洞

其他可选模式:

csharp 复制代码
RetrievalModes.External    // 只检测外轮廓
RetrievalModes.List        // 检测所有轮廓,不建立层次关系
RetrievalModes.CComp       // 检测所有轮廓,建立两层层次关系
RetrievalModes.Tree        // 检测所有轮廓,建立完整的层次树

轮廓近似方法

ContourApproximationModes.ApproxSimple含义:压缩水平、垂直、对角方向的元素,只保留端点

效果:减少轮廓点数,提高处理速度

适用场景:矩形或近似矩形的物体

其他可选方法:

csharp 复制代码
ContourApproximationModes.ApproxNone    // 保存所有轮廓点
ContrieApproximationModes.ApproxSimple  // 压缩轮廓,保留端点
ContourApproximationModes.ApproxTC89L1  // Teh-Chin链逼近算法L1
ContourApproximationModes.ApproxTC89KCOS // Teh-Chin链逼近算法KCOS
csharp 复制代码
// 绘制检测到的运动物体
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()绘制矩形

就这样处理每一帧就可以得到上面的效果了。