【深度学习】OpenCV 视频分析实战:背景建模 + 形态学处理实现运动目标检测

文章目录

  • 完整代码一览
  • 打开视频与定义内核
  • 定义结构内核
  • 创造背景减除器
  • 视频逐帧处理
    • 读取帧
    • 前景掩码
  • 去除噪声,分离目标
  • 轮廓检测与过滤
  • 显示结果与退出控制
  • 释放资源
  • 调优建议

完整代码一览

import cv2 cap=cv2.VideoCapture('test.avi')kernel=cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))fgbg=cv2.createBackgroundSubtractorMOG2()whileTrue:ret,fream=cap.read()ifnot ret:breakcv2.imshow('fream',fream)fgmask=fgbg.apply(fream)cv2.imshow('famask',fgmask)fgmask_new=cv2.morphologyEx(fgmask,cv2.MORPH_OPEN,kernel)cv2.imshow('famask1',fgmask_new)contours=cv2.findContours(fgmask_new,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]forc in contours:perimeter=cv2.arcLength(c,True)ifperimeter>188:x,y,w,h=cv2.boundingRect(c)fgmask_new_rect=cv2.rectangle(fream,(x,y),(x+w,y+h),(0,0,255),2)cv2.imshow('fgmask_new_rect',fgmask_new_rect)k=cv2.waitKey(60)ifk==27:# ESC 键退出breakcap.release()cv2.destroyAllWindows()

打开视频与定义内核

import cv2 cap=cv2.VideoCapture('test.avi')

cv2.VideoCapture:创建一个视频捕获对象,参数可以是视频文件路径或摄像头设备号(0 表示默认摄像头)。这里指定了 ‘test.avi’,表示读取本地视频文件。

定义结构内核

kernel=cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))

定义了一个 十字形结构内核,尺寸为 3×3。这个内核将用于形态学操作(开运算)。十字形结构适合处理细长的噪声或连接断裂的前景区域。

创造背景减除器

fgbg=cv2.createBackgroundSubtractorMOG2()

创建一个 MOG2 背景减除器。MOG2 是基于高斯混合模型的背景建模算法,它能自动学习背景,并且能区分阴影(通过阴影检测参数)。我们使用默认参数即可。

视频逐帧处理

读取帧

whileTrue:ret,fream=cap.read()ifnot ret:breakcv2.imshow('fream',fream)#无限循环不断读取视频的下一帧。

cap.read() 返回两个值:ret 表示是否成功读取(布尔值),fream 是当前帧图像(注意变量名拼写错误,但无影响)。

如果 ret 为 False,说明视频已读完或读取失败,则跳出循环,同时显示原始帧,方便观察视频内容。

前景掩码

fgmask=fgbg.apply(fream)cv2.imshow('famask',fgmask)

fgbg.apply(fream) 将当前帧输入到背景减除器中,返回一个二值图像 fgmask:白色(255)区域表示前景(运动物体),黑色(0)区域表示背景。
显示这个前景掩码,你会看到运动目标呈白色块状,但往往会有很多噪点(小白色斑点)和内部空洞。
运行结果:

去除噪声,分离目标

fgmask_new=cv2.morphologyEx(fgmask,cv2.MORPH_OPEN,kernel)cv2.imshow('famask1',fgmask_new)

cv2.morphologyEx 执行形态学操作,这里用的是 开运算(MORPH_OPEN),即先腐蚀后膨胀。
开运算的效果:去除细小的白色噪点(相当于“擦掉”孤立的小白点),同时断开黏连在一起的大块目标(如果两个物体靠得太近,开运算能稍微分开它们)。

使用我们之前定义的 3×3 十字内核,强度适中,不会过度破坏目标轮廓。处理后,前景掩码会更干净,噪声减少。
运行结果:

轮廓检测与过滤

contours=cv2.findContours(fgmask_new,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]forc in contours:perimeter=cv2.arcLength(c,True)ifperimeter>188:x,y,w,h=cv2.boundingRect(c)fgmask_new_rect=cv2.rectangle(fream,(x,y),(x+w,y+h),(0,0,255),2)

cv2.findContours 在去噪后的前景掩码上查找轮廓。RETR_EXTERNAL 只检测最外层轮廓,CHAIN_APPROX_SIMPLE 压缩轮廓点以节省内存。

遍历每个轮廓 c:

cv2.arcLength(c, True) 计算轮廓的周长(闭合)。如果周长 大于 188,则认为这个目标足够大(过滤掉小噪点),然后:
cv2.boundingRect© 获取外接矩形的左上角坐标 (x,y) 和宽高 (w,h)。

cv2.rectangle 在原图 fream 上绘制红色矩形框,线宽 2。

显示结果与退出控制

cv2.imshow('fgmask_new_rect',fgmask_new_rect)k=cv2.waitKey(60)ifk==27:break

显示绘制了矩形框的帧。

运行结果:

释放资源

cap.release()cv2.destroyAllWindows()

释放视频捕获资源,关闭所有 OpenCV 窗口。

调优建议

关键参数调优:

周长阈值 188:需要根据视频中目标的大小调整。如果目标较小,可降低阈值;如果背景噪声多,可提高阈值。

内核尺寸:3×3 适合小目标,若目标大或噪声多,可增大内核(如 5×5)增强去噪效果。

形态学操作:开运算适合去除噪声,如果前景内部空洞多,可改用闭运算(先膨胀后腐蚀)填充空洞。

等待时间 waitKey:数值越大,播放越慢;若设为 1,则播放尽可能快。
如果视频没有运动物体,前景掩码将是全黑,矩形框也不会出现。