YOLOv11 车辆跟踪 ROS 功能包

ROS Noetic C++11/14 TensorRT 8.6 CUDA 11.x
版本 0.0.0 · 最后更新 2026-03-20 · 维护者: jiamufengyue

基于 YOLOv11 + TensorRT 的高性能车辆检测与跟踪 ROS 节点,采用多线程流水线和 IoU 跟踪,实时输出可视化结果和 ROS 消息。

📘 概述

yolov11 功能包为 ROS 提供了基于 YOLOv11 的车辆检测与跟踪能力。它利用 TensorRT 对模型进行推理加速,通过多线程架构实现摄像头/视频流的高效处理,并集成了一个轻量级的基于 IoU 的跟踪器,可为每个车辆分配唯一 ID 并绘制运动轨迹。

系统实时发布带有绘制信息的图像话题 (/debug_image) 和可视化 Marker 话题 (/detected_objects),方便集成到更大的自动驾驶或监控系统中。

✨ 核心特性

🚀 TensorRT 加速

使用 FP16/INT8 优化,显著降低推理延迟,提高吞吐量。

🧵 三线程流水线

捕获、推理、显示分离,充分利用 CPU 和 GPU 资源。

🎯 实时 IoU 跟踪

基于 IoU 的轻量级跟踪,为车辆分配稳定 ID,绘制轨迹。

📊 性能监控

实时显示 FPS、处理耗时、跟踪数量等仪表盘。

📡 ROS 原生集成

发布可视化 Marker 和调试图像,易于集成和调试。

📸 多源输入

支持 USB 摄像头、CSI 摄像头、视频文件。

📁 功能包结构

yolov11/
├── CMakeLists.txt          # 编译配置 (CUDA / TensorRT / OpenCV)
├── package.xml             # 功能包清单
├── include/                # 头文件
│   ├── block.h             # 网络模块构建 (C2f, SPPF, C2PSA...)
│   ├── calibrator.h        # INT8 校准器
│   ├── config.h            # 全局配置 (类别数, 阈值, 输入尺寸)
│   ├── cuda_utils.h        # CUDA 错误检查宏
│   ├── logging.h           # TensorRT 日志封装
│   ├── macros.h            # 导出宏 & TRT 版本兼容
│   ├── model.h             # 引擎构建接口 (det/seg/pose/obb)
│   ├── postprocess.h       # 后处理函数 (NMS, 坐标映射)
│   ├── preprocess.h        # CUDA 预处理 (warpaffine)
│   ├── track.h             # 早期跟踪器定义
│   ├── tracker_enhanced.h  # 增强跟踪器 (带关键点)
│   ├── types.h             # Detection 结构体
│   ├── utils.h             # 文件/图像工具
│   └── yololayer.h         # YOLO 插件层
├── src/
│   ├── yolo11_car_ros_node.cpp   # ROS 主节点 (跟踪版本)
│   ├── yolo11_car_tracking.cpp   # (同上, 备份)
│   ├── block.cpp           # 网络层实现
│   ├── calibrator.cpp      # 校准器实现
│   ├── model.cpp           # 引擎构建 (det/seg/pose/obb)
│   ├── postprocess.cpp     # CPU 后处理 (get_rect, nms)
│   ├── postprocess.cu      # CUDA 后处理 (decode, nms 核函数)
│   ├── preprocess.cu       # CUDA warpaffine 预处理
│   └── tracker_enhanced.cpp # 增强跟踪器实现 (带关键点)
├── plugin/
│   ├── yololayer.cu        # YOLO 插件 CUDA 实现 (CalDetection)
│   └── yololayer.h         # 插件声明
└── launch/
    ├── yolo11_tracking.launch    # 车辆跟踪启动文件
    └── yolo_pose_tracking.launch # 姿态跟踪启动文件 (另一项目)

🔧 依赖项

ROS 依赖 (package.xml)

系统依赖

提示: TensorRT 安装后需确保 libnvinfer.so 在链接路径中。CMake 中已包含 /usr/local/cuda 和自定义 TensorRT 路径变量。

⚡ 快速开始

1. 编译功能包

cd ~/catkin_ws/src
git clone <your-repo>/yolov11.git
cd ~/catkin_ws
catkin_make -DCMAKE_BUILD_TYPE=Release
source devel/setup.bash

2. 准备 TensorRT 引擎文件

将训练好的 YOLOv11 模型(.wts)转换为 .engine 文件(可使用 model.cpp 中的构建函数)。假设引擎文件位于 /home/sutpc/car_ws/car.engine

3. 运行节点

# 使用 launch 文件 (摄像头 ID 4, 分辨率 640x480)
roslaunch yolov11 yolo11_tracking.launch

# 或直接运行节点并传递参数
rosrun yolov11 yolo11_car_ros_node _camera_id:=0 _engine_file:=/path/to/your.engine _width:=640 _height:=480

启动后,将显示 OpenCV 窗口 "YOLOv11 Vehicle Tracking",并发布 ROS 话题。

🏗️ 系统架构

🎯 跟踪器 VehicleTracker

轻量级 IoU 跟踪器,维护内部轨迹列表,为每个检测框分配唯一 ID。

数据结构 Track

核心算法

