一、背景建模是是什么
指在计算机视觉中,从视频序列中提取出静态背景的一种技术。在视频中,背景通常被定义为相对稳定的部分,例如墙壁、地面或天空等。
背景建模的目标是将动态的前景对象与静态的背景进行分离,以便进一步分析和处理。
二、背景建模的目的
通过背景建模,我们可以实现很多应用,例如运动检测、目标跟踪
三、背景建模的方法
1、帧差法backgroundSubtractor
2、基于K近邻的背景/前景分割算法BackgroundSubtractorKNN
3、基于高斯混合的背景/前景分割算法BackgroundSubtractorMOG2
帧差法的原理
由于场景中的目标在运动,目标的影像在不同图像帧中的位置不同。该类算法对时间上连续的两帧图像进行差分运算,不同帧对应的像素点相减,判断灰度差的绝对值,当绝对值超过一定阈值时,即可判断为运动目标,从而实现目标的检测功能。

帧差法的优缺点
帧差法非常简单,但是会引入噪音和空洞(人物中间是黑色的)问题
四、核心技术原理
1、混合高斯模型(MOG2):背景建模与前景提取
视频由一帧帧连续的图像组成,运动目标检测的本质是区分 "静止背景" 和 "运动前景"。
混合高斯模型(Gaussian Mixture Model, GMM)是实现这一目标的经典算法,OpenCV 封装的createBackgroundSubtractorMOG2是其优化版本,核心优势如下:
-
自适应背景更新:能自动学习并更新背景模型,适应光线变化、背景轻微扰动(如树叶晃动)等场景;
-
前景掩码输出:处理后会生成一张黑白掩码图(前景掩码),白色区域代表运动目标,黑色区域代表背景;
-
无需手动标注:无需提前采集背景帧,可直接对视频流进行实时处理。
2、形态学开运算:去除噪点干扰
通过 MOG2 提取的前景掩码通常会包含大量细小噪点(如光线突变、视频压缩噪声),这些噪点会干扰后续的轮廓检测。形态学开运算(先腐蚀后膨胀)能有效解决这个问题:
-
腐蚀:消除小的亮区域(噪点),收缩前景目标的边界;
-
膨胀:恢复前景目标的原始大小,弥补腐蚀造成的边界收缩;
-
组合效果:保留大面积的运动目标,去除零散的小噪点,让前景轮廓更规整。
3、轮廓检测与筛选:精准定位运动目标
在处理后的前景掩码基础上,通过轮廓检测找到所有连通的前景区域,再通过轮廓周长 / 面积筛选,排除小的无效区域,最终用矩形框标出真正的运动目标,实现 "检测 - 定位" 一体化
五、完整代码与解析
python
import cv2
# 1. 读取测试视频文件(替换为你的视频路径)
cap = cv2.VideoCapture(r"E:\xwechat_files\wxid_qi43v1w2nqcb12_e432\msg\file\2026-01\test(1).avi")
# 2. 创建形态学运算卷积核(十字形,3x3)
# MORPH_CROSS:十字形核,适合保留目标的边缘特征;ksize=(3,3):核大小,越小越精细
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, ksize=(3, 3))
# 3. 初始化混合高斯背景建模器
# createBackgroundSubtractorMOG2:默认参数已适配大多数场景,可添加detectShadows=False去除阴影检测
fgbg = cv2.createBackgroundSubtractorMOG2()
# 4. 循环处理视频每一帧
while True:
# 读取当前帧:ret为布尔值(是否读取成功),frame为帧图像(BGR格式)
ret, frame = cap.read()
if not ret: # 读取失败(如视频结束),退出循环
break
# 显示原始视频帧
cv2.imshow('Original Frame', frame)
# 5. 应用背景建模,提取前景掩码
# fgmask:8位灰度图,白色(255)为前景(运动目标),黑色(0)为背景
fgmask = fgbg.apply(frame)
cv2.imshow('Foreground Mask (Raw)', fgmask)
# 6. 形态学开运算:去除噪点,优化前景掩码
# MORPH_OPEN:开运算(腐蚀→膨胀),消除小噪点,保留大的运动区域
fgmask_new = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
cv2.imshow('Foreground Mask (Processed)', fgmask_new)
# 7. 轮廓检测:查找前景掩码中的所有轮廓
# RETR_EXTERNAL:只检索最外层轮廓,减少计算量;CHAIN_APPROX_SIMPLE:压缩轮廓点,节省内存
contours, hierarchy = cv2.findContours(fgmask_new, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 8. 遍历轮廓,筛选并绘制运动目标矩形框
for c in contours:
# 计算轮廓周长,用于筛选小的无效区域
perimeter = cv2.arcLength(c, closed=True)
# 周长阈值(188):可根据视频分辨率/目标大小调整,过滤小噪点轮廓
if perimeter > 188:
# 计算轮廓的外接矩形:x(左)、y(上)、w(宽)、h(高)
x, y, w, h = cv2.boundingRect(c)
# 在原始帧上绘制绿色矩形框(BGR格式:(0,255,0))
cv2.rectangle(frame, pt1=(x, y), pt2=(x + w, y + h), color=(0, 255, 0), thickness=2)
# 显示绘制了目标框的视频帧
cv2.imshow('Motion Detection Result', frame)
# 9. 按键控制:等待60ms,按ESC键(27)退出
k = cv2.waitKey(60) & 0xFF # 0xFF解决跨平台按键兼容问题
if k == 27:
break
# 10. 释放资源:关闭视频流,销毁所有窗口
cap.release()
cv2.destroyAllWindows()
形态学卷积核创建:
python
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, ksize=(3, 3))
-
cv2.MORPH_CROSS:十字形卷积核,相比矩形核,能更好地保留目标的边缘细节,适合细长型运动目标(如行人、车辆); -
ksize=(3,3):核的大小为 3×3,是平衡去噪效果和计算效率的常用值;若噪点较多,可改为(5,5),但会增加计算量。
混合高斯模型初始化
python
fgbg = cv2.createBackgroundSubtractorMOG2()
该函数默认开启阴影检测(detectShadows=True),阴影区域会显示为灰色(值为 127),若不需要检测阴影,可改为:
python
fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows=False)
前景掩码提取与优化
python
fgmask = fgbg.apply(frame)
fgmask_new = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
-
fgbg.apply(frame):对当前帧进行背景建模,输出的fgmask是灰度图,白色区域为运动目标; -
cv2.morphologyEx(..., cv2.MORPH_OPEN, kernel):开运算先腐蚀后膨胀,核心作用是 "去小留大"------ 消除面积小于卷积核的噪点,同时不改变大目标的整体形状。
轮廓检测与筛选
python
contours, hierarchy = cv2.findContours(fgmask_new, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
perimeter = cv2.arcLength(c, closed=True)
if perimeter > 188:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0), 2)
-
cv2.findContours:返回所有轮廓的列表,每个轮廓是一组点的坐标; -
cv2.arcLength(c, True):计算轮廓的闭合周长,阈值188是经验值 ------ 需根据视频分辨率调整(如 720P 视频可设为 100,4K 视频可设为 300); -
cv2.boundingRect(c):为每个符合条件的轮廓生成最小外接矩形,用cv2.rectangle绘制在原始帧上,实现目标可视化。
运行结果
运行代码,会弹出 4 个窗口:
Original Frame:原始视频帧;
Foreground Mask (Raw):MOG2 提取的原始前景掩码(含噪点);
Foreground Mask (Processed):开运算处理后的前景掩码(无噪点);
Motion Detection Result:绘制了绿色矩形框的最终检测结果;
