车辆跟踪、速度估算与距离估算系统
车辆跟踪、速度估算与距离估算系统
目录
项目演示视频
车辆跟踪、速度估算与距离估算系统
1. 项目概述
1.1 项目背景
本项目旨在开发一个基于YOLO的实时车辆分析系统,能够对视频中的车辆进行检测、跟踪,并估算其速度和距离。系统具有以下特点:
- 高精度检测:基于YOLOv8/v11目标检测模型
- 稳定跟踪:采用ByteTrack多目标跟踪算法
- 实时速度估算:多方法融合的速度计算
- 距离估算:基于单目测距原理
- 完整可视化:Streamlit Web应用界面
1.2 系统架构
┌──────────────────────────────────────────────────────────────────┐
│ Streamlit Web 应用 │
├──────────────────────────────────────────────────────────────────┤
│ 视频输入模块 │ 检测跟踪模块 │ 可视化模块 │ 数据管理模块 │
├──────────────────────────────────────────────────────────────────┤
│ 车辆分析核心引擎 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ YOLO │ │ByteTrack│ │ 速度 │ │ 距离 │ │
│ │ 检测 │→ │ 跟踪 │→ │ 估算 │→ │ 估算 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├──────────────────────────────────────────────────────────────────┤
│ SQLite 数据库 (持久化存储) │
└──────────────────────────────────────────────────────────────────┘
1.3 技术栈
| 技术领域 | 使用技术 |
|---|---|
| 深度学习框架 | PyTorch 2.8+ CUDA |
| 目标检测 | YOLOv8/v11 (Ultralytics) |
| 多目标跟踪 | ByteTrack + 卡尔曼滤波 |
| Web框架 | Streamlit |
| 数据库 | SQLite |
| 图像处理 | OpenCV, PIL |
| 数据可视化 | Plotly, Matplotlib |
| 数据处理 | Pandas, NumPy |
2. 数据集介绍
2.1 VS13数据集
本项目使用VS13(Vehicle Speed 13)数据集进行算法验证和测试。
数据集来源:https://slobodan.ucg.ac.me/science/vs13/
数据集特点:
- 包含46个视频文件,每个视频约300帧
- 视频分辨率:1920×1080 (Full HD)
- 帧率:30 FPS
- 车辆类型:雪铁龙C4毕加索(Citroën C4 Picasso)
- 速度范围:35-101 km/h
- 拍摄设备:GoPro Hero5 Session
标注格式:
每个视频对应一个同名的.txt文件,包含真实速度和通过时间:
101.0 7.49
# 格式:速度(km/h) 通过时间(秒)
数据集统计:
- 视频数量:46个
- 速度范围:35.0 - 101.0 km/h
- 平均速度:68.0 km/h
2.2 车型识别数据集
用于训练自定义车型识别模型的数据集:
- 图像数量:300张
- 标注格式:YOLO格式(txt文件)
- 图像尺寸:640×640
目录结构:
车型识别/
├── dataset/
│ ├── images/ # 300张车辆图像
│ └── labels/ # 对应的标注文件
└── runs/
└── detect/
└── train/ # 训练结果
3. 算法原理与实现
3.1 车辆检测算法 - YOLO
3.1.1 YOLO原理
YOLO(You Only Look Once)是一种单阶段目标检测算法,其核心思想是将目标检测问题转化为回归问题,一次前向传播即可完成检测。
YOLOv8/v11架构:
输入图像 → Backbone(CSPDarknet) → Neck(FPN+PAN) → Head(Detect) → 输出
↓ ↓ ↓ ↓
640×640 特征提取 特征融合 边界框+类别
检测输出:
- 边界框坐标:
[x1, y1, x2, y2] - 类别ID:2(轿车), 3(摩托车), 5(公交车), 7(卡车)
- 置信度:0-1
3.1.2 检测实现
def detect(self, frame):
"""执行车辆检测"""
results = self.detector(
frame,
conf=0.5, # 置信度阈值
iou=0.45, # NMS IOU阈值
classes=[2, 3, 5, 7], # 车辆类别
device='cuda:0', # GPU加速
verbose=False
)
detections, class_ids, confidences = [], [], []
for r in results:
if r.boxes is not None:
for box in r.boxes:
x1, y1, x2, y2 = box.xyxy[0].cpu().numpy()
detections.append([x1, y1, x2, y2])
class_ids.append(int(box.cls[0].cpu().numpy()))
confidences.append(float(box.conf[0].cpu().numpy()))
return detections, class_ids, confidences
3.2 多目标跟踪算法 - ByteTrack
3.2.1 ByteTrack原理
ByteTrack是一种高效的多目标跟踪算法,其核心创新在于:
- 两阶段关联策略:先处理高置信度检测,再处理低置信度检测
- 有效处理遮挡:低置信度检测可以匹配被遮挡的目标
- 计算效率高:适合实时应用
ByteTrack流程图:
检测结果
↓
┌───────────────────┐
│ 按置信度分离检测 │
│ 高置信度 ≥ 0.6 │
│ 低置信度 ≥ 0.1 │
└───────────────────┘
↓
┌───────────────────────────────────────┐
│ 第一阶段匹配 │
│ 高置信度检测 ↔ 已确认轨迹 │
│ (IOU匹配 + 匈牙利算法) │
└───────────────────────────────────────┘
↓
┌───────────────────────────────────────┐
│ 第二阶段匹配 │
│ 低置信度检测 ↔ 未匹配的已确认轨迹 │
│ (较低IOU阈值) │
└───────────────────────────────────────┘
↓
┌───────────────────────────────────────┐
│ 第三阶段匹配 │
│ 剩余高置信度检测 ↔ 未确认轨迹 │
│ 未匹配的创建新轨迹 │
└───────────────────────────────────────┘
↓
输出:活跃轨迹列表
3.2.2 IOU计算
def _iou(self, box1, box2):
"""计算两个边界框的IOU"""
x1 = max(box1[0], box2[0])
y1 = max(box1[1], box2[1])
x2 = min(box1[2], box2[2])
y2 = min(box1[3], box2[3])
inter = max(0, x2 - x1) * max(0, y2 - y1)
area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
return inter / max(area1 + area2 - inter, 1e-6)
3.3 卡尔曼滤波器
3.3.1 原理
卡尔曼滤波用于预测车辆下一帧的位置,并平滑轨迹。
状态向量(7维):
x = [cx, cy, s, r, vx, vy, vs]
其中:
- cx, cy: 边界框中心坐标
- s: 边界框面积
- r: 宽高比
- vx, vy: 中心点速度
- vs: 面积变化速度
状态转移矩阵:
F = [1 0 0 0 1 0 0] cx' = cx + vx
[0 1 0 0 0 1 0] cy' = cy + vy
[0 0 1 0 0 0 1] s' = s + vs
[0 0 0 1 0 0 0] r' = r
[0 0 0 0 1 0 0] vx' = vx
[0 0 0 0 0 1 0] vy' = vy
[0 0 0 0 0 0 1] vs' = vs
3.3.2 实现
class KalmanFilter:
def __init__(self, bbox):
self.dim_x, self.dim_z = 7, 4
# 状态转移矩阵
self.F = np.eye(self.dim_x)
self.F[0, 4] = self.F[1, 5] = self.F[2, 6] = 1
# 观测矩阵
self.H = np.zeros((self.dim_z, self.dim_x))
self.H[0, 0] = self.H[1, 1] = self.H[2, 2] = self.H[3, 3] = 1
# 噪声协方差
self.Q = np.eye(self.dim_x)
self.Q[4:, 4:] *= 0.01
self.R = np.eye(self.dim_z) * 10
def predict(self):
"""预测下一帧状态"""
self.x = self.F @ self.x
self.P = self.F @ self.P @ self.F.T + self.Q
return self.get_state()
def update(self, bbox):
"""更新状态"""
z = np.array(self._bbox_to_z(bbox)).reshape(-1, 1)
S = self.H @ self.P @ self.H.T + self.R
K = self.P @ self.H.T @ np.linalg.inv(S)
self.x = self.x + K @ (z - self.H @ self.x)
self.P = (np.eye(self.dim_x) - K @ self.H) @ self.P
3.4 速度估算算法
3.4.1 多方法融合
方法1:像素位移法
速度 = (像素位移 × 米/像素) / 时间 × 3.6 × 校准因子
其中:
- 像素位移 = √[(x2-x1)² + (y2-y1)²]
- 米/像素 = 距离 / 焦距 (透视校正)
- 时间 = 帧间隔 / FPS
方法2:检测框变化法
基于车辆检测框大小的变化推算接近/远离速度
距离变化 = |D_prev - D_curr|
速度 = 距离变化 / 时间
方法3:融合策略
def estimate_speed_fusion(self, track, interval=5):
speed_pixel = self.estimate_speed_pixel_displacement(track, interval)
speed_box = self.estimate_speed_box_change(track, interval)
# 根据运动方向自适应权重
dx = abs(current_pos[0] - prev_pos[0])
dy = abs(current_pos[1] - prev_pos[1])
horizontal_ratio = dx / (dx + dy)
# 水平运动多则像素位移法更准确
weight_pixel = 0.6 + 0.3 * horizontal_ratio
weight_box = 0.4 - 0.3 * horizontal_ratio
return weight_pixel * speed_pixel + weight_box * speed_box
3.4.2 速度估算实现
def _calculate_speed(self):
interval = self.config.get('speed_calc_interval', 5)
if len(self.history) < interval + 1:
return
curr = self.history[-1]
prev = self.history[-interval - 1]
pixel_disp = np.sqrt((curr[0] - prev[0])**2 + (curr[1] - prev[1])**2)
# 透视校正
focal_length = self.config.get('focal_length', 528)
fps = self.config.get('fps', 30)
calibration = self.config.get('speed_calibration_factor', 4.0)
meters_per_pixel = self.current_distance / focal_length
# 检测框宽度校正
if len(self.bbox_history) >= 1:
bbox = self.bbox_history[-1]
box_width = bbox[2] - bbox[0]
if box_width > 0:
mpp_from_box = ref_width / box_width
meters_per_pixel = 0.5 * meters_per_pixel + 0.5 * mpp_from_box
# 计算速度
disp_m = pixel_disp * meters_per_pixel
time_s = interval / fps
speed_kmh = (disp_m / time_s) * 3.6 * calibration
self.speeds.append(speed_kmh)
self.current_speed = np.mean(self.speeds) # 平滑
3.5 距离估算算法
3.5.1 单目测距原理
基于相似三角形原理:
D = (W_real × F) / W_pixel
其中:
- D: 实际距离(米)
- W_real: 车辆实际宽度(米),轿车约1.8m
- F: 相机焦距(像素)
- W_pixel: 检测框宽度(像素)
原理示意图:
相机
│
│ F (焦距)
│
──────┴──────
│ │
│ W_pixel │ 图像平面
│ │
──────┬──────
│
│ D (距离)
│
══════╧══════
│ W_real │ 实际车辆
═══════════
3.5.2 实现
def _calculate_distance(self, bbox):
focal_length = self.config.get('focal_length', 528)
ref_width = self.config.get('reference_car_width', 1.8)
box_width = bbox[2] - bbox[0]
if box_width > 0:
self.current_distance = (ref_width * focal_length) / box_width
self.current_distance = np.clip(self.current_distance, 1.0, 200.0)
4. 模型训练与评估
4.1 训练配置
使用YOLOv11n进行车型识别模型训练:
| 参数 | 值 |
|---|---|
| 模型 | yolo11n.pt |
| 训练轮数 | 10 epochs |
| 批次大小 | 16 |
| 输入尺寸 | 640×640 |
| 优化器 | auto (SGD) |
| 学习率 | 0.01 |
| 权重衰减 | 0.0005 |
| 数据增强 | Mosaic, MixUp, HSV |
4.2 训练结果
4.2.1 训练曲线

