尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

YOLOv8+DeepSORT+Gradio:构建行人检测与跟踪系统实战

YOLOv8+DeepSORT+Gradio:构建行人检测与跟踪系统实战 简介基于 Gradio、OpenCV、YOLOv8 与 DeepSORT 的行人检测跟踪项目配有可选 WebUI 界面面向计算机视觉学生、毕设开发者与入门学习者。项目源于已通过测试的个人毕设可帮助理解检测、多目标跟踪与界面展示的完整流程。资源共 42 个文件以 31 个 Python 脚本为主涵盖主程序、检测模型、跟踪模块与工具配置另有说明文档、模型权重、测试视频与演示截图压缩包约 50.26MB目录清晰便于二次开发。当前已有 271 人学习下载。拿到后可直接运行完整工程参考说明文档复用权重和示例视频也可在代码基础上修改用于课程设计或项目演示但需遵守文档中的使用约定。1. YOLOv8、DeepSORT与Gradio各自负责什么组合后能做什么如果只用YOLOv8画面里的行人是没有“身份”的——每一帧都是独立检测上一帧出现在左侧的那个人下一帧是不是中间那位模型根本不知道。DeepSORT的卡尔曼滤波加外观特征匹配正好把跨帧的检测框串成带ID的轨迹人流计数、进出判定、轨迹回放这些功能才有数据基础。而Gradio的价值在交付侧不需要使用者懂命令行打开浏览器上传视频、拖一下置信度滑块就能看到结果演示时说服力强很多。这个资源把yolov8n.pt权重、DeepSORT模块、test.mp4测试视频和Gradio界面打包在一起适合做毕设演示、算法对比以及检测跟踪链路的快速验证。2. 先跑通依赖DeepSORT、YOLOv8、Gradio的环境搭建与项目结构2.1 项目入口与目录职责解压后先看两个入口文件main.py和app.py。main.py是命令行版本适合本地跑一段视频并输出结果文件app.py是 Gradio 启动器把视频上传、参数调整、结果预览集成在一个浏览器页面里。两者共用同一套检测和跟踪逻辑只是调用方式不同。其余目录的职责大致如下deep_sort/存放跟踪器实现包括卡尔曼滤波、匈牙利匹配、外观特征提取器configs/模型和跟踪器的参数配置默认已经给出适合行人场景的初始值utils/公共工具函数主要处理坐标格式转换、画框、结果统计。test.mp4是作者提供的行人测试视频先拿它跑通链路再换成自己的监控或路口视频。yolov8n.pt是用 COCO 数据集预训练好的权重模型本身支持 80 类目标但本项目只关心 person 这一类别所以检测阶段要显式过滤。2.2 依赖安装与版本倾向先建立虚拟环境再装依赖避免把系统 Python 搅乱cd yolov8-deepsort-tracking-main python -m venv .venv # Windows 下用 .venv\Scripts\activate source .venv/bin/activate pip install --upgrade pip setuptools wheel # CPU 环境先装 CPU 版 torch体积小很多 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 再装项目依赖 pip install -r requirements.txtrequirements.txt里核心是这几个包ultralytics8.0.0提供 YOLOv8 的模型加载和推理opencv-python负责视频读取和画框scipy在 DeepSORT 里承担线性分配求解gradio提供 WebUInumpy和torch是底层计算依赖。注意ultralytics默认会拉取最新版 torch如果先装好了 CPU 版 torch它会自动跳过 torch 的重复安装。如果原资源里的deep_sort目录是纯 Python 实现直接import就能用我更习惯在代码里换用deep-sort-realtime这个包API 更清晰后续跟踪器的初始化也要简单很多。两种方式跟踪逻辑一致不影响本文后面的代码。2.3 环境验证用命令行先把链路跑通安装完成后先不急着看代码用命令行做一次端到端验证python main.py --weights yolov8n.pt --source test.mp4 --conf 0.4 --device cpu命令的含义是把test.mp4逐帧送入 YOLOv8 检测检测框再由 DeepSORT 分配 ID最终在终端打印每帧的目标数量并把结果保存到输出目录。--conf 0.4是置信度阈值低于 0.4 的检测框会被丢弃--device cpu指定推理设备如果你的显卡支持 CUDA改成cuda速度会快数倍。跑完检查输出视频里行人框是否连续、ID 是否稳定这一步通过说明环境没问题。2.4 环境问题集中在三个位置新手在这个环节最容易报错基本集中在三处ModuleNotFoundError: No module named cv2原因是opencv-python没装进当前虚拟环境或者 VSCode 选了解释器但终端没激活虚拟环境。No module named torch且pip install ultralytics没报错说明 ultralytics 安装时跳过了 torch 的依赖解析单独执行第二条命令即可。Gradio 启动时报OSError: [Errno 98] Address already in use这是端口 7860 被占了换端口或者找到占用进程杀掉。提示Windows 下如果 ultralytics 加载模型时报DLL load failed装一遍 Visual C Redistributable 基本能解决这个问题常见于精简版系统。3. YOLOv8检测器yolov8n.pt选型、检测参数与行人过滤实现3.1 为什么默认权重是 yolov8n 而不是 s 或 mYOLOv8 按模型宽度和深度分成 n、s、m、l、x 五个档位yolov8n.pt是参数量最小的一档。行人检测跟踪是连续视频帧推理每帧都要做一次检测延迟直接决定系统能不能实时跑所以默认选用 nano 权重是合理的。权重文件参数量典型推理环境适合场景yolov8n.pt约3.2MCPU、低功耗板、嵌入设备实时视频流、在线演示yolov8s.pt约11.2M中低端GPU、较强CPU本地离线分析精度优先yolov8m.pt约25.9M服务器GPU密集小目标、多路视频离线处理YOLOv8 在骨干网络里用 C2f 结构替换了之前的 C3 模块不同层的特征在通道维度上做了更多组合同样参数量的特征表达能力更好。对行人这种中等尺寸目标nano 和 s 的差距并没有想象中大但推理速度差距接近一倍。如果后续要做 RK3588 这类边缘设备部署建议保留 nano 权重只用半精度推理进一步提速。3.2 检测器封装把 YOLO 推理包装成可复用类直接调用model(frame)也能检测但跟踪器需要的是结构化的坐标和置信度封装一步更稳妥from ultralytics import YOLO class PersonDetector: def __init__(self, model_pathyolov8n.pt, conf0.4, iou0.6): self.model YOLO(model_path) self.conf conf self.iou iou self.person_cls 0 # COCO 数据集中 person 类别索引是 0 def detect(self, frame): # frame 是 cv2 读出来的 BGR 图像数组 results self.model.predict( sourceframe, confself.conf, iouself.iou, classes[self.person_cls], verboseFalse, ) boxes results[0].boxes if boxes is None or len(boxes) 0: return None xyxy boxes.xyxy.cpu().numpy() confs boxes.conf.cpu().numpy() return xyxy, confs这个类把模型加载和推理细节都收拢了。conf0.4表示只保留置信度 40% 以上的预测框iou0.6是 NMS 的 IoU 阈值两个行人靠得近时高于这个重叠度会被合并成一个框classes[0]把输出限定在 person 类避免了把车、狗也送进跟踪器的浪费。xyxy是左上右下坐标格式后续转给 DeepSORT 时需要换算成中心点加宽高。3.3 检测参数对跟踪效果的影响conf和iou不是随便设的它们的取值会直接传导到跟踪层。conf调高到 0.5 以上稀疏场景里画面更干净但远处的小目标会被滤掉造成轨迹中断如果要做摔倒检测这类细粒度行为分析反而要调低到 0.3 甚至 0.25把低置信度的检测框留给跟踪器做时间平滑。iou在行人拥挤场景要特别注意设得过高会让重叠行人合成一个框跟踪 ID 随之错乱一般维持在 0.5 到 0.7 之间。我的习惯是先不看效果直接用命令行扫一遍置信度梯度yolo detect predict modelyolov8n.pt sourcetest.mp4 \ conf0.3 iou0.6 classes0 saveTrue projectrunsdetect子命令表明当前任务是检测classes0等同于代码里的 person 过滤saveTrue会把标注结果写到runs/detect/目录。逐个试 0.3、0.4、0.5 三档观察哪一档兼顾了框的完整性和噪声抑制再把这个值固定到检测类里。3.4 替换成自己训练的模型权重如果后续基于.yaml配置训练了自己的行人检测模型替换过程很简单把训练产出的best.pt路径传给PersonDetector的model_path参数即可。注意 Ultralytics 的模型文件自带类别信息如果训练数据集只有 person 一类classes[0]仍适用如果数据集是自定义多类别需要先打印model.names确认 person 的索引不要想当然用 0。4. DeepSORT跟踪集成卡尔曼预测、外观匹配与轨迹ID输出4.1 DeepSORT 在匹配时到底做了什么DeepSORT 的核心是“预测 匹配”。卡尔曼滤波器根据目标的历史运动状态预测当前帧的位置和速度得到一个先验框然后把 YOLOv8 给出的检测框和这个先验框做关联。关联依据有两个一是运动距离用马氏距离衡量检测框和预测位置的偏离程度二是外观相似度把目标区域缩放到固定尺寸后送入特征提取网络得到描述向量再算余弦距离。两个指标加权合并后交给匈牙利算法做全局最优匹配找到每一对检测框和轨迹的对应关系。这里有个容易忽略的细节YOLOv8 输出的是检测结果DeepSORT 跟踪的是轨迹两者之间没有一一对应关系。检测框没有匹配到任何轨迹时会新建一条未确认轨迹轨迹连续多帧没匹配到检测框会被保留一段时间后删除。所以跟踪器输出的 ID 和检测框并不是简单的强绑定关系。4.2 初始化跟踪器与参数含义如果使用deep-sort-realtime库初始化代码非常直观from deep_sort_realtime.deepsort_tracker import DeepSort tracker DeepSort( max_age30, # 目标连续多少帧没匹配到就删除轨迹 n_init3, # 连续匹配到 3 帧后才确认 ID 并输出 nn_budget100, # 外观特征队列最多记住 100 个向量 max_cosine_distance0.3 # 余弦距离超过 0.3 的检测框不匹配 )max_age30表示目标离开画面后 30 帧内再次出现还能延续原 ID调大到 50 以上能应对长时间遮挡但也会让误匹配的概率变高。n_init3的作用是减少闪烁 ID——前 3 帧的轨迹不会输出只有稳定出现 3 帧后才给 ID缺点是最初几帧看不到目标。nn_budget100限制外观特征是一般存储在固定大小的环形队列里目标外观变化不大时不需要调它。4.3 完整视频循环读取、检测、跟踪、绘制、输出把前面的组件串起来就是完整的主流程import cv2 cap cv2.VideoCapture(test.mp4) fourcc cv2.VideoWriter_fourcc(*mp4v) fps cap.get(cv2.CAP_PROP_FPS) w int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) writer cv2.VideoWriter(track_result.mp4, fourcc, fps, (w, h)) detector PersonDetector(yolov8n.pt, conf0.4, iou0.6) tracker DeepSort(max_age30, n_init3, nn_budget100) while cap.isOpened(): ret, frame cap.read() if not ret: break dets detector.detect(frame) raw_dets [] if dets is not None: boxes, confs dets for (x1, y1, x2, y2), conf in zip(boxes, confs): # DeepSORT 需要 [x, y, w, h] 格式置信度放第二位 raw_dets.append(([x1, y1, x2 - x1, y2 - y1], conf, None)) tracks tracker.update_tracks(raw_dets, frameframe) for track in tracks: if not track.is_confirmed(): continue x1, y1, x2, y2 map(int, track.to_ltrb()) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, fID:{track.track_id}, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) writer.write(frame) cap.release() writer.release()这段代码把检测和跟踪稳定地衔接起来。update_tracks传入的列表里每个元素是(bbox, confidence, feature)bbox必须是[x, y, width, height]第三个位置默认给None表示不使用外部特征由跟踪器内部的 ReID 模型自行提取。track.is_confirmed()过滤掉还在观察期的轨迹to_ltrb()把内部的中心点宽高格式转回左上右下坐标。循环结束用VideoWriter保存结果视频编码选mp4v是兼容性最好的方案。如果你已经有了deep_sort/目录的原始实现核心调用逻辑不变区别只是包名和坐标转换函数。替换时的检查点是确认update方法是否要求传入原始帧图像部分旧版本实现依赖帧图像做外观特征提取。4.4 跟踪参数调试经验表调试跟踪效果时重点关注三个参数参数默认值调参场景调参建议max_age30行人被遮挡后 ID 频繁变化提高到 50~70保留轨迹更久n_init3画面角落出现闪烁 ID提高到 5但注意 ID 显示延迟nn_budget100拥挤场景 ID 串扰严重提高到 200丰富外观特征一个我实际踩过的坑在商场出入口这类高密度场景max_age调到 70 后 ID 数量反而激增因为遮挡后的旧轨迹和新检测框发生了错误匹配。此时优先降低max_cosine_distance到 0.2严格控制外观相似度比单纯延长轨迹存活时间更有效。5. Gradio WebUI封装滑块调参、身份验证与部署排错5.1 用 Blocks 组装可交互页面Gradio 的Interface适合单输入单输出但检测跟踪场景需要同时控制视频、置信度、IoU 三个输入用Blocks更灵活import gradio as gr def batch_process(video_path, conf, iou): # video_path 是 Gradio 上传后的本地临时路径 return run_video_pipeline(video_path, confconf, iouiou) with gr.Blocks(title行人检测与跟踪) as demo: gr.Markdown(### YOLOv8 DeepSORT 视频检测跟踪) with gr.Row(): video_in gr.Video(label上传视频) video_out gr.Video(label跟踪结果) conf_bar gr.Slider(0.1, 0.9, value0.4, step0.05, label置信度阈值) iou_bar gr.Slider(0.1, 0.9, value0.6, step0.05, labelNMS IoU 阈值) btn gr.Button(开始推理) btn.click(batch_process, inputs[video_in, conf_bar, iou_bar], outputsvideo_out) demo.launch(server_name0.0.0.0, server_port7860)gr.Video组件接收上传视频后会缓存到临时目录回调函数batch_process拿到的video_path是磁盘路径直接传给cv2.VideoCapture读取即可。gr.Slider的step0.05让拖动精度足够细避免 0.1 的步长在 0.4 和 0.5 之间找不到合适值。server_name0.0.0.0是关键否则默认只监听127.0.0.1局域网其他设备访问不到。5.2 网页内处理图像时注意 BGR 与 RGB 转换用cv2.VideoCapture读入的每一帧都是 BGR 排列Gradio 的图像组件按 RGB 解析。如果直接把 BGR 帧交给gr.Image展示画面会偏蓝偏黄。正确做法是在送入 Gradio 之前做一次颜色空间转换frame_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)而保存视频时不需要转换VideoWriter内部默认按 BGR 处理。如果同时输出预览帧和结果视频最容易漏的正是这个转换检查方法很简单预览画面里红色衣服变成蓝色就是 BGR/RGB 没转。5.3 身份验证与端口冲突处理demo.launch支持auth参数传一个用户名密码元组即可开启身份验证demo.launch( server_name0.0.0.0, server_port7860, auth(admin, change_me) )这个参数适用于部署到服务器后给多人访问的场景避免了如何让内网同事通过浏览器拉地址看到自己的WebUI的问题。如果启动时报端口占用说明上一个 Gradio 实例还在运行在 Linux 下执行lsof -i :7860找到 PID 后结束进程再重新启动。Gradio 版本升级后最常见的报错是cannot import name ... from gradio这通常是 pydantic 版本冲突卸载 pydantic 后重新安装 gradio 会自动补齐兼容版本。提示在 Gradio 里处理实时摄像头流时优先让 Gradio 直接接收摄像头帧而不是反复上传视频文件gr.Image配合streamingTrue能拿到实时帧上一帧检测结果来不及输出时可以直接丢弃保证界面交互不卡顿。本文还有配套的精品资源点击获取
返回列表