拓冰建站拓冰建站
首页 / 资讯中心 / 正文

目标追踪实战:从dlib相关滤波到MobileNet-SSD检测追踪对比

简介本项目为计算机视觉实战型学习资源专注于视频场景下的目标检测与多目标持续追踪适合具备一定Python与深度学习基础、希望动手完成追踪项目的开发者。包内含训练与推理脚本、OpenCV与dlib等依赖whl安装包、模型配置与权重文件以及用于演示的mp4视频和avi输出视频共15个文件压缩包约125.3MB覆盖检测、特征提取、追踪、数据关联等关键流程。当前已有1113人学习下载。通过该资源可掌握基于Mobilenet SSD与dlib的多目标追踪实现思路理解KCF、卡尔曼滤波、DeepSORT等算法在实际数据上的效果并可基于示例代码直接运行调试结合运行视频与结果avi直观对比不同追踪策略的差异适合用于课程设计、项目实训与算法入门。1. 目标追踪项目为什么值得拆开看从dlib到MobileNet-SSD的取舍我拿到这个项目时第一反应不是跑通而是看它为什么同时给出两个版本。同一个race.mp4赛车视频一个用dlib的correlation tracker做单目标追踪一个用MobileNet-SSD做检测后追踪输出分别叫race_output_slow.avi和race_output_fast.avi。这其实是两条很典型的技术路线传统相关滤波方法不依赖外部检测器但需要手动框定初始目标而基于深度学习的检测追踪可以自动发现目标但要处理检测频率和计算开销的平衡。适合正在学计算机视觉的开发者也适合想要理解追踪瓶颈在检测还是关联的从业者。下面我会把依赖安装、两个脚本的差异、参数调整和验证方法完整走一遍。2. 目标追踪的两种技术路线从相关滤波到检测器驱动2.1 先搞清楚多目标追踪要解决什么问题多目标追踪MOT不是简单地在每帧做目标检测而是要把不同帧的同一个目标关联起来形成轨迹。这里有两个子问题检测目标在哪和数据关联哪个新框是老目标的新位置。在race.mp4这个赛车场景里车辆移动快有遮挡赛道有弯道容易出现目标短暂消失或互相贴近的情况。更麻烦的是透视几何的影响——远处目标很小近处目标很大如果追踪器不支持尺度变化同一个框会从车头漂到车尾。所以评估一个目标追踪方案不是看它在静态图片里画框有多准而是看它能不能跨帧保持ID一致。常见指标是MOTA多目标追踪准确度和ID Switch次数。但在这个项目里没有官方评测脚本我们只能用输出视频来主观判断或者自己加日志模块统计丢失帧数。2.2 dlib相关滤波追踪器的原理与适用边界dlib的correlation_tracker基于相关滤波思想它用目标区域提取特征训练一个滤波器模板然后在下一帧图像上滑动窗口计算响应响应最大的位置就是目标新位置。它的核心优势是快而且不需要GPU。在race.mp4这种画面里单CPU跑完全程毫无压力。但相关滤波有一个先天弱点模板会被目标外观自适应更新。如果目标被遮挡或背景与目标颜色相近滤波器会被污染响应峰值变得不清晰框就会慢慢跑偏。dlib的get_position()返回的置信度其实可以反映这种情况但很多入门代码不会去读tracker.update(frame)的返回值。另一个弱点是尺度估计能力有限虽然它内部有多尺度搜索但一旦目标尺寸变化太快或形变剧烈它跟不上节奏。所以slow版本适合目标运动平稳、没有大遮挡的场景。一旦出现以上问题就要转向检测器驱动的方法。2.3 MobileNet-SSD检测器如何与追踪器结合fast版本使用了MobileNet-SSD。MobileNet做特征提取SSD做多尺度检测框回归输入图像通常缩放为300x300或512x512。在CPU上MobileNet-SSD的推理速度大约能到20~30ms一帧加上后处理整体帧率可以接受。但检测器本身只回答“这一帧里有哪些目标”不回答“哪个目标是我上一帧跟的那个”。要完成追踪常见做法有三种对每个检测框和已有追踪框做IoU匹配用匈牙利算法分配ID用卡尔曼滤波器预测目标下一帧位置再做最近邻匹配提取目标的外观特征用ReID模型做深层关联。这个项目里的fast脚本并没有完整实现DeepSORT它更像是一个轻量级的“检测IOU关联”版本。理解这一点很重要因为你拿源码去跑会发现它处理多目标交叉时依然会出现ID跳变这是正常的。2.4 项目文件结构slow和fast脚本到底差在哪看一下压缩包里的文件分布. ├── multi_object_tracking_slow.py # dlib相关滤波需手动标注初始框 ├── multi_object_tracking_fast.py # MobileNet-SSD检测 追踪逻辑 ├── multi_object_tracking.py # 较早的版本可对照学习 ├── utils.py # 公共工具函数 ├── race.mp4 # 测试视频 ├── race_output_slow.avi # slow版本输出 ├── race_output_fast.avi # fast版本输出 ├── mobilenet_ssd/ # Caffe模型文件与标签 └── videos/ # 可能存放输出或测试素材从命名可以看出项目的演进先实现一个需要人工介入的慢速方案再换成自动检测的快速方案。multi_object_tracking.py可能是中间版本不建议直接用它当模板但可以对比看作者补了哪些逻辑。下表是slow和fast两个脚本在实现层面的核心差异对比项multi_object_tracking_slow.pymulti_object_tracking_fast.py目标初始化用户鼠标选中或固定坐标检测器自动发现追踪方式dlib correlation_tracker每帧检测 IoU关联尺度变化弱容易漂移由检测器重检恢复遮挡恢复差如果重新被检测到可恢复CPU占用低中输出AVIrace_output_slow.avirace_output_fast.avi这个表格不是让你背诵而是提醒你如果项目要求“自动追踪多个目标”那直接用slow版改是没戏的因为它只有一个tracker实例。必须先理解fast版的逻辑再决定往哪个方向扩展。3. 环境配置与依赖安装dlib wheel与Python版本的对应关系3.1 为什么dlib要用cp36的wheel包项目里单独放了dlib-19.7.0-cp36-cp36m-win_amd64.whl。这个文件名里的cp36指CPython 3.6cp36m指带pymalloc的ABIwin_amd64是Windows 64位。很多人在这一步卡住因为直接pip install dlib会触发源码编译需要本机装有Visual Studio和CMake耗时又容易失败。这个wheel是作者预编译好的省掉了编译环节。但它只适用于Python 3.6 Windows 64位。如果你本机是Python 3.8或3.10直接装这个wheel会提示“not a supported wheel”。这时候你有两个选择换conda环境到3.6或者改用pip install dlib19.24.0之类的新版预编译包。我建议先按原项目的环境来因为它配套的OpenCV和numpy版本也是按Python 3.6测的。3.2 创建虚拟环境并安装依赖我习惯用conda建独立环境避免污染全局Pythonconda create -n mot python3.6 conda activate mot pip install dlib-19.7.0-cp36-cp36m-win_amd64.whl pip install opencv-python4.5.5.64 pip install numpy1.19.5参数说明python3.6必须是这个版本否则wheel无法安装。opencv-python选4.5.5实测与dlib 19.7共存时没有DLL冲突。如果你装最新版可能会出现cv2.imshow偶尔崩溃的问题。numpy锁在1.19.5是因为OpenCV 4.5.5在更高版本的numpy下某些矩阵操作会报类型不匹配的错误。如果你的机器没有安装conda用virtualenv也可以但要注意Python解释器必须是3.6 x64。另外下载时注意你的系统是arm还是amd64文件名里已经写明了。3.3 验证安装是否正确安装完成后用一个最小脚本验证import dlib import cv2 import numpy as np print(dlib, dlib.__version__) print(opencv, cv2.__version__) print(numpy, np.__version__)预期输出dlib 19.7.0 opencv 4.5.5 numpy 1.19.5常见问题和处理方式如下表报错现象原因解决办法ImportError: DLL load failedVC运行库缺失或Python位数不一致安装Visual C Redistributable 2015-2022用64位Pythondlib没有__version__属性旧版本或导入错误直接打印dlib.__cpu_cache等不靠谱用dlib.__version__若不行说明dlib损坏cv2报错Unsupported dtypenumpy版本过新降级numpy到1.19.5验证通过后再运行multi_object_tracking_slow.py。如果运行时报找不到模型文件那问题不是环境而是工作路径。需要把当前目录切到mobilenet_ssd所在的父目录或者直接把脚本里的相对路径改成绝对路径。4. 实战复现multi_object_tracking_slow.py 的主流程拆解4.1 初始化追踪器如何框定第一个目标打开multi_object_tracking_slow.py第一段通常是读取视频创建dlib的correlation_tracker对象然后让用户在第一帧手动选择赛车。常见实现是用cv2.selectROIimport cv2 import dlib tracker dlib.correlation_tracker() cap cv2.VideoCapture(race.mp4) ret, frame cap.read() bbox cv2.selectROI(First Frame, frame, fromCenterFalse, showCrosshairTrue) if bbox[2] 0 and bbox[3] 0: dlib_rect dlib.rectangle(bbox[0], bbox[1], bbox[0] bbox[2], bbox[1] bbox[3]) tracker.start_track(frame, dlib_rect)参数说明cv2.selectROI返回一个元组(x, y, w, h)需要把它换算成左上角和右下角坐标因为dlib.rectangle只接受两个点。start_track(frame, rect)是初始化模板不是更新。如果调用update之前没有start_track会直接抛异常。selectROI默认是中心拖动设置fromCenterFalse后才是从左上角框选更符合直觉。这段代码做完后你就有了一个只追踪第一帧里那个目标的tracker。注意它没有多目标逻辑如果你框选时不小心划过两辆车它会把两辆车当成一个整体模板追踪漂移的概率大增。4.2 帧循环update追踪器的输出真正的追踪发生在循环里writer cv2.VideoWriter(race_output_slow.avi, cv2.VideoWriter_fourcc(*MJPG), 20, (frame.shape[1], frame.shape[0])) while True: ret, frame cap.read() if not ret: break tracker.update(frame) pos tracker.get_position() x1 int(pos.left()) y1 int(pos.top()) x2 int(pos.right()) y2 int(pos.bottom()) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, Target, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) writer.write(frame) cv2.imshow(Tracking, frame) if cv2.waitKey(1) 0xFF ord(q): break这段代码有几个容易被忽视的细节tracker.update(frame)的返回值是一个dlib.dlib.score对象里面包含weight和peak_to_side_lobe两个指标。很多教程直接忽略这个返回值但如果你要做抗漂移应该在跟随得分低时触发重检测。get_position()返回的是带小数的坐标画框必须转成int否则OpenCV会报错。VideoWriter的格式选了MJPG大约每帧20fps。要改速度就把第三个参数调高但要注意编码器是否支持。4.3 慢速版的局限为什么它只能追一个目标限定“只能追一个目标”的原因很简单代码里只创建了一个dlib.correlation_tracker实例。如果你把start_track和update放进循环里再调用一次那么第二个tracker会覆盖第一个吗不会但两个tracker会互相干扰因为它们都会尝试更新自己的位置而update之后你拿到的get_position是最后一个tracker的。另外dlib的相关滤波追踪器对尺度变化的支持有限。虽然它内部有多尺度搜索但当赛车从画面深处开向镜头车辆尺寸可能增大一倍这个时候tracker的响应峰值会变得平坦。一个朴素的改进方法是在每帧update之后根据pos宽高做一定的外扩然后再重新start_track但这个操作成本高且容易丢失历史信息。我的建议是如果你想用slow版快速验证目标追踪的流程那么就用它自带的race_output_slow.avi作为基准输出如果你想把它改造成多目标应该直接参考fast版的思路而不是在dlib tracker上堆多线程。4.4 utils.py里藏着什么辅助函数很多人在跑通后就不看utils.py了其实这个项目里它承担了重要的封装角色。通常它包含dlib_rect_to_cv_bbox把dlib.rectangle转成(x, y, w, h)元组start_trackers多目标时批量初始化trackerdraw_text在图片上写带背景的文字方便调试。打开后你会发现fast脚本和slow脚本都引用了它。如果后续你要增加日志输出或者统计帧率直接在utils.py里加一个函数两个脚本都能用这样不会让主代码变得臃肿。5. 从慢速版到快速版性能优化与验证技巧5.1 快速版做了什么优化multi_object_tracking_fast.py最大的改动是用MobileNet-SSD替代了手动框选。它会加载mobilenet_ssd/deploy.prototxt和mobilenet_ssd/mobilenet_iter_73000.caffemodel然后对每一帧做检测。为了平衡速度常见的做法是每隔5帧跑一次检测中间几帧直接用dlib tracker或光流预测。这个“检测-追踪-再检测”的循环既保留了检测器的绝对位置校准能力又借助追踪器避免每帧都跑CNN。如果你打开fast脚本大概率会看到类似这样的推理代码net cv2.dnn.readNetFromCaffe(deploy.prototxt, mobilenet_iter_73000.caffemodel) blob cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 0.007843, (300, 300), 127.5) net.setInput(blob) detections net.forward()blobFromImage的第二个参数是缩放因子第三个参数是输入尺寸第四个参数是均值。这里用的均值和缩放是针对MobileNet-SSD预训练数据来的不要随意改成0否则检测精度会明显下降。5.2 用输出视频和日志验证追踪质量跑完后生成race_output_fast.avi除肉眼观察外更可信的验证是统计追踪框的稳定性。我一般会加一个简单的日志记录每帧目标框的中心点和宽度with open(track_log.txt, w) as f: for i, det in enumerate(detections): f.write(f{i},{det[0]},{det[1]},{det[2]},{det[3]},{det[4]}\n)然后用pandas读进来计算中心点在连续两帧之间的位移。如果某帧中心点跳变超过车身宽度的一半大概率是ID Switch或跟错了目标。这个方法比看视频主观评价可靠得多。5.3 参数调优的具体技巧当出现丢失或乱跟时优先检查这几个参数置信度阈值det[2]是置信度通常设为0.5。如果你发现漏检多降到0.3如果误报多升到0.7。NMS阈值检测框重叠严重时需要非极大值抑制。OpenCV没有内置NMSBoxes其实有在cv2.dnn.NMSBoxes里但记得传入的是(x,y,w,h)格式不是(x1,y1,x2,y2)。检测间隔fast版如果每帧都检测CPU会吃力如果间隔太大目标快速转弯时会丢失。我一般在赛车场景设为2~3帧一次。追踪框外扩比例当目标有轻微遮挡时把上一帧的框向外扩5%再作为下一次检测的ROI输入能明显减少丢失。拿到这个项目后你真正要做的不是把两个脚本跑出一样的结果而是用不同参数观察追踪框在弯道和遮挡处的变化。理解了这两个版本的设计取舍才算真正掌握目标追踪的核心矛盾检测提升召回追踪保持稳定二者必须协同才能扛住真实视频里的尺度变化和遮挡。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门