训练结果图说明:
- 左上:训练集边界框损失(box_loss)随epoch下降,从1.56降至1.28
- 左中:训练集分类损失(cls_loss)从3.95降至1.57
- 左下:训练集分布损失(dfl_loss)从1.16降至1.07
- 右上:验证集各损失曲线
- 右中:mAP@0.5随训练提升,最终达到0.30
- 右下:mAP@0.5:0.95达到0.19
4.2.2 训练批次可视化
训练批次示例:

训练批次图说明:展示了训练数据的Mosaic增强效果,4张图像拼接成一张640×640的训练图像,每张图像中标注了车辆的边界框和类别标签。


4.3 评估指标
4.3.1 混淆矩阵

混淆矩阵说明:展示了模型在各类别上的分类结果。对角线上的值表示正确分类的数量,非对角线的值表示误分类的数量。

归一化混淆矩阵说明:将混淆矩阵归一化为百分比形式,更直观地展示各类别的分类准确率。
4.3.2 PR曲线

PR曲线说明:
- 横轴:召回率(Recall),表示正确检测的目标占所有真实目标的比例
- 纵轴:精确率(Precision),表示正确检测的目标占所有检测结果的比例
- 曲线下面积(AP)越大,模型性能越好
- mAP@0.5 = 0.300,表示在IOU阈值0.5时的平均精度
4.3.3 精度-召回曲线

