基于 YOLO11 + ByteTrack 的车辆检测跟踪与车流量统计系统实战
摘要本文围绕一个可以直接运行的 AI 项目展开完整实现了“车辆检测、目标跟踪、过线计数、统计可视化、结果导出、Web 页面展示”这一套常见道路视频分析流程。项目默认支持两种运行方式第一种是接入 Ultralytics YOLO11 权重对真实道路图片或视频进行车辆检测并通过 ByteTrack 进行目标 ID 跟踪第二种是离线演示模式即使没有下载 YOLO11 权重也可以运行内置道路示例验证检测框绘制、目标 ID、计数线判断、统计图表和 CSV 导出等核心功能。这个项目适合用作 AI 项目实战、课程设计、交通视频分析入门、目标检测系统开发练习也适合作为后续扩展 PySide6 桌面软件、Flask/FastAPI 接口服务、停车场检测、道路拥堵分析、车牌识别系统的基础版本。项目已经包含完整源码、配置文件、示例数据、权重下载说明、运行脚本、运行结果截图和博客配图可以直接运行也可以继续二次开发。关键词YOLO11、ByteTrack、车辆检测、目标跟踪、车流量统计、OpenCV、Streamlit、Python 项目实战、目标检测系统、道路视频分析1. 项目背景为什么要做车辆检测与车流量统计系统在计算机视觉项目中车辆检测和车流量统计是非常适合做成项目实战的题目。它不像单纯图像分类那样只输出一个类别也不像完整智能交通平台那样一开始就需要复杂业务系统。车辆检测统计系统的中间层次比较合适既有深度学习模型推理又有 OpenCV 视频处理还能加入目标跟踪、过线计数、统计图表和 Web 界面。对于学习者来说它能把“模型推理”和“系统落地”连接起来。从应用场景看道路监控、园区入口、停车场通道、物流园区、校园门口、工厂门禁都可能需要统计车辆通行情况。一个基础系统通常至少要解决四个问题画面中有没有车车辆属于哪一类同一辆车在连续帧中如何保持同一个 ID车辆是否穿过了指定计数线。前两个问题主要由目标检测模型解决第三个问题由多目标跟踪算法解决第四个问题由业务计数逻辑解决。YOLO11 是 Ultralytics 推出的目标检测模型系列官方文档说明 YOLO11 支持目标检测、实例分割、图像分类、姿态估计和旋转框检测等任务并提供yolo11n.pt、yolo11s.pt、yolo11m.pt等检测模型变体。对于车辆检测这种需要实时或准实时处理的项目先使用较轻的yolo11n.pt做演示比较合适后续再根据精度要求换成更大的模型。Ultralytics 的跟踪模式还支持 BoT-SORT 和 ByteTrack使用trackerbytetrack.yaml或自定义 YAML 配置即可启用跟踪能力。参考资料Ultralytics YOLO11 文档https://docs.ultralytics.com/models/yolo11/Ultralytics Track 模式文档https://docs.ultralytics.com/modes/track/本文的项目不是只讲模型调用而是把车辆检测系统做成完整工程源码结构清晰有配置文件有演示数据有可视化结果有 CSV 导出有 Streamlit 页面也保留真实 YOLO11 权重接入方式。这样的项目更适合发布在 CSDN 的“AI 项目实战”栏目因为读者不仅能看到效果图还能下载源码直接运行。2. 项目效果展示为了让效果图对应真实运行结果本文重新使用真实道路视频素材和 YOLO11 权重进行了正式验证。测试时使用yolo11s.pt作为检测权重从真实道路视频中抽取一帧做图片检测并继续处理视频前 140 帧做 ByteTrack 跟踪与过线计数。检测后端为yolo11置信度阈值为 0.20水平计数线位置比例为 0.55。下面是真实道路视频抽取的原始帧可以看到前方有货车、多辆轿车和道路遮挡运行图片检测后系统在同一帧中识别出 6 个车辆目标包括 car 和 truck并叠加类别、置信度、ID、计数线和统计面板运行视频处理后系统逐帧调用 YOLO11 检测和 ByteTrack 跟踪目标轨迹以青色线条保留在画面中。下面这张结果帧中货车目标已经获得稳定 ID画面顶部统计面板显示本次视频累计过线 1 次统计图表会展示车辆过线总数和方向统计。本次真实视频验证处理了 140 帧过线事件总数为 1其中 down 方向 1 次类别统计为 car 1 次3. 技术路线说明本项目的核心路线可以概括为读取图片或视频帧调用检测器得到车辆框给连续帧中的车辆分配 ID计算车辆中心点和计数线的位置关系根据中心点跨越方向记录过线事件最后将结果可视化并导出文件。在真实 YOLO11 模式下系统会优先加载配置文件中的model_path。本文的正式运行截图使用weights/yolo11s.pt如果更关注速度也可以换成weights/yolo11n.pt。模型加载后系统通过 Ultralytics 的推理接口得到检测框。如果处理视频并且配置中启用了use_yolo_bytetrack系统会调用 YOLO 的track()方法结合configs/custom_bytetrack.yaml获得目标 ID。这样车辆在连续帧中可以保持相对稳定的编号后续过线计数就能基于 ID 去重避免同一辆车被重复统计。在离线演示模式下系统使用内置示例道路数据和颜色块检测器模拟车辆检测再用轻量的质心跟踪器分配 ID。这个设计的目的很明确模型权重文件较大不适合直接打包到项目里很多用户第一次拿到项目包时也不一定能联网下载权重。如果项目必须先下载模型才能看到效果交付体验会变差。因此项目默认提供一个可复现的最小演示流程同时保留真实模型接入入口。从工程角度看这种双模式设计比较实用。对于项目展示、课程设计和博客发布内置演示可以保证结果可复现对于真实场景YOLO11 ByteTrack 可以处理真实道路图片和视频。两部分共用同一套计数、绘图和导出逻辑后续扩展时不需要重写业务代码。4. 系统架构设计系统架构分为输入层、检测层、跟踪层、计数层、可视化层和导出层。输入层负责读取图片、视频或用户上传文件检测层根据权重情况选择 YOLO11 或离线演示检测器跟踪层负责分配目标 ID计数层根据虚拟线和车辆中心点判断方向可视化层绘制框、ID、轨迹、计数线和统计面板导出层保存图片、视频、CSV 和图表。这种结构的好处是每个模块职责比较清楚。比如后续想把 Streamlit 换成 Flask只需要保留src/video_processor.py里的处理逻辑把页面层换成接口服务即可。想把检测模型从 YOLO11 换成自定义best.pt只需要修改配置文件中的模型路径。想增加多条计数线只需要扩展counter.py的计数逻辑而不是改动模型推理代码。5. 项目目录结构项目目录如下核心文件说明如下。yolo11_vehicle_counter_system/ ├── blog.md # 当前博客文章 ├── README.md # 项目运行说明 ├── requirements.txt # Python 依赖 ├── app.py # Streamlit Web 页面 ├── run_demo.py # 命令行演示入口 ├── run.bat # Windows 运行脚本 ├── run.sh # Linux / macOS 运行脚本 ├── configs/ │ ├── config.yaml # 主配置文件 │ └── custom_bytetrack.yaml # ByteTrack 配置 ├── src/ │ ├── detector.py # YOLO11 / 离线检测器 │ ├── tracker.py # 离线质心跟踪器 │ ├── counter.py # 过线计数逻辑 │ ├── visualizer.py # 检测框、轨迹、统计面板绘制 │ ├── video_processor.py # 图片和视频处理流水线 │ ├── demo_generator.py # 内置示例数据生成 │ └── report_utils.py # 图表和博客配图生成 ├── demo_data/ │ ├── sample_road.png # 自动生成的示例图片 │ └── sample_video.mp4 # 自动生成的示例视频 ├── weights/ │ └── README_WEIGHTS.md # 模型权重下载说明 ├── images/ │ ├── figures/ # 架构图、流程图、目录图 │ └── results/ # 运行结果图 ├── outputs/ │ ├── detections.csv # 逐帧检测结果 │ ├── crossing_events.csv # 过线事件 │ ├── count_summary.json # 统计摘要 │ └── processed_demo_video.mp4 # 处理后视频 └── docs/ ├── common_errors.md # 常见问题 ├── development_notes.md # 开发说明 └── packaging_guide.md # 打包说明6. 环境配置与模型准备项目推荐使用 Python 3.9 及以上版本。先进入项目根目录然后安装依赖pipinstall-rrequirements.txt如果只想验证项目流程可以直接运行python run_demo.py这条命令会自动生成示例图片和示例视频然后依次执行图片检测、视频处理、过线计数、统计图生成和结果文件保存。由于默认配置是model.mode: auto当系统没有发现配置文件中指定的 YOLO11 权重时会自动使用离线演示检测器。如果要对真实道路视频进行 YOLO11 检测需要准备模型权重。本文效果截图使用的是yolo11s.pt如果机器性能有限也可以改用更轻的yolo11n.pt。可以先安装 Ultralyticspipinstallultralytics然后下载或触发下载yolo11s.ptpython-cfrom ultralytics import YOLO; YOLO(yolo11s.pt)下载完成后将权重复制到weights/yolo11s.pt配置文件中保持如下设置model:mode:automodel_path:weights/yolo11s.pt如果权重存在系统会优先使用 YOLO11如果权重不存在则自动回退到 demo 模式。模型权重没有直接打包到压缩包中因为.pt文件通常比较大并且可能受网络环境影响。项目已经在weights/README_WEIGHTS.md中写清楚权重名称、下载方式、保存路径和检查命令。7. 配置文件设计configs/config.yaml是项目的主配置文件。常用参数如下model:mode:automodel_path:weights/yolo11s.ptconfidence:0.25iou:0.45device:cpuvehicle_classes:-car-bus-truck-motorcycle-bicycletracking:use_yolo_bytetrack:truetracker_config:configs/custom_bytetrack.yamlmax_disappeared:12max_distance:90counting:line_position_ratio:0.55line_orientation:horizontalvideo:max_demo_frames:96fps:12codec:mp4vmode有三个可选值。auto是推荐模式权重存在时使用 YOLO11不存在时使用离线演示检测器。yolo是强制真实模型模式如果没有安装 Ultralytics 或没有权重会直接报错。demo是强制离线演示模式适合写博客、课程展示和快速测试。line_position_ratio控制计数线位置。例如视频高度为 480比例为 0.55则水平计数线的 y 坐标约为 264。车辆中心点从计数线一侧移动到另一侧时就会生成一个过线事件。8. 核心代码解析检测器如何兼容 YOLO11 和离线演示检测器写在src/detector.py中。项目启动时会先尝试加载 YOLO11如果ultralytics库或模型权重不存在就保持 demo 后端。核心逻辑可以简化理解为classVehicleDetector:def__init__(self,model_path,modeauto,confidence0.25,iou0.45):self.modelNoneself.backenddemoifmodein(auto,yolo):self._try_load_yolo()defdetect(self,frame_bgr):ifself.modelisnotNone:returnself._detect_yolo(frame_bgr)returnself._detect_demo_color_blocks(frame_bgr)真实 YOLO11 模式会调用resultsself.model.predict(frame_bgr,confself.confidence,iouself.iou,deviceself.device,verboseFalse,)然后从结果中解析xyxy、置信度、类别 ID 和类别名称。为了让项目聚焦车辆统计代码会过滤出car、bus、truck、motorcycle、bicycle等车辆相关类别。由于 YOLO11 的 COCO 预训练模型已经包含常见车辆类别所以不训练也能先做通用车辆检测演示。离线演示模式使用颜色块检测器。它不是为了替代深度学习模型而是为了保证项目包在无权重环境下也能完整运行。示例道路中的车辆由程序生成颜色和类别一一对应检测器通过严格的 BGR 颜色规则找到车辆块然后返回统一的Detection数据结构。后续跟踪、计数、绘图、导出逻辑完全相同所以真实模式和演示模式的工程接口是一致的。9. 核心代码解析视频跟踪与 ByteTrack 接入在真实 YOLO11 模式下项目支持调用 Ultralytics 的track()方法resultsself.model.track(frame_bgr,persistTrue,trackertracker_value,confself.confidence,iouself.iou,deviceself.device,verboseFalse,)persistTrue表示在连续帧之间保留跟踪状态。tracker可以指向项目里的configs/custom_bytetrack.yaml也可以直接使用 Ultralytics 内置的bytetrack.yaml。当跟踪结果中存在boxes.id时系统会将目标 ID 写入Detection.track_id后面的计数逻辑就可以根据 ID 去重。离线演示模式下没有真实模型输出的跟踪 ID所以项目实现了一个简单的CentroidTracker。它的思路是保存上一帧每个目标的中心点下一帧来了新检测框后计算新旧中心点距离把距离最近且类别一致的检测框分配给同一个 ID。如果某个目标连续多帧没有匹配上就认为它消失。这个方法不适合复杂遮挡场景但对内置演示视频足够稳定。跟踪器中还做了类别约束也就是 car 只会和 car 匹配bus 只会和 bus 匹配避免两个目标靠近时 ID 跳到不同类别的车辆上。真实道路视频中这类问题通常交给 ByteTrack 处理。10. 核心代码解析过线计数逻辑过线计数写在src/counter.py中。它并不依赖 YOLO11也不依赖 Streamlit只依赖每个检测目标的中心点和 ID。对于水平计数线系统会比较车辆中心点的 y 坐标和计数线 y 坐标。如果上一帧在计数线上方当前帧到了计数线下方就记为down如果上一帧在计数线下方当前帧到了计数线上方就记为up。对于垂直计数线也可以类似判断left和right。简化逻辑如下previous_sideself.last_side.get(track_id)current_sideself._side(detection)ifprevious_sideisnotNoneandprevious_side!current_side:directiondownifprevious_sidecurrent_sideelseupself.direction_counts[direction]1为了避免同一辆车在计数线附近抖动导致重复计数系统维护了counted_pairs记录已经统计过的(track_id, direction)。同一个 ID 同一个方向只会被统计一次。真实场景中如果车辆可能掉头或反复穿越计数线可以根据业务需求修改去重策略例如同一 ID 在间隔一定帧数后允许再次计数。本次真实视频验证处理 140 帧生成了 1 条过线事件一辆 car 在第 76 帧向下穿过水平计数线。结果保存到outputs/real_crossing_events.csv示例内容如下center_x,center_y,class_name,direction,frame,track_id 555,1061,car,down,76,611. 核心代码解析可视化与结果导出可视化代码写在src/visualizer.py中主要负责绘制检测框、类别名称、置信度、目标 ID、轨迹、计数线和统计面板。对于项目展示来说可视化很重要。仅仅输出一个 CSV 很难让读者直观看到效果而检测框和轨迹可以快速说明系统确实完成了车辆识别和跟踪。视频处理流水线写在src/video_processor.py中。它使用 OpenCV 的VideoCapture逐帧读取视频使用VideoWriter保存处理后的视频。OpenCV 官方教程也将cv2.VideoCapture()和cv2.VideoWriter()作为读取、显示和保存视频的基础接口。项目在保存 MP4 失败时会尝试改用 AVI避免不同系统编码器不一致导致程序中断。处理完成后项目会导出几个文件outputs/real_detections.csv outputs/real_crossing_events.csv outputs/real_count_summary.json outputs/real_anpr_processed_video.mp4 images/results/real_traffic_image_detection_result.png images/results/real_traffic_video_count_result.png images/results/real_traffic_statistics_chart.pngreal_detections.csv保存每一帧的检测框、类别、置信度和 track_idreal_crossing_events.csv保存实际过线事件real_count_summary.json保存总数、方向统计、类别统计和输出路径。这样既可以在页面上展示也可以给后续分析程序读取。12. Streamlit Web 页面实现app.py提供了一个 Streamlit 页面。页面左侧是参数设置包括检测模式、置信度阈值、IoU 阈值、计数线位置和最大处理帧数右侧分为图片检测、视频计数和运行说明三个标签页。页面中使用了st.file_uploader让用户上传图片或视频。Streamlit 官方文档说明st.file_uploader可以在应用中显示文件上传控件默认支持通过参数限制上传文件类型。这个控件非常适合小型 AI 演示项目因为用户不需要手动修改路径只要上传文件就能测试模型。图片检测页面的逻辑是如果用户上传图片就保存到outputs/uploads/如果用户点击内置示例按钮就使用demo_data/sample_road.png。然后调用VehicleCounterPipeline.process_image()得到结果图和 CSV并用st.image()和st.dataframe()展示。视频计数页面的逻辑类似。用户上传视频或选择内置示例后系统调用process_video()处理视频保存结果帧、结果视频、检测 CSV 和过线 CSV再展示统计图表。真实部署时可以进一步加入任务队列、进度条、历史记录和数据库但作为项目实战版本当前页面已经覆盖了核心展示需求。13. 运行项目并查看结果在项目根目录执行下面命令可以先跑通内置演示流程python run_demo.py如果要复现本文中的真实效果图需要先准备 YOLO11 权重并把真实道路视频放到项目输入目录再调用同一套VehicleCounterPipeline处理图片帧和视频。本文正式运行的日志类似如下Starting real YOLO11 vehicle counter run... Model: weights/yolo11s.pt Image source: real_inputs/anpr_real_frame_42.jpg Video source: real_inputs/anpr-demo-video.mp4 Detector backend: yolo11 Real image detections: 6 Video frames processed: 140 Crossing total: 1 Down: 1, Up: 0, Right: 0, Left: 0 Real YOLO11 run finished successfully.如果安装了 Streamlit可以运行streamlit run app.py打开页面后建议先点击“运行内置图片示例”和“运行内置视频示例”确认项目流程正常。然后再下载 YOLO11 权重把真实道路视频上传到页面中测试。初次测试真实视频时可以先把最大处理帧数设置小一点例如 100 或 200确认速度和效果后再处理完整视频。14. 常见问题与解决方法问题一为什么没有把 YOLO11.pt权重直接打包进项目模型权重文件较大并且用户可能希望选择不同模型版本。直接打包权重会让压缩包变大也可能影响分发。因此项目只提供weights/README_WEIGHTS.md说明下载方式和保存路径。没有权重时项目仍然可以运行离线演示。问题二为什么真实图片没有检测结果先检查配置中的model_path指向的权重是否存在再检查model.mode是否为auto或yolo。如果图片中车辆太小、遮挡严重或画面过暗可以降低置信度阈值比如从 0.25 调到 0.15或者换用yolo11s.pt这类更强的模型。通用 COCO 权重对常见车辆有效但对特殊车辆、夜间监控、俯视角道路画面可能不够稳定这时需要训练自定义数据集。问题三为什么视频统计数量不准确车辆计数依赖跟踪 ID 是否稳定。如果车辆遮挡、检测框丢失、画面抖动或计数线设置不合适ID 可能切换导致漏计或误计。可以尝试调整置信度、使用更强模型、降低视频分辨率提高帧率或者训练更适合当前道路场景的模型。问题四OpenCV 保存视频失败怎么办不同操作系统对 MP4 编码支持不完全一致。项目默认使用mp4v如果失败会尝试 AVI。也可以在configs/config.yaml中修改video.codec例如MJPG或XVID。问题五如何处理摄像头实时检测当前项目主要演示图片和视频文件。要扩展摄像头实时检测可以把cv2.VideoCapture(video_path)改为cv2.VideoCapture(0)然后在循环中读取摄像头帧。界面版可以增加“摄像头模式”按钮但需要注意 Streamlit 对实时视频刷新并不是最强项桌面端可以考虑 PySide6。15. 项目扩展方向这个项目可以继续扩展成多个实用版本。第一可以扩展成停车场车位检测系统。车辆检测只判断车在哪里而车位检测还需要固定车位区域、多边形区域判断和占用状态统计。可以在当前项目的计数线基础上增加 ROI 区域模块。第二可以扩展成道路拥堵分析系统。除了统计通过数量还可以计算单位时间车流量、平均速度、车道密度和拥堵等级。速度估计需要相机标定或像素到实际距离的换算适合做进阶版项目。第三可以接入车牌识别。检测到车辆后再裁剪车辆区域或车牌区域调用 OCR 或车牌识别模型保存车牌号、时间、方向和截图。这类系统适合园区门禁、停车场出入口等场景。第四可以改成 PySide6 桌面软件。很多课程设计或项目展示更喜欢桌面界面可以把VehicleCounterPipeline复用到 PySide6 中增加视频选择、开始检测、停止检测、结果表格、检测记录等功能。第五可以改成 Flask 或 FastAPI 接口服务。后端提供图片上传、视频任务提交、任务状态查询、结果下载接口前端使用 Vue 或普通 HTML 页面展示结果。这样更适合部署到服务器。第六可以训练自定义数据集。COCO 预训练模型适合通用车辆但如果要识别校车、渣土车、危化品车、救护车、消防车等细分类别需要准备数据集并训练自定义模型。训练完成后只要把weights/best.pt放进项目再修改配置即可。16. 总结本文完成了一个基于 YOLO11 ByteTrack 思路的车辆检测跟踪与车流量统计系统。项目不是单纯调用模型而是把检测、跟踪、计数、可视化、导出和 Web 页面组合成一个完整工程。为了保证项目包可以直接运行系统默认提供离线演示模式为了支持真实场景系统保留 YOLO11 权重接入和 ByteTrack 跟踪配置。从学习角度看这个项目适合掌握目标检测系统的基本开发流程模型加载、视频逐帧处理、检测结果解析、目标 ID 跟踪、过线计数、OpenCV 绘图、CSV 导出和 Streamlit 页面展示。从二次开发角度看它可以继续扩展成停车场检测、园区车辆统计、道路拥堵分析、车牌识别、桌面软件和 Web 后台系统。项目已经包含完整源码、运行脚本、配置文件、示例数据、权重说明和运行截图。下载后先运行python run_demo.py确认结果正常再根据需要下载 YOLO11 权重处理真实道路视频。