当前位置:首页 > 技术 > 正文内容

YOLOv10车辆测速实战:Python+OpenCV构建智能交通监控系统

访客 技术 2026年5月26日 3

YOLOv10车辆测速实战:Python+OpenCV构建智能交通监控系统

在现代交通管理中,计算机视觉技术正扮演着越来越重要的角色。利用摄像头和算法实现车辆速度监测,已经从实验室走向了实际应用。本文将通过YOLOv10目标检测模型和OpenCV图像处理库,构建一个可运行的车辆测速系统,整个过程仅需基础Python开发环境即可完成。

1. 环境初始化与模型加载

首先需要搭建Python运行环境。推荐使用虚拟环境来隔离项目依赖,避免与系统其他Python版本产生冲突。以下命令序列用于创建并激活环境:

conda create --name speed_cv python=3.10 --yes
conda activate speed_cv
pip install torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cu118
pip install ultralytics opencv-python-headless==4.8.0

上述命令假设使用CUDA 11.8的GPU环境。若使用CPU版本,可将PyTorch安装命令替换为:

pip install torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu

YOLOv10提供了多种预训练模型,选择取决于计算资源与精度需求:

  • yolov10n.pt:Nano版本,适合边缘设备或实时处理
  • yolov10s.pt:Small版本,精度与速度均衡
  • yolov10m.pt / yolov10l.pt / yolov10x.pt:大型模型,适合服务器级精度需求

加载模型并验证其基本功能:

from ultralytics import YOLO

# 初始化模型(以nano为例)
detector = YOLO('yolov10n.pt')

import cv2
import numpy as np

# 创建随机图像测试模型是否可用
fake_frame = np.random.randint(0, 256, (480, 640, 3), dtype=np.uint8)
output = detector(fake_frame)
print("检测结果:", output[0].boxes)

2. 视频流处理核心

车辆测速需要处理连续的视频帧,而非单张图片。OpenCV的VideoCapture类能高效读取视频文件或摄像头流。以下代码实现视频帧的循环处理:

def analyze_video(source_path, save_path=None):
    """
    读取视频文件,逐帧进行目标检测
    :param source_path: 输入视频路径
    :param save_path: 可选,输出视频路径
    """
    capture = cv2.VideoCapture(source_path)
    if not capture.isOpened():
        raise RuntimeError("无法打开视频源" + source_path)

    # 获取视频参数
    frame_rate = capture.get(cv2.CAP_PROP_FPS)
    frame_width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
    frame_height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))

    if save_path:
        video_writer = cv2.VideoWriter(
            save_path,
            cv2.VideoWriter_fourcc(*'mp4v'),
            frame_rate,
            (frame_width, frame_height)
        )

    while True:
        ret, frame = capture.read()
        if not ret:
            break  # 读取完毕

        # 使用YOLOv10检测
        results = detector(frame)

        # 后续将在此处添加测速逻辑

        if save_path:
            # 将检测结果绘制在帧上
            annotated_frame = results[0].plot()
            video_writer.write(annotated_frame)

        # 显示实时画面(可选)
        cv2.imshow("Detection", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    capture.release()
    if save_path:
        video_writer.release()
    cv2.destroyAllWindows()

# 调用示例
analyze_video("traffic_clip.mp4", "output.mp4")

3. 速度计算原理与实现

计算车辆速度需要两个关键数据:

  • 车辆在画面中的位移量
  • 相邻帧之间的时间差

实际部署时,通常需要在场景中设置一个已知长度的参考物,比如车道标线或固定距离的标记。但作为演示,我们可以简化为利用车辆在画面中的像素位移和帧率估算相对速度。

以下代码实现了基于中心点跟踪的速度估算:

class SpeedTracker:
    def __init__(self, pixels_per_meter=100, fps=30):
        self.pixels_per_meter = pixels_per_meter  # 像素与米的比例
        self.fps = fps
        self.previous_positions = {}  # 存储车辆ID与上一帧位置

    def calculate_speed(self, car_id, current_bbox):
        """
        根据车辆边界框计算速度
        :param car_id: 车辆唯一标识
        :param current_bbox: [x1, y1, x2, y2]
        :return: 速度(公里/小时)或None
        """
        # 计算当前中心点
        current_center_x = (current_bbox[0] + current_bbox[2]) / 2
        current_center_y = (current_bbox[1] + current_bbox[3]) / 2

        if car_id in self.previous_positions:
            prev_x, prev_y = self.previous_positions[car_id]

            # 计算像素位移
            dx = current_center_x - prev_x
            dy = current_center_y - prev_y
            pixel_distance = np.sqrt(dx**2 + dy**2)

            # 转换为实际距离(米)
            real_distance = pixel_distance / self.pixels_per_meter

            # 计算时间间隔(秒)
            time_interval = 1.0 / self.fps

            # 速度(米/秒)
            speed_mps = real_distance / time_interval

            # 转换为公里/小时
            speed_kmh = speed_mps * 3.6

            # 更新位置
            self.previous_positions[car_id] = (current_center_x, current_center_y)
            return speed_kmh
        else:
            # 首次出现,记录位置
            self.previous_positions[car_id] = (current_center_x, current_center_y)
            return None

# 在视频处理循环中使用
tracker = SpeedTracker(pixels_per_meter=100, fps=frame_rate)

while True:
    ret, frame = capture.read()
    if not ret:
        break

    results = detector(frame)
    boxes = results[0].boxes.xyxy.cpu().numpy()
    ids = results[0].boxes.id.cpu().numpy()  # 假设yolo返回ID

    for box, obj_id in zip(boxes, ids):
        speed = tracker.calculate_speed(int(obj_id), box)
        if speed is not None:
            cv2.putText(frame, f"{speed:.1f} km/h", 
                        (int(box[0]), int(box[1])-10),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)

    # 显示和保存帧

注意:上述代码假设YOLOv10输出车辆跟踪ID(通过track方法获得)。实际使用时,需要将detector(frame)改为detector.track(frame, persist=True)来启用跟踪功能。

4. 完整测速系统集成

将所有组件整合到一个函数中:

def speed_monitor_system(video_path, output_path, ref_distance=5.0, ref_pixels=200):
    """
    完整车辆测速系统
    :param video_path: 输入视频路径
    :param output_path: 输出视频路径
    :param ref_distance: 参考距离(米)
    :param ref_pixels: 参考距离对应的像素数
    """
    cap = cv2.VideoCapture(video_path)
    fps = cap.get(cv2.CAP_PROP_FPS)

    # 计算像素每米比例
    ppm = ref_pixels / ref_distance
    tracker = SpeedTracker(pixels_per_meter=ppm, fps=fps)

    # 初始化写入器
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    writer = cv2.VideoWriter(output_path, fourcc, fps,
                             (int(cap.get(3)), int(cap.get(4))))

    while True:
        success, frame = cap.read()
        if not success:
            break

        # 执行跟踪检测
        results = detector.track(frame, persist=True)
        if results[0].boxes is not None and results[0].boxes.id is not None:
            boxes = results[0].boxes.xyxy.cpu().numpy()
            ids = results[0].boxes.id.cpu().numpy()
            cls = results[0].boxes.cls.cpu().numpy()

            for i in range(len(boxes)):
                if cls[i] == 2:  # 只检测车辆(COCO类别中车辆类为2)
                    speed_val = tracker.calculate_speed(int(ids[i]), boxes[i])
                    if speed_val:
                        cv2.putText(frame, f"Speed: {speed_val:.1f} km/h",
                                    (int(boxes[i][0]), int(boxes[i][1])-20),
                                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

        writer.write(frame)
        cv2.imshow("Speed Monitor", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    writer.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    speed_monitor_system("highway.mp4", "highway_speed_output.mp4")

5. 校准与优化提示

实际部署中,测速精度高度依赖场景校准:

  • 参考距离:在画面中标记一段已知长度的道路(如10米),并测量对应像素数
  • 透视校正:车辆在不同纵向位置像素尺度不同,可引入透视变换矩阵进行补偿
  • 稳定跟踪:使用卡尔曼滤波或排序算法减少ID切换带来的速度波动

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。