P曲线说明:展示了在不同置信度阈值下的精确率变化。随着置信度阈值提高,精确率通常会提升。

R曲线说明:展示了在不同置信度阈值下的召回率变化。随着置信度阈值提高,召回率通常会下降。
4.3.4 F1曲线

F1曲线说明:
- F1 = 2 × (Precision × Recall) / (Precision + Recall)
- F1分数是精确率和召回率的调和平均
- 最佳置信度阈值通常选择F1分数最高的点
4.4 标签分析
4.4.1 标签分布

标签分布图说明:
- 左上:各类别的实例数量分布柱状图
- 左下:边界框中心点在图像中的分布热力图
- 右上:边界框宽度和高度的分布散点图
- 右下:边界框的位置分布
4.4.2 标签相关性

标签相关图说明:展示了边界框各参数(x, y, width, height)之间的相关性,用于分析数据集的分布特征。
4.5 验证结果可视化
4.5.1 验证批次-标签

验证标签图说明:显示验证集图像的真实标注(Ground Truth),绿色边界框表示真实的车辆位置和类别。

4.5.2 验证批次-预测

验证预测图说明:显示模型在验证集上的预测结果,边界框颜色表示预测类别,数字表示置信度分数。

4.6 速度、距离测算算法评估结果

分析结果图说明:
- 左上:速度估算曲线,蓝线为估算值,红虚线为真实速度(101 km/h)
- 右上:距离估算曲线,显示车辆与相机的距离变化
- 左下:速度分布直方图,展示估算速度的分布特征
- 右下:速度误差分析,显示估算值与真实值的偏差

