krishna8399/traffic-tracking-analytics
GitHub: krishna8399/traffic-tracking-analytics
一个基于YOLOv8和ByteTrack的多目标交通跟踪与分析系统,用于实时监控视频流中的车辆并生成计数、速度和热图等统计数据。
Stars: 2 | Forks: 0
## 标题:交通跟踪分析
表情符号:🚗
起始颜色:蓝色
结束颜色:靛蓝色
SDK:gradio
SDK版本:5.25.0
应用文件:app.py
置顶:否
许可证:MIT
简短描述:YOLOv8 + ByteTrack 车辆检测、跟踪与分析
# 多目标交通跟踪与分析
[](https://github.com/krishna8399/traffic-tracking-analytics/actions/workflows/ci.yml)
[](https://python.org)
[](https://docs.ultralytics.com)
[](https://fastapi.tiangolo.com)
[](https://docker.com)
[](LICENSE)
一个生产级的交通分析系统,使用 YOLOv8 检测车辆和行人,通过 ByteTrack 在连续帧间进行跟踪,计算实时分析数据(车辆计数、速度估算、交通密度热力图),并通过 FastAPI 后端和交互式 Streamlit 仪表板提供所有服务。
## 演示

*YOLOv8n + ByteTrack 在英国高速公路录像上实时运行——6 秒片段,12 fps。跟踪 ID 在部分遮挡下保持不变;轨迹尾显示最近 30 帧。*
## 样本输出
**多车道车辆检测与跟踪——英国高速公路,黄昏,2560×1440**
*绿色框 = 汽车 · 橙色 = 卡车 · 蓝色 = 摩托车 · 标签显示跟踪 ID 和置信度*
**交通密度热力图**(60 秒片段,衰减系数 = 0.98):

*热点对应主要行车道;硬路肩保持冷区。*
## 架构
```
┌─────────────────────────────────────────────────────────────────┐
│ INPUT │
│ Video file (MP4/AVI/MOV) or RTSP stream │
└───────────────────────────┬─────────────────────────────────────┘
│ BGR frames (2560×1440)
▼
┌─────────────────────────────────────────────────────────────────┐
│ DETECTION — src/detection/detector.py │
│ │
│ YOLOv8n (COCO pretrained) │
│ • Letterbox-resize → 640×640 │
│ • Single-shot inference + NMS │
│ • Class filter: person, bicycle, car, motorcycle, bus, truck │
│ • Output: List[Detection(bbox, confidence, class)] │
└───────────────────────────┬─────────────────────────────────────┘
│ N detections per frame
▼
┌─────────────────────────────────────────────────────────────────┐
│ TRACKING — src/tracking/byte_tracker.py │
│ │
│ ByteTrack (two-stage IoU matching) │
│ • Kalman filter predicts position during occlusion │
│ • Stage 1: high-conf dets → all tracks (thresh = 0.4 IoU) │
│ • Stage 2: low-conf dets → unmatched tracks │
│ • States: TENTATIVE (< 3 hits) → CONFIRMED → LOST → deleted │
│ • Output: List[Track(id, class, bbox, trajectory, state)] │
└──────────────┬────────────────────────────────┬─────────────────┘
│ confirmed tracks │
┌───────▼──────────┐ ┌─────────▼────────────────┐
│ COUNTING │ │ SPEED ESTIMATION │
│ counter.py │ │ speed.py │
│ │ │ │
│ Virtual lines │ │ Pixel displacement │
│ Cross-product │ │ × px/m constant │
│ direction check │ │ ÷ Δt (fps) │
│ Counted-IDs set │ │ 5-frame smoothing window │
└───────┬──────────┘ └─────────┬────────────────┘
│ │
┌───────▼──────────────────────────────▼─────────────────┐
│ HEATMAP GENERATOR — heatmap.py │
│ │
│ 64×48 accumulation grid, exponential decay (α = 0.98) │
│ Mapped to hot colormap and overlaid on frame │
└───────────────────────────┬────────────────────────────┘
│ annotated frames + metrics
┌──────────────▼──────────────────────────────┐
│ SERVING │
│ │
│ FastAPI :8000 — REST API (upload → JSON) │
│ Streamlit :8501 — Live dashboard │
└──────────────────────────────────────────────┘
```
## 结果
在 60 秒英国高速公路片段上进行基准测试,2560×1440 @ 30 fps。
| 指标 | 值 |
|--------|-------|
| 处理 FPS — GTX 1650 (GPU) | ~45 fps |
| 处理 FPS — CPU (无 GPU) | 17.4 fps |
| 每帧毫秒数 — GPU | ~22 ms |
| 每帧毫秒数 — CPU | 57.3 ms |
| 源视频分辨率 | 2560 × 1440 |
| YOLO 输入尺寸 (letterboxed) | 640 × 640 |
| 60 秒片段中的跟踪对象 | ~80 个唯一 ID |
| 每帧平均可见车辆数 | 12–18 |
## 快速开始
### 选项 1:Docker (CPU)
```
docker-compose up --build
# API:http://localhost:8000/docs
# 仪表板:http://localhost:8501
```
### 选项 2:Docker (GPU — GTX 1650 / 任意 NVIDIA)
```
# 需要:NVIDIA Container Toolkit
docker-compose --profile gpu up --build
```
### 选项 3:本地运行
```
conda create -n traffic-track python=3.10 -y
conda activate traffic-track
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124
pip install -r requirements.txt
# 在视频上运行完整流水线
python scripts/run_pipeline.py --video assets/sample_videos/traffic.mp4 --output results/
# API 服务器
uvicorn src.api.main:app --reload --port 8000
# 仪表板(单独终端)
streamlit run src/dashboard/app.py
```
## 项目结构
```
traffic-tracking-analytics/
├── README.md
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── .flake8
├── .github/
│ └── workflows/
│ └── ci.yml # pytest + flake8 on every push; Docker smoke test on main
├── configs/
│ ├── detector.yaml # YOLOv8 model, confidence / IoU thresholds, target classes
│ ├── tracker.yaml # ByteTrack parameters
│ └── analytics.yaml # Counting lines, speed calibration, heatmap settings
├── src/
│ ├── detection/
│ │ ├── detector.py # YOLOv8 wrapper — class filtering, batch inference
│ │ └── model_utils.py # Model loading, benchmarking helpers
│ ├── tracking/
│ │ ├── byte_tracker.py # Two-stage ByteTrack with Kalman IoU matching
│ │ ├── track.py # Track dataclass — state machine + Kalman filter
│ │ ├── kalman_filter.py # Constant-velocity Kalman (8-D state, 4-D measurement)
│ │ └── trajectory.py # Trajectory storage and smoothing
│ ├── analytics/
│ │ ├── counter.py # Virtual-line crossing counter (cross-product method)
│ │ ├── speed.py # Speed estimation from pixel displacement
│ │ ├── heatmap.py # Exponential-decay traffic density heatmap
│ │ └── zone.py # Zone-based occupancy tracking (optional)
│ ├── api/
│ │ ├── main.py # FastAPI app — lifespan, endpoints, pipeline orchestration
│ │ └── schemas.py # Pydantic request/response models
│ └── dashboard/
│ └── app.py # Streamlit dashboard — tabs: overview, timeline, classes, heatmap
├── scripts/
│ ├── run_pipeline.py # CLI entry point for offline video processing
│ ├── download_sample.py # Download sample traffic videos
│ └── benchmark.py # FPS and latency benchmarking
├── tests/
│ ├── test_detector.py # 20 tests — class filtering, thresholds, batch, mock YOLO
│ ├── test_tracker.py # 34 tests — lifecycle, Kalman, two-stage matching
│ ├── test_counter.py # 37 tests — crossing, direction, double-count prevention
│ ├── test_speed.py # 20 tests — pixel→km/h conversion, smoothing, cap
│ ├── test_heatmap.py # 27 tests — grid shape, decay, render, overlay, reset
│ └── test_api.py # 9 tests — FastAPI endpoints, schema validation
├── assets/
│ ├── demo.gif # 6-second animated demo (720p, 12fps)
│ ├── test_detection_001.jpg # Sample annotated frame (cars, trucks)
│ ├── test_detection_002.jpg
│ ├── test_detection_003.jpg
│ ├── test_detection_004.jpg
│ └── test_detection_005.jpg
└── results/
├── traffic_tracked.mp4 # Full annotated output video (60 s, 2560×1440)
└── traffic_heatmap.png # 60-second density heatmap
```
## 技术栈
| 层级 | 技术 |
|-------|-----------|
| 检测 | YOLOv8n (Ultralytics), 在 COCO 上预训练 |
| 跟踪 | ByteTrack + 恒速卡尔曼滤波器 |
| 分析 | NumPy, OpenCV |
| API | FastAPI, Pydantic, uvicorn |
| 仪表板 | Streamlit, Plotly |
| 部署 | Docker, docker-compose (CPU + GPU 配置) |
| CI | GitHub Actions — pytest, flake8, Docker 冒烟测试 |
| 视频 I/O | OpenCV, ffmpeg |
## 局限性
### 速度估算需要近乎俯视的摄像机角度
估算器使用固定的 `pixels_per_meter` 常量(`configs/analytics.yaml`)将像素位移转换为公里/小时。只有当摄像机直接架设在道路上方时,这才是有效的近似。对于像样本片段这样的侧面角度录像,透视畸变意味着远处的车辆在每米距离上移动的像素数少于近处的车辆——估算器会低估远处物体的速度,高估近处物体的速度。对于中等角度(~45° 以上),4 点单应性校准可以减少误差,但浅角摄像机(< 30° 仰角)完全违反了地面平面假设。**将非俯视录像中的速度数据仅视为指示性数据。**
### 可靠的指标需要相机校准
如果没有场景中真实校准目标测得的 `pixels_per_meter` 值,所有速度和距离数据都只是估算。校准方法:
1. 将两个已知距离的标记物(例如,英国的车道标线通常相距 3 米)放置在摄像机的视野范围内。
2. 在有代表性的帧中测量它们之间的像素距离。
3. 在 `configs/analytics.yaml` 中将 `pixels_per_meter` 设置为 `pixel_distance / real_distance`。
4. 为了进行透视校正,使用四个地面平面控制点运行 `scripts/calibrate_perspective.py` 来计算单应性矩阵。
### 密集交通中的跟踪失败
ByteTrack 在帧间为每个检测结果分配一个 ID,但在密集的高速公路上,以下三种情况会导致持续失败:
- **遮挡级联。** 当三辆或更多车辆同时重叠时(例如,一辆卡车在相邻车道超越两辆汽车),内部车辆的卡尔曼预测边界框在表观尺寸上缩小,可能不再与任何检测结果重叠。所有三个跟踪会同时变为 LOST 状态,当车辆分开时,跟踪器会生成三个新的 ID——从而夸大总计数。
- **变道时的 ID 切换。** 变道车辆穿过相邻车辆的预测轨迹。如果它们的边界框即使短暂重叠(IoU > 0.4),匈牙利算法可能在该帧交换它们的 ID。这种交换通常是永久的,因为卡尔曼滤波器已经采用了彼此的速度。5 帧速度平滑窗口部分掩盖了由此产生的速度峰值,但无法完全消除。
- **帧边缘的漏检。** 部分在画面外的车辆可见边界框较小,YOLO 置信度较低,通常低于 0.35 的置信度阈值。它们被间歇性检测到,导致快速的 TENTATIVE → (漏检) → 新 TENTATIVE → CONFIRMED 循环,在穿越边缘虚拟线时产生虚假计数。
在 `configs/detector.yaml` 中将 `yolov8n` 升级到 `yolov8s` 或 `yolov8m` 可以提高部分可见和遮挡车辆的召回率,但会降低吞吐量(在 GTX 1650 上,每提升一级模型尺寸大约减少 30 fps)。
### YOLOv8n 的精度权衡
该流程使用 nano YOLO 模型以追求速度。在样本高速公路片段上,nano 模型大约遗漏了远车道中每 8 辆车中的 1 辆(表观尺寸小,黄昏时低对比度)。切换到 `yolov8s.pt` 可以恢复大部分这些检测结果,但推理时间大约是原来的 2 倍。
## 经验总结
**卡尔曼滤波器是让跟踪感觉“真实”的关键。** 没有卡尔曼预测,IoU 匹配在车辆部分遮挡的瞬间就会失败——边界框缩小,与任何检测结果的 IoU 都会降至阈值以下。一旦我添加了基于预测的匹配(使用 `track.predicted_bbox` 而不是 `track.bbox` 来计算 IoU),跟踪器就能在不丢失 ID 的情况下,跨越桥墩和车道变化等 10-15 帧的间隙。恒速模型是最简单的可行方案;通常也足够了。
**ByteTrack 的两阶段设计解决了一个实际问题。** 标准方法——丢弃低置信度检测结果——恰恰在你最需要保留 ID 时丢失了严重遮挡的车辆。第二阶段捕获这些低置信度检测结果,并仅将它们路由到尚未匹配的跟踪轨迹,因此它们不会污染新创建的轨迹。从头实现这个设计让我对它的理解比单纯阅读论文要深刻得多。
**围绕计算机视觉管道构建生产级 API 暴露了你原本不会测试的边缘情况。** FastAPI 中的生命周期模式(启动时加载一次模型,跨请求复用)事后看来很明显,但最初的实现是在每次 `/analyze` 调用时重新加载 YOLOv8 权重——每次请求有 2 秒的延迟。跟踪器的 `global` 状态也需要在视频之间调用 `reset()`,这是我直到第二个上传的视频仍然显示第一个视频中的车辆被跟踪时才发现的。
**没有校准的速度估算只是装饰,而非测量。** 我在真实录像上运行之前构建了完整的像素位移→公里/小时管道,结果发现数字偏差了三倍。我使用的摄像机角度大约与水平线成 25°——对于地面平面假设来说太浅了。教训是:在将数字输出接入仪表板之前,要根据真值验证它们。
**在高分辨率下,CPU 与 GPU 的吞吐量差距比我预期的更大。** 在 640×640(YOLO 的默认输入)下,CPU 的瓶颈在于推理(~50 帧/秒)。在 2560×1440 的源分辨率下,瓶颈部分转移到了预处理(letterbox 缩放和归一化),这在 CPU 上额外消耗 10-15 毫秒,但在 GPU 上几乎免费。结果是,在更高分辨率下,GPU 的加速倍数比仅推理基准测试所暗示的更大。
**在正确的层级进行模拟可以使测试快速且可靠。** 在张量层级模拟 `YOLO.__call__`(使 `.cpu().numpy()` 返回已知数组)让我能够在不加载模型权重的情况下测试所有包装器的过滤和格式化逻辑。模拟任何更高层级——例如模拟 `VehicleDetector.detect`——将使类别过滤代码无法被测试。
## 作者
**Krishna Singh** — 柏林 IU 大学人工智能硕士
- GitHub: [@krishna8399](https://github.com/krishna8399)
- LinkedIn: [krishna839](https://linkedin.com/in/krishna839)
## 许可证
MIT — 详见 [LICENSE](LICENSE)。
标签:AV绕过, ByteTrack, Docker, FastAPI, Kubernetes, Python, Streamlit, YOLOv8, 交互式仪表板, 交通分析, 交通流量分析, 交通监控, 人工智能, 代码示例, 多目标检测, 安全防御评估, 实时分析, 密度热图, 数据分析, 无后门, 智能交通系统, 深度学习, 热图可视化, 用户模式Hook绕过, 目标跟踪, 视频分析, 计算机视觉, 访问控制, 请求拦截, 车辆计数, 车辆跟踪, 逆向工具, 速度估计