车辆跟踪、速度估算与距离估算系统

目录

  1. 项目概述
  2. 数据集介绍
  3. 算法原理与实现
  4. 模型训练与评估
  5. 数据库设计
  6. 系统目录结构
  7. 系统界面与功能
  8. 技术详解
  9. 核心代码
  10. 总结

项目演示视频

车辆跟踪、速度估算与距离估算系统

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是一种高效的多目标跟踪算法,其核心创新在于:

  1. 两阶段关联策略:先处理高置信度检测,再处理低置信度检测
  2. 有效处理遮挡:低置信度检测可以匹配被遮挡的目标
  3. 计算效率高:适合实时应用

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的车辆跟踪、速度估算与距离估算系统,主要成果包括:

  1. 高效的车辆检测:基于YOLOv8/v11,GPU加速,处理速度约10ms/帧
  2. 稳定的多目标跟踪:ByteTrack算法,有效处理遮挡和漏检
  3. 准确的速度估算:多方法融合,校准后误差显著降低
  4. 可靠的距离估算:基于单目测距原理,距离范围1-200米
  5. 完整的Web应用:Streamlit界面,支持视频输入、处理、可视化、数据导出
  6. 持久化存储:SQLite数据库,完整记录所有检测结果

10.2 技术创新

  1. ByteTrack两阶段关联:高/低置信度分离处理,提升跟踪稳定性
  2. 自适应权重速度融合:根据运动方向动态调整估算方法权重
  3. 多特征距离估算:融合宽度、高度、位置多种特征
  4. 卡尔曼滤波轨迹平滑:7维状态空间,预测+更新机制

10.3 性能指标

指标 数值
检测速度 ~100 FPS (GPU)
跟踪准确率 >95%
速度估算误差 校准后 <20%
距离估算范围 1-200米
数据库响应 <10ms

10.4 未来改进

  1. 深度学习速度回归:使用神经网络直接回归速度
  2. 多相机融合:支持多视角协同跟踪
  3. ReID特征:引入外观特征提升重识别能力
  4. 边缘部署:优化模型支持嵌入式设备

附录

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. 参考文献

  1. YOLOv8 - Ultralytics
  2. ByteTrack: Multi-Object Tracking by Associating Every Detection Box
  3. VS13 Dataset
  4. Kalman Filter
  5. Streamlit Documentation
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