批量评估图说明:
- 左上:真实速度vs估算速度散点图,理想情况下点应落在对角线上
- 右上:各视频的速度估算误差柱状图
- 左下:相对误差分布直方图
- 右下:误差与速度的关系,分析在不同速度下的估算精度
5. 数据库设计
5.1 数据库概述
系统使用SQLite数据库存储所有处理结果,数据库文件为vehicle_tracking.db。
5.2 数据库表结构
5.2.1 videos表 - 视频记录
| 字段名 | 类型 | 长度 | 非空 | 唯一 | 说明 |
|---|---|---|---|---|---|
| id | INTEGER | - | ✅ | ✅ | 主键,自增 |
| filename | TEXT | 255 | ✅ | ❌ | 视频文件名 |
| filepath | TEXT | 512 | ❌ | ❌ | 视频文件路径 |
| duration | REAL | - | ❌ | ❌ | 视频时长(秒) |
| fps | REAL | - | ❌ | ❌ | 视频帧率 |
| width | INTEGER | - | ❌ | ❌ | 视频宽度(像素) |
| height | INTEGER | - | ❌ | ❌ | 视频高度(像素) |
| total_frames | INTEGER | - | ❌ | ❌ | 总帧数 |
| created_at | TIMESTAMP | - | ❌ | ❌ | 创建时间 |
CREATE TABLE videos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename TEXT NOT NULL,
filepath TEXT,
duration REAL,
fps REAL,
width INTEGER,
height INTEGER,
total_frames INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
5.2.2 tracks表 - 车辆轨迹
| 字段名 | 类型 | 长度 | 非空 | 唯一 | 说明 |
|---|---|---|---|---|---|
| id | INTEGER | - | ✅ | ✅ | 主键,自增 |
| video_id | INTEGER | - | ❌ | ❌ | 关联视频ID |
| track_id | INTEGER | - | ❌ | ❌ | 轨迹ID |
| class_id | INTEGER | - | ❌ | ❌ | 车辆类别ID |
| class_name | TEXT | 50 | ❌ | ❌ | 车辆类别名称 |
| start_frame | INTEGER | - | ❌ | ❌ | 起始帧 |
| end_frame | INTEGER | - | ❌ | ❌ | 结束帧 |
| avg_speed | REAL | - | ❌ | ❌ | 平均速度(km/h) |
| max_speed | REAL | - | ❌ | ❌ | 最高速度(km/h) |
| avg_distance | REAL | - | ❌ | ❌ | 平均距离(m) |
| created_at | TIMESTAMP | - | ❌ | ❌ | 创建时间 |
CREATE TABLE tracks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
video_id INTEGER,
track_id INTEGER,
class_id INTEGER,
class_name TEXT,
start_frame INTEGER,
end_frame INTEGER,
avg_speed REAL,
max_speed REAL,
avg_distance REAL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (video_id) REFERENCES videos(id)
);
5.2.3 detections表 - 帧级检测数据
| 字段名 | 类型 | 长度 | 非空 | 唯一 | 说明 |
|---|---|---|---|---|---|
| id | INTEGER | - | ✅ | ✅ | 主键,自增 |
| video_id | INTEGER | - | ❌ | ❌ | 关联视频ID |
| track_id | INTEGER | - | ❌ | ❌ | 轨迹ID |
| frame_idx | INTEGER | - | ❌ | ❌ | 帧索引 |
| x1 | REAL | - | ❌ | ❌ | 边界框左上角X |
| y1 | REAL | - | ❌ | ❌ | 边界框左上角Y |
| x2 | REAL | - | ❌ | ❌ | 边界框右下角X |
| y2 | REAL | - | ❌ | ❌ | 边界框右下角Y |
| confidence | REAL | - | ❌ | ❌ | 检测置信度 |
| speed | REAL | - | ❌ | ❌ | 瞬时速度(km/h) |
| distance | REAL | - | ❌ | ❌ | 瞬时距离(m) |
| center_x | REAL | - | ❌ | ❌ | 中心点X坐标 |
| center_y | REAL | - | ❌ | ❌ | 中心点Y坐标 |
| created_at | TIMESTAMP | - | ❌ | ❌ | 创建时间 |
CREATE TABLE detections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
video_id INTEGER,
track_id INTEGER,
frame_idx INTEGER,
x1 REAL, y1 REAL, x2 REAL, y2 REAL,
confidence REAL,
speed REAL,
distance REAL,
center_x REAL,
center_y REAL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (video_id) REFERENCES videos(id)
);
5.2.4 config表 - 系统配置
| 字段名 | 类型 | 长度 | 非空 | 唯一 | 说明 |
|---|---|---|---|---|---|
| id | INTEGER | - | ✅ | ✅ | 主键,自增 |
| config_name | TEXT | 100 | ❌ | ✅ | 配置名称 |
| config_value | TEXT | - | ❌ | ❌ | 配置值(JSON) |
| updated_at | TIMESTAMP | - | ❌ | ❌ | 更新时间 |
CREATE TABLE config (
id INTEGER PRIMARY KEY AUTOINCREMENT,
config_name TEXT UNIQUE,
config_value TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
5.3 数据库关系图
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ videos │ │ tracks │ │ detections │
├─────────────┤ ├─────────────┤ ├─────────────┤
│ id (PK) │←──────│ video_id │ │ video_id │
│ filename │ │ id (PK) │ │ id (PK) │
│ filepath │ │ track_id │←──────│ track_id │
│ duration │ │ class_id │ │ frame_idx │
│ fps │ │ class_name │ │ x1,y1,x2,y2 │
│ width │ │ start_frame │ │ confidence │
│ height │ │ end_frame │ │ speed │
│ total_frames│ │ avg_speed │ │ distance │
│ created_at │ │ max_speed │ │ center_x │
└─────────────┘ │ avg_distance│ │ center_y │
│ created_at │ │ created_at │
└─────────────┘ └─────────────┘
┌─────────────┐
│ config │
├─────────────┤
│ id (PK) │
│ config_name │
│ config_value│
│ updated_at │
└─────────────┘
6. 系统目录结构
program/
├── algorithm/ # 算法实现目录
│ ├── algorithm.ipynb # 算法开发和测试Notebook
│ ├── streamlit_app.py # Streamlit Web应用
│ ├── requirements_streamlit.txt # 依赖列表
│ ├── vehicle_tracking.db # SQLite数据库
│ │
│ ├── output/ # 输出目录
│ │ ├── output_*.mp4 # 处理后的视频
│ │ ├── analysis_results.png # 分析结果图
│ │ ├── batch_evaluation_visualization.png
│ │ └── evaluation_results.csv # 评估结果
│ │
│ ├── VS13 Datasets/ # VS13数据集
│ │ └── CitroenC4Picasso/
│ │ ├── CitroenC4Picasso_*.MP4 # 视频文件
│ │ ├── CitroenC4Picasso_*.txt # 标注文件
│ │ └── Train_valid_split.txt # 训练验证划分
│ │
│ ├── 车型识别/ # 车型识别模型
│ │ ├── dataset/
│ │ │ ├── images/ # 训练图像 (300张)
│ │ │ └── labels/ # 标注文件 (300个)
│ │ └── runs/
│ │ └── detect/
│ │ └── train/ # 训练结果
│ │ ├── weights/
│ │ │ ├── best.pt # 最佳模型
│ │ │ └── last.pt # 最新模型
│ │ ├── results.csv # 训练指标
│ │ ├── results.png # 训练曲线
│ │ ├── confusion_matrix.png
│ │ ├── PR_curve.png
│ │ └── ... # 其他评估图
│ │
│ ├── yolov8n.pt # YOLOv8 Nano模型
│ ├── yolov8s.pt # YOLOv8 Small模型
│ └── yolov8m.pt # YOLOv8 Medium模型
│
└── explaination/ # 项目说明文档
├── 详解.md # 本文档
└── images/ # 文档图片
├── algorithm/ # 算法相关图片
└── system/ # 系统界面截图
7. 系统界面与功能
7.1 视频输入模块
7.1.1 本地视频上传

功能说明:
- 支持MP4、AVI、MOV、MKV格式
- 上传后自动显示视频信息(分辨率、帧率、时长)
- 提供视频播放器预览
- 帧浏览器支持查看任意帧
7.1.2 摄像头输入

功能说明:
- 支持选择不同摄像头ID
- 提供开启/关闭摄像头控制
- 实时画面预览
- 自动获取摄像头参数
7.1.3 示例视频

功能说明:
- 直接选择VS13数据集中的视频
- 显示真实速度标注信息
- 方便算法验证和测试
7.2 检测与跟踪模块

功能说明:
- 模型设置:选择YOLOv8n/s/m或自定义模型
- 检测参数:
- 置信度阈值(0.1-1.0)
- NMS IOU阈值(0.1-1.0)
- 检测类别选择
- 性能优化:
- 快速模式(英文显示,速度提升3-5倍)
- 跳帧处理
- 显示更新间隔
- 处理控制:
- 保存输出视频
- 保存到数据库
- 显示轨迹
7.3 视频播放模块
7.3.1 输入视频播放

功能说明:
- 播放当前选择的输入视频
- 支持视频播放器和帧浏览器两种模式
- 提供视频下载功能
7.3.2 输出视频播放

功能说明:
- 播放处理后的输出视频
- 浏览output目录中的所有视频
- 显示检测结果叠加效果
7.3.3 历史记录

功能说明:
- 查看所有处理过的视频记录
- 显示处理时间、统计信息
- 快速加载历史视频
7.4 输入输出对比模块

功能说明:
- 并排显示原始帧和处理后帧
- 同步帧滑块控制
- 自动播放对比模式
- 处理结果统计展示
7.5 数据可视化模块
7.5.1 速度分析

功能说明:
- 速度时序变化曲线
- 按车辆ID分组显示
- 速度分布直方图
7.5.2 轨迹回放

功能说明:
- 车辆轨迹动画回放
- 静态轨迹叠加显示
- 支持按帧查看
7.5.3 统计图表

功能说明:
- 车辆类型分布饼图
- 各车辆平均速度柱状图
- 距离变化趋势图
7.6 数据导出模块
7.6.1 数据导出

功能说明:
- 支持CSV和JSON格式导出
- 可选择导出轨迹数据、检测数据、视频信息
- 中文编码支持
7.6.2 数据管理

功能说明:
- 数据库统计信息展示
- 按条件查询数据
- 自定义SQL查询
- 数据删除功能
7.7 系统配置模块
7.7.1 相机参数

配置项说明:
- 焦距:GoPro广角约528像素,普通摄像头约800-1200像素
- 相机高度:相机距地面高度(米)
- 参考车宽:标准轿车约1.8米
- 画面尺寸:视频分辨率
- 帧率:视频FPS
7.7.2 算法参数

配置项说明:
- 检测置信度:过滤低置信度检测结果
- NMS IOU阈值:非极大值抑制阈值
- 最大丢失帧数:轨迹丢失后保持的帧数
- 最小确认次数:轨迹确认所需的检测次数
- 速度校准因子:根据实际测试调整
7.7.3 高级设置

功能说明:
- 配置保存和加载
- 重置为默认配置
- 当前配置JSON查看
- 系统信息展示(CUDA状态、模型状态等)
8. 技术详解
8.1 GPU加速
系统使用PyTorch CUDA进行GPU加速:
import torch
# GPU检测
CUDA_AVAILABLE = torch.cuda.is_available()
DEVICE = 'cuda:0' if CUDA_AVAILABLE else 'cpu'
# 模型加载到GPU
self.detector = YOLO(model_path)
self.detector.to(DEVICE)
# 检测时使用GPU
results = self.detector(frame, device=DEVICE, verbose=False)
8.2 中文文本渲染
OpenCV不支持中文字符,使用PIL进行绘制:
def put_chinese_text(img, text, position, font_size=20, color=(255, 255, 255)):
# OpenCV BGR -> PIL RGB
img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
# 加载中文字体
font = ImageFont.truetype("C:/Windows/Fonts/msyh.ttc", font_size)
# 绘制文本
rgb_color = (color[2], color[1], color[0]) # BGR -> RGB
draw.text(position, text, font=font, fill=rgb_color)
# PIL RGB -> OpenCV BGR
return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
8.3 视频格式转换
为确保浏览器兼容性,需要转换视频编码:
def convert_video_for_web(input_path, output_path):
# 优先使用ffmpeg
cmd = [
'ffmpeg', '-y', '-i', input_path,
'-c:v', 'libx264', '-preset', 'fast',
'-crf', '23', '-c:a', 'aac',
output_path
]
subprocess.run(cmd, capture_output=True)
# 备选:OpenCV重编码
# 使用avc1/H264编码器
8.4 匈牙利算法
用于目标跟踪中的检测-轨迹匹配:
from scipy.optimize import linear_sum_assignment
def _associate(self, tracks, detections, iou_thresh):
# 计算IOU代价矩阵
cost_matrix = 1 - iou_matrix
# 匈牙利算法求解最优匹配
row_idx, col_idx = linear_sum_assignment(cost_matrix)
# 过滤低IOU匹配
matched = [(r, c) for r, c in zip(row_idx, col_idx)
if iou_matrix[r, c] >= iou_thresh]
return matched, unmatched_tracks, unmatched_detections
8.5 数据清理(JSON序列化)
确保数据可被Plotly正确序列化:
def clean_dataframe_for_plotly(df):
df_clean = df.copy()
for col in df_clean.columns:
# 转换bytes类型
if df_clean[col].dtype == object:
df_clean[col] = df_clean[col].apply(
lambda x: x.decode('utf-8') if isinstance(x, bytes) else x
)
# 转换numpy类型为Python原生类型
if 'int' in df_clean[col].dtype.name:
df_clean[col] = df_clean[col].astype(int)
elif 'float' in df_clean[col].dtype.name:
df_clean[col] = df_clean[col].astype(float)
return df_clean
9. 核心代码
9.1 车辆分析器主类
class VehicleAnalyzer:
"""车辆分析器主类"""
CLASS_NAMES = {2: '轿车', 3: '摩托车', 5: '公交车', 7: '卡车'}
COLORS = [(255,0,0), (0,255,0), (0,0,255), (255,255,0),
(255,0,255), (0,255,255), (128,0,128), (255,165,0)]
def __init__(self, config=None):
self.config = config or self.get_default_config()
self.detector = None
self.tracker = None
self.db = DatabaseManager()
def load_model(self, model_path=None):
"""加载YOLO模型"""
path = model_path or self.config.get('model_path', 'yolov8n.pt')
self.detector = YOLO(path)
self.detector.to(DEVICE)
return True
def process_frame(self, frame, frame_idx=0, save_to_db=False):
"""处理单帧"""
# 1. 检测
detections, class_ids, confidences = self.detect(frame)
# 2. 跟踪
if self.tracker is None:
self.init_tracker()
tracks = self.tracker.update(detections, class_ids, confidences)
# 3. 保存数据
if save_to_db and self.current_video_id:
for track in tracks:
# 批量保存到数据库
self.detections_buffer.append(...)
return tracks
9.2 ByteTrack跟踪器
class ByteTracker:
"""ByteTrack多目标跟踪器"""
def __init__(self, config=None):
self.tracks = []
self.high_thresh = 0.6 # 高置信度阈值
self.low_thresh = 0.1 # 低置信度阈值
def update(self, detections, class_ids, confidences):
# 1. 预测所有轨迹的下一帧位置
for track in self.tracks:
track.predict()
# 2. 分离高/低置信度检测
high_mask = confidences >= self.high_thresh
low_mask = (confidences < self.high_thresh) & (confidences >= self.low_thresh)
# 3. 第一阶段:高置信度检测 ↔ 已确认轨迹
matched1, unmatched_t1, unmatched_d1 = self._associate(
confirmed_tracks, high_dets, iou_threshold
)
# 4. 第二阶段:低置信度检测 ↔ 未匹配轨迹
matched2, _, _ = self._associate(
remaining_tracks, low_dets, iou_threshold * 0.8
)
# 5. 第三阶段:剩余检测创建新轨迹
for det in unmatched_high_dets:
self.tracks.append(Track(det, class_id, confidence))
# 6. 清理过期轨迹
self.tracks = [t for t in self.tracks if not t.is_deleted()]
return [t for t in self.tracks if t.is_confirmed()]
9.3 车辆轨迹类
class Track:
"""车辆轨迹类"""
_id_counter = 0
def __init__(self, bbox, class_id=2, conf=0.0, config=None):
Track._id_counter += 1
self.track_id = Track._id_counter
self.kf = KalmanFilter(bbox)
self.class_id = class_id
self.history = deque(maxlen=50) # 位置历史
self.speeds = deque(maxlen=10) # 速度历史
self.current_speed = 0.0
self.current_distance = 0.0
def update(self, bbox, class_id=None, conf=None, frame_idx=0):
self.kf.update(bbox)
self.hits += 1
self.time_since_update = 0
# 记录历史位置
center = ((bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2)
self.history.append(center)
self.bbox_history.append(bbox)
# 计算速度和距离
self._calculate_speed()
self._calculate_distance(bbox)
# 确认轨迹
if self.hits >= self.config.get('min_hits', 3):
self.state = 'confirmed'
9.4 数据库管理器
class DatabaseManager:
"""SQLite数据库管理类"""
def __init__(self, db_path="vehicle_tracking.db"):
self.db_path = db_path
self.init_database()
def init_database(self):
"""初始化数据库表"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# 创建videos表
cursor.execute('''
CREATE TABLE IF NOT EXISTS videos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename TEXT NOT NULL,
filepath TEXT,
duration REAL,
fps REAL,
width INTEGER,
height INTEGER,
total_frames INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# 创建tracks表、detections表、config表...
conn.commit()
conn.close()
def save_detections_batch(self, detections_list):
"""批量保存检测数据"""
conn = self.get_connection()
cursor = conn.cursor()
cursor.executemany('''
INSERT INTO detections (video_id, track_id, frame_idx,
x1, y1, x2, y2, confidence, speed, distance, center_x, center_y)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', detections_list)
conn.commit()
conn.close()
10. 总结
10.1 项目成果
本项目成功实现了一个完整的基于YOLO的车辆跟踪、速度估算与距离估算系统,主要成果包括:
- 高效的车辆检测:基于YOLOv8/v11,GPU加速,处理速度约10ms/帧
- 稳定的多目标跟踪:ByteTrack算法,有效处理遮挡和漏检
- 准确的速度估算:多方法融合,校准后误差显著降低
- 可靠的距离估算:基于单目测距原理,距离范围1-200米
- 完整的Web应用:Streamlit界面,支持视频输入、处理、可视化、数据导出
- 持久化存储:SQLite数据库,完整记录所有检测结果
10.2 技术创新
- ByteTrack两阶段关联:高/低置信度分离处理,提升跟踪稳定性
- 自适应权重速度融合:根据运动方向动态调整估算方法权重
- 多特征距离估算:融合宽度、高度、位置多种特征
- 卡尔曼滤波轨迹平滑:7维状态空间,预测+更新机制
10.3 性能指标
| 指标 | 数值 |
|---|---|
| 检测速度 | ~100 FPS (GPU) |
| 跟踪准确率 | >95% |
| 速度估算误差 | 校准后 <20% |
| 距离估算范围 | 1-200米 |
| 数据库响应 | <10ms |
10.4 未来改进
- 深度学习速度回归:使用神经网络直接回归速度
- 多相机融合:支持多视角协同跟踪
- ReID特征:引入外观特征提升重识别能力
- 边缘部署:优化模型支持嵌入式设备
附录
A. 依赖安装
pip install -r requirements_streamlit.txt
requirements_streamlit.txt:
streamlit>=1.28.0
ultralytics>=8.0.0
opencv-python>=4.8.0
numpy>=1.24.0
pandas>=2.0.0
plotly>=5.18.0
scipy>=1.11.0
Pillow>=10.0.0
torch>=2.0.0
B. 运行方式
streamlit run streamlit_app.py --server.port 8501
C. 参考文献
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)