5.2 运动分析


5.2 运动分析

本节摘要:运动分析回答"画面里什么在动、动了多少、往哪动"。三套方案各有地盘:帧间差分最简单,适合触发告警;背景减除(MOG2、KNN)建背景模型分离前景,是运动目标提取的主力;光流给出逐像素/逐点的运动方向。本节跑通三者的最小实现,讲清背景模型的更新机制与阴影抑制,并给出选型路线。

从项目需求看本节目标

阅读完本节,你应当能够:

  1. 用 absdiff 加阈值实现帧间差分运动检测
  2. 用 createBackgroundSubtractorMOG2 实时提取前景掩码并调参
  3. 解释背景模型的"学习率"与阴影检测参数的作用
  4. 用稀疏光流跟踪角点并可视化运动方向
  5. 按场景在三种方案中做出选择并组合成完整方案

先跑起来:三种运动检测的最小实现

帧间差分——两帧相减,动的区域亮,静的区域黑:

import cv2 prev = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY) curr = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY) diff = cv2.absdiff(prev, curr) _, mask = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)

mask 里白色的地方就是两帧之间发生变化的区域。25 这个阈值过滤掉轻微的传感器噪声(第 2 章第 4 节的固定阈值在此复用)。

背景减除——建一个"背景模型",每帧与模型比对:

backsub = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True) mask = backsub.apply(frame) # 每帧调用,模型自动更新 mask = cv2.threshold(mask, 200, 255, cv2.THRESH_BINARY)[1] # 阴影127前景255

光流——给一组点,看它们下一帧跑到哪:

p0 = cv2.goodFeaturesToTrack(prev_gray, 100, 0.1, 7) p1, st, err = cv2.calcOpticalFlowPyrLK(prev_gray, curr_gray, p0, None) good = p1[st == 1] # st=1 表示成功跟踪

三段代码对应三个层次的问题:差分答"变了吗"、背景减除答"哪些像素属于运动物体"、光流答"往哪个方向、多快"。

核心原理:背景、差分与运动场

2.1 帧间差分:最快但最粗

相邻两帧相减,逻辑简单到不需要模型。优点:零训练、零状态、计算极便宜,对光照突变的鲁棒性意外地好(变化是相对的)。缺点有三个:目标运动慢时与背景几乎重合,差分"看不见"慢慢挪动的目标;提取的掩码是"运动扫过的区域",目标内部纹理均匀处是空洞,轮廓不完整;只知道"变了",不知道是目标进来还是背景被遮挡。

定位就是轻量触发器:门口有人经过触发抓拍、画面异常触发告警,够用且几乎不占算力。

2.2 背景减除:给每个像素建档案

思路:统计每个像素在时间轴上的取值分布,多数时间是"背景态";新帧里明显偏离档案的像素判为前景。均值背景是最朴素的版本(本章开头的思路),但树叶晃动、水面波光这类"背景本身在抖"的场景,单一均值无法描述。

MOG2 的解法是混合高斯模型:每个像素的档案不是一条数,而是 3 到 5 个高斯分布的混合——多数时间匹配到的分布算背景,偶尔出现的另一套分布(比如摇晃的树叶)也纳入档案。新帧来了,匹配任何背景分布则判背景,全不匹配则判前景。KNN 是近年加入的方案,用最近邻思路做同样的事,对复杂纹理背景常更稳。

两个关键参数:history 是"档案统计多长时间",值越大背景越保守(适应光照渐变慢),500 是常规起点;varThreshold 是"偏离多少算可疑",噪声大调大,远处小目标检测不出时调小。detectShadows 开启后阴影被标成 127(前景是 255),需要再用阈值把阴影滤掉——光照强的室外场景这个功能价值巨大,阴影跟着目标走、极易被误当前景的一部分。

背景模型还有个"冷启动"问题:视频开头模型未收敛,前几秒全是前景。对策是给 apply 传学习率参数:初始化阶段用较大学习率快速建模,稳定后转默认自适应更新,或干脆先空跑几百帧不输出。

2.3 光流:从"哪里动"到"怎么动"

光流假设"同一像素的亮度在相邻帧间不变",据此为每个像素解一个运动向量(亮度恒常假设在真实世界里近似成立)。稠密光流(Farneback)对全图每像素算向量,信息全但计算重;稀疏光流(金字塔 Lucas-Kanade,calcOpticalFlowPyrLK)只算指定的一组点,配合上一章的 goodFeaturesToTrack 角点(第 3 章第 1 节的 Shi-Tomasi 正是为此设计),快且稳,是视频跟踪的标准搭配。

稀疏光流的输出是每个点的新位置与状态位,画在图上就是一张"运动场"——箭头指示方向与幅度。应用直接而实用:手势识别(运动区域的主方向)、车流方向统计、相机自运动估计。

2.4 掩码后处理:把第 2 章接上

背景减除的原始掩码必然带碎斑与空洞,标准后处理正是第 2 章的组合:开运算清碎斑、闭运算填空洞、findContours 提取连通域、按面积过滤掉太小的区域,剩下的轮廓就是"运动目标候选框",交给下一节的跟踪器或第 4 章的检测器。

工程实践要点

3.1 选型与组合

实战里三套方案常常组合:背景减除出候选框(便宜),框内跑检测器确认类别(贵但准),光流在跟踪丢失时提供运动线索。纯帧间差分做触发、检测器做确认,是算力受限设备的经典两段式。选择的第一依据永远是相机是否固定——背景减除的前提是"背景基本不动",云台相机或手持场景直接出局,只能走差分或光流。

3.2 参数从哪调起

