【OpenCV 入门到精通 10】视频分析与光流跟踪:背景减除与运动检测

【OpenCV 入门到精通 10】视频分析与光流跟踪:背景减除与运动检测

标签 :OpenCV 背景减除 光流 Meanshift Camshift 运动检测

难度 :⭐⭐⭐ | 阅读时长 :约 65 分钟 | 系列 :第 10/12 集

前置 :09 特征检测 | 下一集 :11 机器学习


写在前面

监控画面怎么检测移动的人?无人机怎么跟踪目标?本集讲解 背景减除 、Meanshift/Camshift 跟踪 和 光流法 ,对应官方 第6章 视频分析。


本集学习目标

  • 使用 MOG2/KNN 进行背景减除
  • 掌握 Meanshift 和 Camshift 目标跟踪
  • 理解稠密光流和稀疏光流
  • 完成运动检测实战

文章目录

  • [【OpenCV 入门到精通 10】视频分析与光流跟踪:背景减除与运动检测](#【OpenCV 入门到精通 10】视频分析与光流跟踪:背景减除与运动检测)
    • 写在前面
    • 本集学习目标
    • [10.1 背景减除](#10.1 背景减除)
    • [10.2 Meanshift 跟踪](#10.2 Meanshift 跟踪)
    • [10.3 Camshift 跟踪](#10.3 Camshift 跟踪)
    • [10.4 光流法](#10.4 光流法)
      • [稀疏光流 Lucas-Kanade](#稀疏光流 Lucas-Kanade)
      • [稠密光流 Farneback](#稠密光流 Farneback)
    • [10.5 综合实战:运动检测](#10.5 综合实战:运动检测)
    • [10.6 踩坑指南](#10.6 踩坑指南)
    • [10.7 本集小结](#10.7 本集小结)

10.1 背景减除

从视频中分离运动前景:

python 复制代码
import cv2

cap = cv2.VideoCapture("traffic.mp4")

# MOG2 背景减除器
fgbg = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True)

while True:
    ret, frame = cap.read()
    if not ret: break

    fgmask = fgbg.apply(frame)

    # 去阴影(MOG2 阴影值为 127)
    _, fgmask = cv2.threshold(fgmask, 200, 255, cv2.THRESH_BINARY)

    cv2.imshow("Frame", frame)
    cv2.imshow("FG Mask", fgmask)
    if cv2.waitKey(30) & 0xFF == ord('q'): break

cap.release()
cv2.destroyAllWindows()
算法 特点
MOG2 最常用,支持阴影检测
KNN 对噪声更鲁棒
GMG 需较长初始化

10.2 Meanshift 跟踪

在指定区域内找颜色直方图最匹配的位置:

python 复制代码
import cv2

cap = cv2.VideoCapture("slow_traffic.mp4")
ret, frame = cap.read()

# 手动选择 ROI
r, h, c, w = cv2.selectROI("Frame", frame, False)
track_window = (c, r, w, h)
roi = frame[r:r+h, c:c+w]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
roi_hist = cv2.calcHist([hsv_roi], [0], None, [180], [0, 180])
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)

term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)

while True:
    ret, frame = cap.read()
    if not ret: break
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
    ret, track_window = cv2.meanShift(dst, track_window, term_crit)
    x, y, w, h = track_window
    cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0), 2)
    cv2.imshow("Meanshift", frame)
    if cv2.waitKey(30) & 0xFF == ord('q'): break

10.3 Camshift 跟踪

Meanshift 的改进版,窗口大小和角度可自适应:

python 复制代码
ret, track_window = cv2.CamShift(dst, track_window, term_crit)
pts = cv2.boxPoints(ret)
pts = np.int32(pts)
cv2.polylines(frame, [pts], True, (0, 255, 0), 2)
对比 Meanshift Camshift
窗口 固定大小 自适应大小+角度
适用 大小不变的目标 远近变化的目标

10.4 光流法

跟踪像素在两帧间的运动。

稀疏光流 Lucas-Kanade

python 复制代码
import cv2
import numpy as np

cap = cv2.VideoCapture("slow_traffic.mp4")
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

# Shi-Tomasi 角点
feature_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)

lk_params = dict(winSize=(15,15), maxLevel=2,
                 criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

mask = np.zeros_like(old_frame)

while True:
    ret, frame = cap.read()
    if not ret: break
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)

    good_new = p1[st == 1]
    good_old = p0[st == 1]

    for i, (new, old) in enumerate(zip(good_new, good_old)):
        a, b = new.ravel()
        c, d = old.ravel()
        mask = cv2.line(mask, (int(a),int(b)), (int(c),int(d)), (0,255,0), 2)
        frame = cv2.circle(frame, (int(a),int(b)), 5, (0,0,255), -1)

    img = cv2.add(frame, mask)
    cv2.imshow("Optical Flow", img)
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1, 1, 2)
    if cv2.waitKey(30) & 0xFF == ord('q'): break

稠密光流 Farneback

python 复制代码
flow = cv2.calcOpticalFlowFarneback(prev_gray, gray, None,
    pyr_scale=0.5, levels=3, winsize=15, iterations=3,
    poly_n=5, poly_sigma=1.2, flags=0)

# 可视化
magnitude, angle = cv2.cartToPolar(flow[...,0], flow[...,1])
hsv = np.zeros((h,w,3), dtype=np.uint8)
hsv[...,0] = angle * 180 / np.pi / 2
hsv[...,2] = cv2.normalize(magnitude, None, 0, 255, cv2.NORM_MINMAX)
rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
方法 类型 特点
calcOpticalFlowPyrLK 稀疏 跟踪特征点,快
calcOpticalFlowFarneback 稠密 每像素运动,慢

10.5 综合实战:运动检测

python 复制代码
import cv2

cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows=False)

while True:
    ret, frame = cap.read()
    if not ret: break

    fgmask = fgbg.apply(frame)
    # 形态学去噪
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
    fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)

    # 找轮廓
    contours, _ = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contours:
        if cv2.contourArea(cnt) < 500: continue
        x, y, w, h = cv2.boundingRect(cnt)
        cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0), 2)

    cv2.imshow("Motion Detection", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'): break
cap.release()
cv2.destroyAllWindows()

10.6 踩坑指南

坑 解决
背景减除前景太多 调高 varThreshold;等待背景学习
Meanshift 跟丢 目标颜色与背景太接近
光流点消失 特征点被遮挡,重新检测
摄像头背景减除慢 前几秒是背景学习期

10.7 本集小结

技术 API 场景
背景减除 createBackgroundSubtractorMOG2 运动检测
Meanshift meanShift 颜色跟踪
Camshift CamShift 自适应跟踪
稀疏光流 calcOpticalFlowPyrLK 特征点跟踪
稠密光流 calcOpticalFlowFarneback 运动场可视化

← 第09集 第11集:机器学习 →

参考:6_1 背景分离 | 6_2 Meanshift | 6_3 光流

相关推荐
黑妹天下第一乖14 小时前
小智改造实战解读-首 token 延迟去哪了:云端与端侧大模型的分段对照
开发语言·人工智能·python·嵌入式硬件·自然语言处理·iot
布吉岛的石头14 小时前
AI代做PPT报价:50元档和300元档差在哪
人工智能·副业·办公·兼职·ppt代做
数字游民952714 小时前
自由职业和探索AI的这两年时间,分享我的真实经历和感受
人工智能
坊钰14 小时前
【LangChain框架入门级】10. 文本向量与向量数据库(Embedding / Redis / Pinecone / MMR)
数据库·python·langchain·embedding
User_芊芊君子14 小时前
第十五届中国创新创业大赛
人工智能
向哆哆14 小时前
农场畜牧目标检测数据集:5类别、15,000张图像 | 目标检测
人工智能·目标检测·目标跟踪
Info X Med医学之家15 小时前
成纤维细胞与肌成纤维细胞活化在组织修复和纤维化中的作用 | Info X Med 深度文献解读
人工智能·医学文献·info x med·医生
甲维斯15 小时前
太吓人了!VibeCoding写的Bug空烧10000美金!
人工智能
benchmark_cc15 小时前
本地已有一年历史 K 线,第二天更新别只拉“昨天一天”
python·数据分析·pandas·量化交易·股票数据·quantdash
匠测AI说15 小时前
AI for Testing 提效实战·测试设计(四):我拿一个真实需求,让 AI 陪我走完了整个测试设计(全程复盘)
人工智能·测试