输入:当前帧检测框集合 + 置信度
步骤:

  1. 所有现存轨迹 age++、invisible_count++
  2. 对每个轨迹,与未匹配检测框计算 IoU,选择最大 IoU (>阈值) 作为匹配
  3. 匹配到的检测更新轨迹框、重置 invisible_count、更新轨迹点
  4. 未匹配的检测创建新轨迹
  5. 移除 invisible_count 超过 max_age 的轨迹
返回:活跃轨迹列表 VehicleTrack (包含 ID、框、颜色、轨迹等)

std::vector<VehicleTrack> update(const std::vector<cv::Rect_<float>>& detections, const std::vector<float>& confidences);

🧵 多线程安全队列

使用自定义 ThreadSafeQueue<T> 实现线程间数据传递,内部使用 std::mutexstd::condition_variable

template <typename T>
class ThreadSafeQueue {
    void push(const T& value);
    bool try_pop(T& value);   // 非阻塞
    int size() const;
    bool empty() const;
};

捕获线程和生产线程之间通过 raw_frame_queue 传递 cv::Mat,推理线程和显示线程之间通过 processed_frame_queue 传递 FrameData

📡 ROS 接口

发布话题

话题名类型描述
/detected_objectsvisualization_msgs/MarkerArray包含每个车辆的 3D 框(投影到地面)、轨迹线和 ID 标签。
/debug_imagesensor_msgs/Image带有绘制信息(框、ID、轨迹、性能仪表盘)的图像。

参数 (私有命名空间 ~)

参数名类型默认值说明
engine_filestring/home/sutpc/car_ws/car.engineTensorRT 引擎文件路径
camera_idint4摄像头设备ID (如 /dev/video4)
widthint1280图像宽度
heightint720图像高度
fpsfloat30.0期望帧率
iou_thresholdfloat0.3跟踪匹配的 IoU 阈值
max_lost_framesint30轨迹最大丢失帧数
output_framestring"camera"输出消息的 frame_id

⚙️ TensorRT 集成细节

系统通过以下步骤使用 TensorRT 进行推理:

  1. 反序列化引擎 deserialize_engine() 从 .engine 文件加载。
  2. 准备缓冲区 prepare_buffer() 分配 GPU 输入/输出内存。
  3. 预处理 cuda_preprocess() 执行 warpaffine + BGR→RGB + 归一化 + 通道转换 (NHWC→NCHW)。
  4. 推理 context.enqueueV2() 异步执行。
  5. 后处理 CUDA 核函数 cuda_decode()cuda_nms() 在 GPU 上完成候选框筛选。

所有 CUDA 操作均在同一个流 (cudaStream_t) 中执行,确保异步并发。

📌 关键配置 (config.h)

默认值说明
kUserNumClass8检测类别数 (根据模型修改)
kUserInputSize640模型输入尺寸
kUserConfThresh0.5f检测置信度阈值
kUserNmsThresh0.45fNMS IoU 阈值
kBatchSize1批处理大小 (当前仅支持 1)
kGpuId0使用的 GPU 设备 ID
修改类别数后必须重新构建引擎!

📐 核心类速览

💡 示例:自定义调用

在其他节点中订阅 /debug_image/detected_objects 的示例:

#include <ros/ros.h>
#include <visualization_msgs/MarkerArray.h>
#include <sensor_msgs/Image.h>

void markerCallback(const visualization_msgs::MarkerArray::ConstPtr& msg) {
    ROS_INFO("Received %lu tracked objects", msg->markers.size());
    for (const auto& m : msg->markers) {
        if (m.ns == "tracks") {
            // 处理边界框
        }
    }
}

void imageCallback(const sensor_msgs::Image::ConstPtr& msg) {
    // 显示或处理调试图像
}

int main(int argc, char** argv) {
    ros::init(argc, argv, "custom_listener");
    ros::NodeHandle nh;
    ros::Subscriber sub_marker = nh.subscribe("/detected_objects", 1, markerCallback);
    ros::Subscriber sub_img = nh.subscribe("/debug_image", 1, imageCallback);
    ros::spin();
    return 0;
}

🔍 故障排除

引擎文件加载失败 — 检查路径是否正确,文件是否存在,并确保 TensorRT 版本与编译时一致。
无法打开摄像头 — 检查 camera_id,使用 ls /dev/video* 查看可用设备。
没有检测结果 — 降低 kConfThresh (在 config.h 中) 或检查模型是否适配。
编译时报找不到 nvinfer — 在 CMakeLists.txt 中正确设置 TENSORRT_ROOT 路径。

📊 性能调优建议

❓ 常见问题

Q: 支持哪些 YOLOv11 模型变体?
A: 代码中支持检测(det)、分割(seg)、姿态(pose)、旋转框(obb),当前节点使用检测模型。可通过修改 model.cpp 中的构建函数适配。

Q: 如何修改类别数?
A: 修改 config.h 中的 kUserNumClass,然后重新导出 .wts 并构建引擎。

Q: 是否可以跟踪行人或其他目标?
A: 可以,只需将模型替换为对应的检测模型,并修改 VehicleTrack 中的 type 字段。

📝 更新日志

版本 0.0.1 (2026-03-20)

⚖️ 许可证

TODO — 目前未指定许可证,请在使用前联系维护者。

© 2026 jiamufengyue

© 2026 YOLOv11 Tracking ROS Package · 文档基于实际代码生成