ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

OpenCV运动物体检测实战:背景减除算法选型与参数调优指南

OpenCV运动物体检测实战:背景减除算法选型与参数调优指南 做运动物体检测这件事我用Python和OpenCV前前后后折腾了两个多月踩了不少坑也摸索出一套可以直接上手的方案。如果你正好也在研究这个或者准备做一个人脸识别、安防报警、人流统计之类的项目那我这篇应该能帮你少走很多弯路。这篇文章不会只贴一段代码就完事而是会把方案怎么选、参数怎么调、出了问题怎么排查全部掰开揉碎讲清楚。1. 整体设计思路与方案选型1.1 运动检测的主流算法到底怎么选先说结论OpenCV里做运动物体检测常用方案就三种——帧差法、背景减除法、光流法。很多人一上来就纠结选哪个其实没必要先弄清楚它们各自的脾气再根据场景决定。帧差法是最朴素的思路拿当前帧减去上一帧像素变化大的地方就是运动区域。优点是实现极其简单两三行代码就能跑起来计算速度快对光照突变不敏感缺点是只能检测物体边缘轮廓物体内部颜色一致的话会出现“空洞”而且检测结果很碎经常需要大量形态学处理才能连成块。背景减除法是目前工业项目里用得最多的方案。它的思路是先对背景建立统计模型然后拿当前帧和背景模型做差分。OpenCV里提供的createBackgroundSubtractorMOG2和createBackgroundSubtractorKNN就是干这个的。MOG2用混合高斯模型描述每个像素的分布对缓慢的光照变化有一定自适应能力KNN则是用K近邻的思路判断像素属于前景还是背景效果通常比MOG2略好但计算量稍大。这类算法能输出完整的前景目标区域不像帧差法那样只有边缘所以后续做轮廓分析和目标跟踪都更方便。光流法走的是另一条路它计算图像中每个像素点的运动矢量通过光流场的分布来判断运动目标。精度高能算出运动方向但计算开销大实时性很难保证。我实际测试过在树莓派这种低算力设备上跑稠密光流帧率直接掉到个位数基本没法用于实时监控。稀疏光流比如Lucas-Kanade算法要快一些但它更适合跟踪特征点而不是检测整块运动区域。所以如果你做的是实时监控、告警触发、客流统计这类场景背景减除是首选如果是简单实验或者固定场景下快速验证帧差法也够用光流法我建议谨慎除非你有GPU加速或者对运动方向有硬需求否则后期调优会让你崩溃。1.2 为什么我最终选了MOG2背景减除说说我自己的选择逻辑。我做这个项目的场景是室内固定摄像头监控光照有变化偶尔有人走动偶尔有窗帘飘动背景不是完全静止的但也不会剧烈变化。这个场景下帧差法的问题很明显走动的人会出现拖影轮廓框不完整光流法实时性扛不住而MOG2的自适应背景更新机制正好能处理缓慢的光照变化和轻微的背景扰动。而且MOG2有个很有用的参数叫detectShadows开启后能检测并标记阴影区域。室内灯光下人的影子是最大的干扰项如果没有阴影检测影子会被当作前景目标导致检测框严重偏大甚至一个人变成两个框。MOG2会把疑似阴影的像素标记为灰色127前景目标标记为白色255这样我就可以轻松过滤掉阴影。另外一个考虑是OpenCV的版本兼容性。createBackgroundSubtractorMOG2从OpenCV 3.0开始就是稳定API了网上资料多遇到问题也好查。相比之下createBackgroundSubtractorGMG另一种背景分割算法虽然在某些场景效果更好但参数多、收敛慢国内社区讨论也少出了问题很难找到参考。综上我建议大部分做固定场景运动检测的朋友直接选MOG2不用犹豫。如果你的场景是摄像头移动比如车载、无人机那背景减除就不适用了得考虑光流或者深度学习方案但那是另一个话题这篇文章就不展开了。2. 环境准备与OpenCV安装避坑2.1 Python虚拟环境搭建这个项目对Python版本的要求其实不高OpenCV从4.x开始对Python 3.6到3.11都有很好的支持。我个人习惯用Anaconda管理环境因为它自带numpy、scipy等科学计算库省去很多麻烦。conda create -n motion_detect python3.9 conda activate motion_detect pip install opencv-python如果你不用Anaconda用原生Python也是可以的python -m venv motion_env source motion_env/bin/activate # Windows下是 motion_env\Scripts\activate pip install opencv-python装完记得验证一下python -c import cv2; print(cv2.__version__)如果输出类似4.8.0这样的版本号说明装好了。但如果你是在公司内网或者公司配发的电脑上操作经常会遇到权限受限的情况这时候可以用pip install --user opencv-python装到当前用户的site-packages目录避免动系统环境。2.2 处理“No module named cv2”这类问题这个报错是最常见的新手拦路虎。我排查过不少次原因无非以下几种第一Python解释器对不上。比如你明明pip install了opencv但在某个IDE或者Jupyter里还是报错很可能是IDE用的是另一个Python解释器。解决方法是看一下sys.executable指向哪里确认和pip对应的Python是同一个。import sys print(sys.executable)然后在终端里执行命令python -m pip install opencv-python用python -m pip而不是裸的pip能保证装到当前Python对应的环境里。第二包名搞混了。有人装的是opencv-contrib-python有人装的是opencv-python这两个包的命名空间都是cv2但底层功能有差异。opencv-python是主库包含了大部分常用模块opencv-contrib-python额外包含了contrib扩展模块。两者不能同时安装否则会互相覆盖文件导致import报错。第三pip源问题。在国内网络环境下从pypi官方源下载OpenCV这个大包经常超时。我建议用清华源或者阿里源pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python遇到过下载到一半就断的情况可以加--timeout 120 --retries 5增强稳定性。2.3 Linux下源码编译的教训如果你需要在Linux服务器上安装带CUDA加速的OpenCV那pip就搞不定了必须源码编译。这一步坑特别多我经历过一次之后总结出了几个关键点。编译步骤大致是# 安装依赖 sudo apt-get update sudo apt-get install build-essential cmake git pkg-config libgtk-3-dev \ libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \ libxvidcore-dev libx264-dev libjpeg-dev libpng-dev libtiff-dev \ libatlas-base-dev gfortran python3-dev # 下载源码 git clone https://github.com/opencv/opencv.git git clone https://github.com/opencv/opencv_contrib.git cd opencv mkdir build cd build # CMake配置 cmake -D CMAKE_BUILD_TYPERELEASE \ -D CMAKE_INSTALL_PREFIX/usr/local \ -D WITH_CUDAON \ -D WITH_CUDNNON \ -D OPENCV_DNN_CUDAON \ -D ENABLE_FAST_MATH1 \ -D CUDA_FAST_MATH1 \ -D WITH_CUBLAS1 \ -D OPENCV_EXTRA_MODULES_PATH../../opencv_contrib/modules \ .. make -j$(nproc) sudo make install这个过程中最容易踩的坑是CUDA版本和OpenCV版本不匹配。OpenCV 4.x对CUDA的版本要求很严格比如OpenCV 4.8要求CUDA 11.x以上但你如果是CUDA 10.2的老环境就得找对应版本的OpenCV源码。另外opencv_contrib模块和opencv主仓的版本必须一致否则编译到一半会报找不到头文件的错误。还有一个细节是如果你不需要GPU加速千万别轻易开CUDA编译因为编译时间会从20分钟变成2小时而且稍微配置不对就编译失败。我做运动检测这种轻量级任务CPU版本的OpenCV完全够用。2.4 VSCode调试环境的取舍很多初学者喜欢问我用哪个IDE写OpenCV代码。我的答案是VSCode够了不用非得装PyCharm。VSCode里配置Python环境也就三步装Python扩展按CtrlShiftP选择解释器在.vscode/launch.json里设置python.defaultInterpreterPath然后配合断点调试看每一帧的fgmask长什么样效率非常高。特别是调试运动检测算法的时候很多时候你光看代码发现不了问题得把中间结果可视化出来才行。我会在代码里加窗口显示实时观察frame、fgmask和最终的标注结果三个画面这样问题一眼就能看出来。不过有一点我要提醒VSCode里如果装了多个Python插件有时候会导致解释器切换混乱。我遇到过一次明明选了conda环境跑起来却还是系统Python的情况最后发现是.vscode/settings.json里显式指定了一个旧的pythonPath。新版插件不认这个字段了要用python.defaultInterpreterPath。3. 核心实现从零搭建运动检测器3.1 完整代码与逐步拆解下面这套代码是我后来项目里一直在用的基础版本经过多次精简和验证稳定性和实时性都很不错。import cv2 import numpy as np class MotionDetector: def __init__(self, history500, var_threshold16, shadowTrue, min_area500): # 初始化MOG2背景减除器 self.bg_subtractor cv2.createBackgroundSubtractorMOG2( historyhistory, varThresholdvar_threshold, detectShadowsshadow ) # 形态学处理的内核椭圆核比矩形核在目标轮廓上更圆润 self.kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) self.min_area min_area # 小于这个面积的轮廓直接忽略 def process(self, frame): # 缩小图像到处理宽度提高实时性 h, w frame.shape[:2] scale 640.0 / w new_w, new_h 640, int(h * scale) frame_resized cv2.resize(frame, (new_w, new_h)) # 1. 背景减除得到前景掩码 fgmask self.bg_subtractor.apply(frame_resized) # 2. 二值化把阴影灰色清除 _, fgmask cv2.threshold(fgmask, 200, 255, cv2.THRESH_BINARY) # 3. 形态学处理先开运算去噪再闭运算填补空洞 fgmask cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, self.kernel) fgmask cv2.morphologyEx(fgmask, cv2.MORPH_CLOSE, self.kernel) # 4. 查找轮廓 contours, _ cv2.findContours( fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) # 5. 遍历轮廓过滤小面积画检测框 boxes [] for cnt in contours: area cv2.contourArea(cnt) if area self.min_area: continue x, y, w, h cv2.boundingRect(cnt) boxes.append((x, y, w, h)) cv2.rectangle(frame_resized, (x, y), (x w, y h), (0, 255, 0), 2) return frame_resized, fgmask, boxes if __name__ __main__: # 打开摄像头换成文件路径也可以 cap cv2.VideoCapture(0) if not cap.isOpened(): print(无法打开摄像头) exit(1) detector MotionDetector(min_area800) while True: ret, frame cap.read() if not ret: print(读取帧失败) break result, mask, boxes detector.process(frame) cv2.imshow(Motion Detection, result) cv2.imshow(Foreground Mask, mask) key cv2.waitKey(30) 0xFF if key 27: # ESC退出 break cap.release() cv2.destroyAllWindows()这段代码有几个设计细节我要重点说明。第一个是第2步的二值化。MOG2输出的fgmask里前景目标是白色255阴影是灰色127背景是黑色0。我直接用一个200的阈值把灰色滤掉只保留白色前景。这个操作看着简单但很多人会忽略导致检测框把影子也框进去。你可以试试不写这个threshold直接用原始fgmask做轮廓检测对比效果差异。第二个是形态学处理的顺序。先开运算先腐蚀后膨胀去掉零散的噪点再闭运算先膨胀后腐蚀填补目标内部的空洞。这个顺序不要反过来否则空洞会先被放大影响检测准确性。核大小也需要根据你的视频分辨率调整我用的是5x5椭圆核如果你的画面更清晰、目标更大可以换成7x7。第三个是min_area参数。它用来过滤面积过小的轮廓避免误检。这个值不是随便设的我建议你先不设过滤运行一次打印出所有轮廓的面积然后根据你关注的目标大小设定阈值。比如我那个项目里摄像头离地面大约3米人走动的轮廓面积通常在2000到20000像素之间而飞虫、树叶晃动产生的轮廓往往几百像素设成800就很安全。3.2 处理不同视频源的输入方式cv2.VideoCapture这个接口分两类一类是摄像头索引比如VideoCapture(0)另一类是视频文件路径比如VideoCapture(test.mp4)。这两者在代码里处理方式是一样的但有几个细微差别需要注意。摄像头输入时建议加一个缓冲区清理的操作。摄像头驱动自带的缓冲区如果不清会导致延迟越来越大画面越来越卡。可以在主循环一开始读掉几帧把缓冲区的旧帧消耗掉for _ in range(5): cap.grab() # 只抓帧不解码速度快视频文件输入时则要注意运动检测器的history参数。摄像头是连续画面背景模型能持续更新但视频文件如果是剪辑过的高频切换片断每到一个新场景MOG2需要重新学习背景大概几百帧才能稳定这期间会有大量误检。解决方法是检测到画面突变时重置模型或者把history调小一些比如200让模型适应更快。另外网络摄像头RTSP流的处理也经常有人问。用VideoCapture(rtsp://192.168.1.100:554/stream)就行但RTSP流的特点是网络抖动会导致拉流中断OpenCV的接口不会自动重连。我自己封装了一个简单的断线重连逻辑def reconnect_capture(url): cap cv2.VideoCapture(url) if not cap.isOpened(): print(拉流失败5秒后重试...) time.sleep(5) cap cv2.VideoCapture(url) return cap这个方案比较粗糙但对付一般项目够了。如果你要做7x24小时的监控建议还是用FFmpeg的拉流能力结合OpenCV处理稳定性更高。3.3 形态学、轮廓、面积过滤的底层逻辑很多初学者在跑通代码之后会问一个问题为什么我检测出的方框要么特别碎要么粘连到一起这就要回到形态学处理和轮廓查找的原理了。OpenCV的findContours查找的是二值图像中白色区域的边界。如果前景掩码里噪点很多就会被识别成很多小轮廓导致方框数量爆炸如果目标区域内部有空洞一个完整的物体会被切成好几块边界框也就变得不准确。形态学开运算是先腐蚀再膨胀。腐蚀会把白区域边界往里缩小的白色噪点会被直接消除然后膨胀把剩余的目标区域恢复回来。这个操作用来处理背景减除产生的离散噪点非常有效。闭运算是先膨胀再腐蚀把目标内部的小黑洞填上。这里有一个参数需要注意就是形态学的迭代次数fgmask cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, self.kernel, iterations2)迭代次数越多效果越强但目标边缘的精度也会下降。我测试下来2次迭代在大多数场景下是性价比最高的。轮廓查找的模式也有讲究。我用的RETR_EXTERNAL只查找最外层轮廓这就避免了一个目标内部的小孔洞被识别成多个轮廓。如果你改成RETR_CCOMP会把所有层级的轮廓都找出来方框之间会出现互相嵌套的情况很难处理。坐标也需要注意contourArea计算的是轮廓的真实面积而不是边界框的面积对形状不规则的物体来说contourArea会比w * h小很多。所以当你的min_area过滤失效时可以检查一下是不是设得太小了。4. 参数调优与性能优化4.1 MOG2三个关键参数的调优心得history、varThreshold、detectShadows这三个参数是MOG2的核心调好了事半功倍。history控制的是背景模型学习的历史帧数。默认500意味着模型最多参考过去500帧的数据来估计背景。调大它可以让背景更新得更慢适合场景中偶尔有短暂物体的场景比如过路的车调小它则让背景更新更快适合光照变化较快的场景但也更容易把缓慢移动的物体吸收成背景。我那个项目里有人会在画面里站着不动几分钟然后突然走动如果history太大站立期间模型会把这个人当成背景一走动反而检测不到完整目标。这时候我建议把history设在200到300之间兼顾稳定性。varThreshold是判断前景的方差阈值它反映了像素与背景模型差异达到多大时才被认为是前景。默认值16调小会更敏感运动区域的细微变化会变成前景但噪声也多调大则相反。雨天树叶抖动的场景我一般会调到25以上。detectShadows默认是False我建议在室内场景开启它。虽然有额外的计算开销但能大幅减少阴影误检。还有一个经常被忽略的点就是背景减除器调用apply时传入的learningRate参数。不传的时候MOG2会根据内部逻辑自动调整学习率但如果你的场景光照变化大可以手动指定一个固定学习率fgmask self.bg_subtractor.apply(frame_resized, learningRate0.01)学习率越大背景更新越快建议范围是0.005到0.05。这个参数很多教程不会提但它是调优时最灵活的工具。举个例子你的摄像头位置轻微晃动导致背景边缘不断变化如果开自动学习率前景掩码会一直闪烁此时固定一个较小的学习率比如0.01效果会明显改善。4.2 实时性能优化的四个方向运行这个检测程序时如果发现卡顿不要急着换电脑先看下面四个方向有没有做到第一图像缩放。OpenCV在处理720p以上的视频时如果直接全分辨率做背景减除速度会显著下降。我把处理宽度统一缩放到640像素因为运动检测本身对分辨率要求不高640宽度完全够用性能却能翻倍。有人会担心缩放影响小目标的检测但其实小目标占的像素比例不变缩放后面积会按比例缩小相应地调低min_area就行。第二调整处理帧率。监控类场景不需要每帧都处理30fps的视频每秒处理10帧也够了。可以在循环里做帧间隔控制frame_counter 0 while True: ret, frame cap.read() if frame_counter % 3 ! 0: frame_counter 1 continue frame_counter 1 # 处理逻辑这个简单的跳帧技巧能让CPU占用率降低三分之一甚至一半。第三用cap.set设置摄像头分辨率。很多时候你不需要1080p的输入在打开摄像头的时候就把它设成640x480能省下大量解码和缩放的算力。cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)第四考虑用多线程把IO和解码分离。摄像头读取本身是阻塞的如果读取一帧耗时50ms那即使处理逻辑只要20ms整体帧率也被拖累。用一个生产者-消费者模式专门有一个线程负责读帧主线程负责处理import threading import queue frame_queue queue.Queue(maxsize2) def read_frames(cap): while True: ret, frame cap.read() if not ret: break if frame_queue.full(): frame_queue.get() # 丢弃旧帧 frame_queue.put(frame) cap cv2.VideoCapture(0) thread threading.Thread(targetread_frames, args(cap,)) thread.daemon True thread.start() while True: frame frame_queue.get() # 处理队列大小设为2就够太大反而会导致延迟。这个方法我是在做多路摄像头检测时想明白的单路可能感受不明显但两路以上提升会非常明显。4.3 检测框稳定性的体验优化用上述代码做实时检测时你会发现检测框会轻微抖动特别是目标静止下来的时候框会忽大忽小。这是因为MOG2对静止目标的背景吸收不是瞬间完成的边界像素偶尔会被判定为前景或背景。解决这个问题有两种思路。一种是在图像层面做平滑对fgmask再做一次中值滤波代价是目标边缘会变模糊。另一种是在结果层面做目标跟踪和框的平滑用卡尔曼滤波或者简单的EMA指数平滑smoothed_box None alpha 0.3 # 在每一帧循环中 if box is not None: if smoothed_box is None: smoothed_box box else: smoothed_box tuple( int(alpha * b (1 - alpha) * s) for b, s in zip(box, smoothed_box) )alpha越大响应越快但抖动越明显alpha越小框越稳但滞后越明显0.3左右是速度和稳定性的不错平衡。另外我强烈建议把检测结果写入一个固定格式的数据结构比如一个deque或者列表记录每一帧检测到的目标坐标和面积。这样做的好处是后续如果要加报警逻辑比如“目标在画面中停留超过10秒”这种需求你只需要统计历史帧里同一个位置的持续出现次数而不必重复解析视频。5. 常见问题与排查技巧实录5.1 问题速查表我把自己和身边朋友在实际操作中遇到过的高频问题整理成了表格方便你对照排查。现象可能原因解决方案import cv2报错ModuleNotFoundErrorPython环境混乱或包名错误用python -m pip install opencv-python确认sys.executable路径摄像头打不开返回False摄像头被其他程序占用、没有权限检查是否被微信/浏览器占用Linux下加sudo或加入video组检测框闪烁严重前景掩码噪点多增大varThreshold增强形态学开运算迭代次数阴影被识别为目标detectShadowsFalse开启阴影检测并加阈值过滤灰色区域检测框把多人连成一个目标距离太近空洞被填满调整闭运算核大小增大面积过滤阈值静止物体误报MOG2背景模型未收敛预热100帧再开始检测期间不输出结果CPU占用100%分辨率太高或没有降帧缩放图像到640宽跳帧处理画面卡顿延迟越来越大摄像头缓冲区积压打开前cap.set设置分辨率主循环开头grab()清空缓冲区RTSP拉流中断后不恢复OpenCV不自动重连封装重连逻辑或用FFmpeg拉流5.2 背景模型预热的重要性有一个经验是血泪教训换来的。刚把检测器接到新场景时前几十帧的检测结果几乎没法看整个画面都在闪。原因是MOG2在启动阶段还没有学到可信的背景模型刚开始的每一帧都算作前景这时候输出报警逻辑的话会疯狂误报。解决方案很简单在正式做检测之前先跑一段“预热”阶段把前100帧的输入喂给apply函数但不做任何检测和输出。相当于让模型先“看一眼”场景学习出一个大致准确的背景。# 预热阶段 for _ in range(100): ret, frame cap.read() if not ret: break self.bg_subtractor.apply(frame)预热阶段我也会做图像缩放保证和正式检测阶段的输入分辨率一致。如果分辨率不一致背景模型会把尺寸变化误判为画面突变预热就白做了。另外背景模型的预热不是一次性的。如果你的摄像头晚上被关了第二天打开光线完全变了旧模型可能已经失效。这时候做一个自动判断如果连续若干帧检测到面积超过画面比例70%的“前景”大概率是背景突变需要重置模型。OpenCV本身没有暴露重置接口但你可以重新创建一个背景减除器对象相当于一切重来。5.3 多目标场景的粘连与分割在实际项目中多人同时进入画面是常态你会发现多个目标会被一个大检测框框住算不出人数。这个问题本质上是由闭运算的填充造成的。目标之间如果距离太近闭运算的膨胀会把它们连成一片。我的处理经验是在形态学阶段闭运算的核不要开太大。很多人觉得核大了填洞更彻底但代价是两个目标的间隙也会被填上。保守的做法是用较小的核比如3x3做闭运算然后在轮廓判断阶段引入一个宽高比过滤。人的宽高比在0.2到1.5之间如果检测框的宽高比异常大说明可能框住了多个挨得很近的目标可以考虑用基于距离的聚类把轮廓再拆分。这里涉及分水岭之类的复杂算法不是这篇文章能展开的。如果你的项目对多人检测要求很高我建议直接考虑用目标检测模型YOLO、SSD这些来替代传统的背景减除。运动检测适合做“有没有东西在动”的粗判断而精细的“有多少人、是谁”还得靠深度学习的检测模型。两者并不冲突你可以先用背景减除做区域级跟踪再用深度学习模型在检测区域内做精细识别这也是一个不错的混合方案。5.4 画面光照变化导致全屏误检这个坑我遇到得很早。白天阳光从窗户照进来云飘过时整个画面的亮度会发生剧烈变化MOG2会把全屏像素都判为前景检测框铺满整个画面。有两个思路可以缓解。一是让背景模型的学习率跟随光照变化动态调整检测到全屏大面积变化时临时提高学习率让模型快速适应新的光照条件。二是做一个全局光照补偿在预处理阶段计算当前帧与背景的亮度差异并做颜色校正。第二种方案实现稍复杂但效果更稳定。我用的一个简化版本是每帧计算前景掩码中白色像素的比例如果超过某个阈值比如0.6就认为发生了全局光照突变此时把这帧当成新的背景强制进行模型自适应white_ratio cv2.countNonZero(fgmask) / fgmask.size if white_ratio 0.6: self.bg_subtractor.apply(frame_resized, learningRate0.1) else: self.bg_subtractor.apply(frame_resized)这个优化在光照突变时能明显减少误报但注意它也会把真正的全屏运动比如有人把摄像头挡住过滤掉。如果你的应用场景不允许漏检这个情况那这个优化就不适用了。6. 写在最后的经验之谈这次做运动物体检测的经历让我最大的体会是OpenCV的API调用其实很简单真正的难点全在参数的配合和对场景的理解上。同一个检测器挪到不同的摄像头位置、不同的光照条件下效果天差地别。所以如果你看到我这篇文章跑通了demo到了自己场景里效果不理想别急着怀疑代码先花半小时观察一下你的画面里到底什么在动、什么在闪、什么被影子覆盖了这些观察结论才是调参的依据。最后再分享一个小技巧调试的时候把cv2.imshow的窗口固定下来不要每次都重新拖动并且用cv2.waitKey(0)单步查看某一帧的fgmask这对理解每一步处理的效果非常有帮助。另外如果你最终要把这个检测结果接入告警或者统计系统记得把检测的置信度比如轮廓面积、检测框的稳定性也一起记录下来后面做策略调整会方便很多。
返回列表