MOG2 的调参顺序:先看原始掩码(imshow 在循环里),碎斑多先加大 varThreshold 或在形态学环节清理;目标整体检出但"缺一块",是目标速度慢被背景模型吸收了,减小 history;光照渐变场景(日出日落)里前景越来越多,加大 history 让模型更慢跟随,或接受定期重建模型。

3.3 帧率与阈值的联动

帧率越低,相邻帧间目标位移越大:差分图更"实"(不容易漏慢目标),但空洞也更大;帧率高则相反。改了帧率(比如从 25 降到 10)后差分阈值与形态学核尺寸都要复查,参数不是一次调好终身有效。

⚠️ 常见坑:忘了滤阴影,检测框比目标大一圈还"拖着尾巴",目标走哪框跟哪大——检查 mask 里的 127 值是否被当成前景用了(阈值卡 200 以上即可滤掉)。另一个坑是相机自动曝光(AE)开着,画面亮度突变瞬间整个画面变前景;固定曝光(CAP_PROP_EXPOSURE 关自动)是监控类项目的第一项配置。

3.4 动手实验清单

  1. 用手机录一段固定场景有人走动的视频,跑 MOG2,观察前几秒模型未收敛的现象。
  2. detectShadows 开与关各跑一次,对比掩码与最终框的差异。
  3. history 从 100 调到 2000,让一个人在画面里站定 20 秒,观察他何时被"吸收"进背景。
  4. goodFeaturesToTrack 加 LK 光流跑一段视频,把轨迹箭头画出来,挥手时看箭头方向是否跟随。

3.5 三套方案的全景对照

运动分析三方案对比矩阵

运动分析三方案对比矩阵

3.6 常见疑问与解答

背景减除对雨雪天气怎么办?

雨雪是"背景在动"的极端案例,粒子噪声会让掩码布满碎斑。应对层次:提高 varThreshold 容忍粒子级波动;形态学开运算清残斑;时间维度的持续性过滤(真目标会连续出现多帧,雨点帧间无连续性,用一个"连续 N 帧命中才上报"的计数器即可过滤)。极端天气下宁可漏报攒着,也别误报刷屏。

相机轻微晃动(风吹支架)能容忍吗?

几像素级的周期性晃动,背景模型能部分吸收(它本来就是统计容忍),配合形态学清理基本无感;晃到十像素以上,边缘与背景反复"进出"模型,掩码沿高对比边缘出现持续噪声带,此时要么物理加固,要么上电子稳像(配准加 warp,计算量上一个台阶)——先怀疑支架螺丝,再怀疑算法。

光流的点跟丢了怎么办?

正常现象。目标转出视野、被遮挡、纹理区滑出,点就会失跟(状态位为 0)。设计上要"边跟边补":每隔几帧重新 goodFeaturesToTrack 补充新点,维持点的总数与覆盖;全靠一茬点跟到底,几十帧后就所剩无几了。

3.7 实战配方:越线计数器的完整实现

用一个高频真实需求收束本节:统计画面中越过指定线的人数(单向)。固定机位、俯视或半俯视视角。

第一步建背景模型。MOG2 挂在脚手架的处理层,前两百帧只更新不输出(冷启动,本节 3.3);阴影检测开着,掩码阈值卡 200 滤影。

第二步净化与目标提取。开闭运算清补(第 2 章第 3 节配方),findContours 加面积过滤出人员候选框。到这一步为止全是已有配方,无新知识。

第三步越线判定。在画面里画一条检测线(两个端点定义),对每个目标框的底边中点做"上一帧与这一帧是否分居线两侧"的判断:是,且方向与设定一致,计一次数。用底边中点而不是框中心,因为人过线时脚先过、框中心滞后,中点判定在行人半身重叠时更稳。

第四步防重与身份。同一人来回跨线会重复计数,两种解法:计数后给该目标加冷却期(几秒内不再计),或用下一节的跟踪器给目标编号、同号只计一次。冷却期方案十行代码,跟踪方案更严谨——按精度需求选,先用冷却期跑起来,不够再升级。

第五步校验。人工数一段视频的真实过线数对比系统计数,偏差超过百分之五回来调面积过滤与冷却期。这个"对账"步骤上线前必做——计数控不住的系统,算法再漂亮也没有意义。

本节要点回顾

  • 三方案三问题:差分答"变了吗"、背景减除答"哪些在动"、光流答"往哪动",组合使用是常态。
  • MOG2 给像素建档案:混合高斯容忍背景自身抖动,history 与 varThreshold 是保守度与灵敏度旋钮。
  • 阴影要主动处理:detectShadows 标 127,阈值卡 200 以上滤除,室外场景价值巨大。
  • 固定机位是前提:背景减除不容移动相机,云台场景换差分或光流;固定曝光同样重要。
  • 后处理接第 2 章:开闭运算加轮廓提取加面积过滤,掩码变候选框的标准链路。
  • 冷启动与慢目标:模型未收敛期空跑几百帧;慢目标被吸收时减小 history。

常见追问:背景减除的掩码为什么总在"呼吸"

那是学习率与场景变化在拉锯。树叶晃动、光照缓变会持续污染背景模型,模型一边学一边忘,掩码边缘就跟着闪。对策分两层:检测端提高 varThreshold 让小幅度扰动过不了门槛;模型端给 learningRate 一个小而非零的值,让背景缓慢更新跟上演化,又不至于把停住的行人学进背景。两参数联调的标准流程是:固定一个、扫另一个,用一段包含"静止目标"的录像做回归测试。

有了运动目标候选框,下一节给它们编号并持续跟随——MeanShift、CSRT 与八种跟踪器的选型一网打尽。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U