一、背景建模概述在计算机视觉领域背景建模是从视频序列中提取静态背景、分离动态前景的核心技术广泛应用于运动检测、目标跟踪、行为分析等场景。简单来说背景就是视频中相对稳定的部分如墙壁、地面前景则是运动的目标如行人、车辆。背景建模的目标就是构建一个可靠的背景模型将两者精准分离。二、三种主流背景建模方法1. 帧差法Frame Difference原理对连续两帧图像做差分运算计算像素灰度差的绝对值超过阈值则判定为运动目标。公式如下优缺点实现简单、计算速度快易受光照变化影响会产生噪声和空洞如目标内部出现黑色区域2. K 近邻背景建模KNN原理为每个像素维护一个历史样本集新像素值与样本集中的 K 个样本做距离比对若多数样本相似则判定为背景否则为前景。优缺点对光照变化和动态背景如树叶晃动有一定鲁棒性计算量较大内存占用较高3. 高斯混合模型MOG2原理用多个高斯分布来建模每个像素的颜色分布通过在线 EM 算法更新模型参数能自适应学习背景变化。优缺点鲁棒性强能处理复杂背景和光照渐变初始建模需要一定时间参数调优较复杂三、代码实现import cv2 import numpy as np # 测试视频路径 video_path test.avi # 初始化三种背景建模器 fgbg_mog2 cv2.createBackgroundSubtractorMOG2(history500, detectShadowsTrue) fgbg_knn cv2.createBackgroundSubtractorKNN(history500, detectShadowsTrue) # 卷积核用于形态学操作去噪 kernel cv2.getStructuringElement(cv2.MORPH_CROSS, ksize(3, 3)) cap cv2.VideoCapture(video_path) if not cap.isOpened(): print(视频打开失败) exit() while True: ret, frame cap.read() if not ret: break # ---------------------- 1. 帧差法 ---------------------- if prev_frame not in locals(): prev_frame frame.copy() continue frame_diff cv2.absdiff(frame, prev_frame) _, thresh_diff cv2.threshold(frame_diff, 30, 255, cv2.THRESH_BINARY) thresh_diff cv2.cvtColor(thresh_diff, cv2.COLOR_BGR2GRAY) thresh_diff cv2.morphologyEx(thresh_diff, cv2.MORPH_OPEN, kernel) prev_frame frame.copy() # ---------------------- 2. KNN 方法 ---------------------- fgmask_knn fgbg_knn.apply(frame) fgmask_knn cv2.morphologyEx(fgmask_knn, cv2.MORPH_OPEN, kernel) # ---------------------- 3. MOG2 方法 ---------------------- fgmask_mog2 fgbg_mog2.apply(frame) fgmask_mog2 cv2.morphologyEx(fgmask_mog2, cv2.MORPH_OPEN, kernel) # ---------------------- 轮廓检测与可视化 ---------------------- def draw_contours(img, mask): _, contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: perimeter cv2.arcLength(c, closedTrue) if perimeter 188: x, y, w, h cv2.boundingRect(c) cv2.rectangle(img, (x, y), (xw, yh), (0, 255, 0), 2) return img frame_diff_rect draw_contours(frame.copy(), thresh_diff) frame_knn_rect draw_contours(frame.copy(), fgmask_knn) frame_mog2_rect draw_contours(frame.copy(), fgmask_mog2) # ---------------------- 显示结果 ---------------------- cv2.imshow(Original Frame, frame) cv2.imshow(Frame Difference, frame_diff_rect) cv2.imshow(KNN Background Subtraction, frame_knn_rect) cv2.imshow(MOG2 Background Subtraction, frame_mog2_rect) k cv2.waitKey(30) 0xff if k 27: # ESC 退出 break cap.release() cv2.destroyAllWindows()四、代码讲解fgbg_mog2 cv2.createBackgroundSubtractorMOG2(history500, detectShadowsTrue) fgbg_knn cv2.createBackgroundSubtractorKNN(history500, detectShadowsTrue)初始化两种高级背景建模器MOG2混合高斯模型自适应背景、抗光照KNNK 近邻模型对动态背景树叶、水波更鲁棒history500表示用 500 帧学习背景detectShadowsTrue开启阴影检测。kernel cv2.getStructuringElement(cv2.MORPH_CROSS, ksize(3, 3))创建 3×3 十字形结构核用于后续开运算去噪消除小噪点让前景更干净。cap cv2.VideoCapture(video_path) if not cap.isOpened(): print(视频打开失败) exit()打开视频文件并判断是否成功打开失败则提示并退出避免程序崩溃。while True: ret, frame cap.read() if not ret: break循环读取视频每一帧。ret是否成功读到帧frame当前帧图像读到视频末尾自动退出循环。# 帧差法 if prev_frame not in locals(): prev_frame frame.copy() continue frame_diff cv2.absdiff(frame, prev_frame) _, thresh_diff cv2.threshold(frame_diff, 30, 255, cv2.THRESH_BINARY) thresh_diff cv2.cvtColor(thresh_diff, cv2.COLOR_BGR2GRAY) thresh_diff cv2.morphologyEx(thresh_diff, cv2.MORPH_OPEN, kernel) prev_frame frame.copy()实现帧差法最简单的运动检测保存上一帧计算当前帧与上一帧差值二值化分离前景背景转灰度图 开运算去噪更新上一帧# KNN fgmask_knn fgbg_knn.apply(frame) fgmask_knn cv2.morphologyEx(fgmask_knn, cv2.MORPH_OPEN, kernel)使用 KNN 背景建模得到前景掩码再通过形态学开运算去除小白点噪点。# MOG2 fgmask_mog2 fgbg_mog2.apply(frame) fgmask_mog2 cv2.morphologyEx(fgmask_mog2, cv2.MORPH_OPEN, kernel)使用 MOG2 混合高斯模型得到前景掩码同样做去噪处理。def draw_contours(img, mask): _, contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: perimeter cv2.arcLength(c, closedTrue) if perimeter 188: x, y, w, h cv2.boundingRect(c) cv2.rectangle(img, (x, y), (xw, yh), (0, 255, 0), 2) return img定义轮廓绘制函数寻找前景轮廓根据轮廓周长过滤小噪声只保留大于 188 的目标绘制绿色外接矩形标记运动目标frame_diff_rect draw_contours(frame.copy(), thresh_diff) frame_knn_rect draw_contours(frame.copy(), fgmask_knn) frame_mog2_rect draw_contours(frame.copy(), fgmask_mog2)分别对帧差法、KNN、MOG2三种结果绘制目标框。五、结果展示
OpenCV 背景建模实战:三种方法实现运动目标检测
发布时间:2026/6/30 16:38:39
一、背景建模概述在计算机视觉领域背景建模是从视频序列中提取静态背景、分离动态前景的核心技术广泛应用于运动检测、目标跟踪、行为分析等场景。简单来说背景就是视频中相对稳定的部分如墙壁、地面前景则是运动的目标如行人、车辆。背景建模的目标就是构建一个可靠的背景模型将两者精准分离。二、三种主流背景建模方法1. 帧差法Frame Difference原理对连续两帧图像做差分运算计算像素灰度差的绝对值超过阈值则判定为运动目标。公式如下优缺点实现简单、计算速度快易受光照变化影响会产生噪声和空洞如目标内部出现黑色区域2. K 近邻背景建模KNN原理为每个像素维护一个历史样本集新像素值与样本集中的 K 个样本做距离比对若多数样本相似则判定为背景否则为前景。优缺点对光照变化和动态背景如树叶晃动有一定鲁棒性计算量较大内存占用较高3. 高斯混合模型MOG2原理用多个高斯分布来建模每个像素的颜色分布通过在线 EM 算法更新模型参数能自适应学习背景变化。优缺点鲁棒性强能处理复杂背景和光照渐变初始建模需要一定时间参数调优较复杂三、代码实现import cv2 import numpy as np # 测试视频路径 video_path test.avi # 初始化三种背景建模器 fgbg_mog2 cv2.createBackgroundSubtractorMOG2(history500, detectShadowsTrue) fgbg_knn cv2.createBackgroundSubtractorKNN(history500, detectShadowsTrue) # 卷积核用于形态学操作去噪 kernel cv2.getStructuringElement(cv2.MORPH_CROSS, ksize(3, 3)) cap cv2.VideoCapture(video_path) if not cap.isOpened(): print(视频打开失败) exit() while True: ret, frame cap.read() if not ret: break # ---------------------- 1. 帧差法 ---------------------- if prev_frame not in locals(): prev_frame frame.copy() continue frame_diff cv2.absdiff(frame, prev_frame) _, thresh_diff cv2.threshold(frame_diff, 30, 255, cv2.THRESH_BINARY) thresh_diff cv2.cvtColor(thresh_diff, cv2.COLOR_BGR2GRAY) thresh_diff cv2.morphologyEx(thresh_diff, cv2.MORPH_OPEN, kernel) prev_frame frame.copy() # ---------------------- 2. KNN 方法 ---------------------- fgmask_knn fgbg_knn.apply(frame) fgmask_knn cv2.morphologyEx(fgmask_knn, cv2.MORPH_OPEN, kernel) # ---------------------- 3. MOG2 方法 ---------------------- fgmask_mog2 fgbg_mog2.apply(frame) fgmask_mog2 cv2.morphologyEx(fgmask_mog2, cv2.MORPH_OPEN, kernel) # ---------------------- 轮廓检测与可视化 ---------------------- def draw_contours(img, mask): _, contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: perimeter cv2.arcLength(c, closedTrue) if perimeter 188: x, y, w, h cv2.boundingRect(c) cv2.rectangle(img, (x, y), (xw, yh), (0, 255, 0), 2) return img frame_diff_rect draw_contours(frame.copy(), thresh_diff) frame_knn_rect draw_contours(frame.copy(), fgmask_knn) frame_mog2_rect draw_contours(frame.copy(), fgmask_mog2) # ---------------------- 显示结果 ---------------------- cv2.imshow(Original Frame, frame) cv2.imshow(Frame Difference, frame_diff_rect) cv2.imshow(KNN Background Subtraction, frame_knn_rect) cv2.imshow(MOG2 Background Subtraction, frame_mog2_rect) k cv2.waitKey(30) 0xff if k 27: # ESC 退出 break cap.release() cv2.destroyAllWindows()四、代码讲解fgbg_mog2 cv2.createBackgroundSubtractorMOG2(history500, detectShadowsTrue) fgbg_knn cv2.createBackgroundSubtractorKNN(history500, detectShadowsTrue)初始化两种高级背景建模器MOG2混合高斯模型自适应背景、抗光照KNNK 近邻模型对动态背景树叶、水波更鲁棒history500表示用 500 帧学习背景detectShadowsTrue开启阴影检测。kernel cv2.getStructuringElement(cv2.MORPH_CROSS, ksize(3, 3))创建 3×3 十字形结构核用于后续开运算去噪消除小噪点让前景更干净。cap cv2.VideoCapture(video_path) if not cap.isOpened(): print(视频打开失败) exit()打开视频文件并判断是否成功打开失败则提示并退出避免程序崩溃。while True: ret, frame cap.read() if not ret: break循环读取视频每一帧。ret是否成功读到帧frame当前帧图像读到视频末尾自动退出循环。# 帧差法 if prev_frame not in locals(): prev_frame frame.copy() continue frame_diff cv2.absdiff(frame, prev_frame) _, thresh_diff cv2.threshold(frame_diff, 30, 255, cv2.THRESH_BINARY) thresh_diff cv2.cvtColor(thresh_diff, cv2.COLOR_BGR2GRAY) thresh_diff cv2.morphologyEx(thresh_diff, cv2.MORPH_OPEN, kernel) prev_frame frame.copy()实现帧差法最简单的运动检测保存上一帧计算当前帧与上一帧差值二值化分离前景背景转灰度图 开运算去噪更新上一帧# KNN fgmask_knn fgbg_knn.apply(frame) fgmask_knn cv2.morphologyEx(fgmask_knn, cv2.MORPH_OPEN, kernel)使用 KNN 背景建模得到前景掩码再通过形态学开运算去除小白点噪点。# MOG2 fgmask_mog2 fgbg_mog2.apply(frame) fgmask_mog2 cv2.morphologyEx(fgmask_mog2, cv2.MORPH_OPEN, kernel)使用 MOG2 混合高斯模型得到前景掩码同样做去噪处理。def draw_contours(img, mask): _, contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: perimeter cv2.arcLength(c, closedTrue) if perimeter 188: x, y, w, h cv2.boundingRect(c) cv2.rectangle(img, (x, y), (xw, yh), (0, 255, 0), 2) return img定义轮廓绘制函数寻找前景轮廓根据轮廓周长过滤小噪声只保留大于 188 的目标绘制绿色外接矩形标记运动目标frame_diff_rect draw_contours(frame.copy(), thresh_diff) frame_knn_rect draw_contours(frame.copy(), fgmask_knn) frame_mog2_rect draw_contours(frame.copy(), fgmask_mog2)分别对帧差法、KNN、MOG2三种结果绘制目标框。五、结果展示