文章目录
完整代码一览
c
import cv2
cap = cv2.VideoCapture('test.avi')
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
fgbg = cv2.createBackgroundSubtractorMOG2()
while True:
ret, fream = cap.read()
if not ret:
break
cv2.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]
for c in contours:
perimeter = cv2.arcLength(c, True)
if perimeter > 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)
if k == 27: # ESC 键退出
break
cap.release()
cv2.destroyAllWindows()
打开视频与定义内核
c
import cv2
cap = cv2.VideoCapture('test.avi')
cv2.VideoCapture:创建一个视频捕获对象,参数可以是视频文件路径或摄像头设备号(0 表示默认摄像头)。这里指定了 'test.avi',表示读取本地视频文件。

定义结构内核
c
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
定义了一个 十字形结构内核,尺寸为 3×3。这个内核将用于形态学操作(开运算)。十字形结构适合处理细长的噪声或连接断裂的前景区域。
创造背景减除器
c
fgbg = cv2.createBackgroundSubtractorMOG2()
创建一个 MOG2 背景减除器。MOG2 是基于高斯混合模型的背景建模算法,它能自动学习背景,并且能区分阴影(通过阴影检测参数)。我们使用默认参数即可。
视频逐帧处理
读取帧
c
while True:
ret, fream = cap.read()
if not ret:
break
cv2.imshow('fream', fream)
#无限循环不断读取视频的下一帧。
cap.read() 返回两个值:ret 表示是否成功读取(布尔值),fream 是当前帧图像(注意变量名拼写错误,但无影响)。
如果 ret 为 False,说明视频已读完或读取失败,则跳出循环,同时显示原始帧,方便观察视频内容。
前景掩码
c
fgmask = fgbg.apply(fream)
cv2.imshow('famask', fgmask)
fgbg.apply(fream) 将当前帧输入到背景减除器中,返回一个二值图像 fgmask:白色(255)区域表示前景(运动物体),黑色(0)区域表示背景。
显示这个前景掩码,你会看到运动目标呈白色块状,但往往会有很多噪点(小白色斑点)和内部空洞。
运行结果:

去除噪声,分离目标
c
fgmask_new = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
cv2.imshow('famask1', fgmask_new)
cv2.morphologyEx 执行形态学操作,这里用的是 开运算(MORPH_OPEN),即先腐蚀后膨胀。
开运算的效果:去除细小的白色噪点(相当于"擦掉"孤立的小白点),同时断开黏连在一起的大块目标(如果两个物体靠得太近,开运算能稍微分开它们)。
使用我们之前定义的 3×3 十字内核,强度适中,不会过度破坏目标轮廓。处理后,前景掩码会更干净,噪声减少。
运行结果:

轮廓检测与过滤
c
contours = cv2.findContours(fgmask_new, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
for c in contours:
perimeter = cv2.arcLength(c, True)
if perimeter > 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。
显示结果与退出控制
c
cv2.imshow('fgmask_new_rect', fgmask_new_rect)
k = cv2.waitKey(60)
if k == 27:
break
显示绘制了矩形框的帧。
运行结果:

释放资源
c
cap.release()
cv2.destroyAllWindows()
释放视频捕获资源,关闭所有 OpenCV 窗口。
调优建议
关键参数调优:
周长阈值 188:需要根据视频中目标的大小调整。如果目标较小,可降低阈值;如果背景噪声多,可提高阈值。
内核尺寸:3×3 适合小目标,若目标大或噪声多,可增大内核(如 5×5)增强去噪效果。
形态学操作:开运算适合去除噪声,如果前景内部空洞多,可改用闭运算(先膨胀后腐蚀)填充空洞。
等待时间 waitKey:数值越大,播放越慢;若设为 1,则播放尽可能快。
如果视频没有运动物体,前景掩码将是全黑,矩形框也不会出现。