部署:YOLO V11 TensorRT 推理&前后处理

开源地址:github.com/robofans/yolov11_trt_ros2

功能实现:yolov11混合精度量化、ros2部署

1. 整体流程

YOLO V11 推理分为三个阶段:

复制代码
输入图像 → 前处理 → TensorRT 推理 → 后处理 → 检测结果

2. 前处理(Preprocess)

2.1 仿射变换原理

YOLO 前处理只需要缩放 + 平移 (不需要旋转),因此令 b = d = 0

复制代码
x' = a·x + c
y' = e·y + f

其中 a = e = min(dst_h / src_h, dst_w / src_w),取长宽缩放比例中较小的那个,保证图像不变形。

中心对齐:源图中心 (H_s/2, W_s/2) 映射到目标图中心 (H_d/2, W_d/2)

复制代码
c = H_d/2 - s·H_s/2
f = W_d/2 - s·W_s/2

关键思路:从目标图坐标出发,根据仿射变换反推源图坐标,然后用双线性插值获取像素值。

2.2 双线性插值

得到浮点坐标 (src_x, src_y) 后,从四个最近整数像素按面积比例插值:

复制代码
x_low = floor(src_x),  x_high = x_low + 1
y_low = floor(src_y),  y_high = y_low + 1
lx = src_x - x_low,   hx = 1 - lx
ly = src_y - y_low,   hy = 1 - ly

w1 = hy·hx  (左上),  w2 = hy·lx  (右上)
w3 = ly·hx  (左下),  w4 = ly·lx  (右下)

2.3 CUDA 实现

cpp 复制代码
// preprocess.cu - 仿射变换 kernel
__global__ void warpaffine_kernel(
    uint8_t* src, int src_line_size, int src_width, int src_height,
    float* dst, int dst_width, int dst_height,
    uint8_t const_value_st, AffineMatrix d2s, int edge)
{
    int position = blockDim.x * blockIdx.x + threadIdx.x;
    if (position >= edge) return;

    int dx = position % dst_width;
    int dy = position / dst_width;

    // 从目标坐标反推源坐标
    float src_x = d2s.value[0] * dx + d2s.value[1] * dy + d2s.value[2] + 0.5f;
    float src_y = d2s.value[3] * dx + d2s.value[4] * dy + d2s.value[5] + 0.5f;

    // 越界填充灰色
    if (src_x <= -1 || src_x >= src_width || src_y <= -1 || src_y >= src_height) {
        c0 = c1 = c2 = const_value_st;
    } else {
        // 双线性插值
        int y_low = floorf(src_y), x_low = floorf(src_x);
        int y_high = y_low + 1, x_high = x_low + 1;
        float ly = src_y - y_low, lx = src_x - x_low;
        float hy = 1 - ly, hx = 1 - lx;

        float w1 = hy*hx, w2 = hy*lx, w3 = ly*hx, w4 = ly*lx;
        // ... 取四个角点像素 ...
        c0 = w1*v1[0] + w2*v2[0] + w3*v3[0] + w4*v4[0]; // B
        c1 = w1*v1[1] + w2*v2[1] + w3*v3[1] + w4*v4[1]; // G
        c2 = w1*v1[2] + w2*v2[2] + w3*v3[2] + w4*v4[2]; // R
    }

    // BGR→RGB 通道交换
    float t = c2; c2 = c0; c0 = t;

    // 归一化 + CHW 重排
    int area = dst_width * dst_height;
    dst[dy * dst_width + dx] = c0 / 255.0f;                    // R channel
    dst[area + dy * dst_width + dx] = c1 / 255.0f;           // G channel
    dst[2*area + dy * dst_width + dx] = c2 / 255.0f;         // B channel
}

3. TensorRT 推理

3.1 模型输出格式

YOLO V11 输出 (DetectionAttributeSize, NumDetections)

索引 内容
0 cx(中心 x)
1 cy(中心 y)
2 ow(宽)
3 oh(高)
4 ~ 4+num_classes 各类别置信度

NumDetections = 8400(三个输出层下采样之和),DetectionAttributeSize = 84(4 + 80 类)。

4. 后处理(Postprocess)

4.1 解码矩形框

cpp 复制代码
// yolov11.cpp - postprocess()
for (int i = 0; i < det_output.cols; ++i) {
    // 提取类别分数
    const Mat classes_scores = det_output.col(i).rowRange(4, 4 + num_classes);
    Point class_id_point;
    double score;
    minMaxLoc(classes_scores, nullptr, &score, nullptr, &class_id_point);

    if (score > conf_threshold) {
        const float cx = det_output.at<float>(0, i);
        const float cy = det_output.at<float>(1, i);
        const float ow = det_output.at<float>(2, i);
        const float oh = det_output.at<float>(3, i);

        // cx,cy 是中心点,转为左上角坐标
        Rect box;
        box.x = static_cast<int>((cx - 0.5 * ow));
        box.y = static_cast<int>((cy - 0.5 * oh));
        box.width = static_cast<int>(ow);
        box.height = static_cast<int>(oh);

        boxes.push_back(box);
        class_ids.push_back(class_id_point.y);
        confidences.push_back(score);
    }
}

4.2 NMS(非极大值抑制)

cpp 复制代码
// 按置信度降序排序
vector<int> sorted(boxes.size());
iota(sorted.begin(), sorted.end(), 0);
sort(sorted.begin(), sorted.end(),
     [&](int a, int b) { return confidences[a] > confidences[b]; });

vector<bool> suppressed(boxes.size(), false);
for (size_t i = 0; i < sorted.size(); i++) {
    if (suppressed[sorted[i]]) continue;
    nms_result.push_back(sorted[i]);
    for (size_t j = i + 1; j < sorted.size(); j++) {
        if (suppressed[sorted[j]]) continue;
        Rect inter = boxes[sorted[i]] & boxes[sorted[j]];
        float overlap = static_cast<float>(inter.area()) /
            (areas[sorted[i]] + areas[sorted[j]] - inter.area());
        if (overlap > nms_threshold)
            suppressed[sorted[j]] = true;
    }
}

NMS 原理

  1. 按置信度排序
  2. 保留最高置信度的框
  3. 剔除与保留框 IoU > 阈值的框
  4. 重复直到处理完所有框

4.3 坐标映射回原图

cpp 复制代码
// yolov11.cpp - draw()
const float ratio_h = input_h / (float)image.rows;
const float ratio_w = input_w / (float)image.cols;

for (int i = 0; i < output.size(); i++) {
    auto box = output[i].bbox;
    auto class_id = output[i].class_id;

    if (ratio_h > ratio_w) {
        // 宽边对齐,x 方向缩放用 ratio_w
        box.x = box.x / ratio_w;
        box.y = (box.y - (input_h - ratio_w * image.rows) / 2) / ratio_w;
        box.width = box.width / ratio_w;
        box.height = box.height / ratio_w;
    } else {
        // 高边对齐
        box.x = (box.x - (input_w - ratio_h * image.cols) / 2) / ratio_h;
        box.y = box.y / ratio_h;
        box.width = box.width / ratio_h;
        box.height = box.height / ratio_h;
    }

    rectangle(image, Point(box.x, box.y),
              Point(box.x + box.width, box.y + box.height), color, 3);
    putText(image, class_string, Point(box.x, box.y - 10), ...);
}
相关推荐
断眉的派大星3 小时前
YOLO26 完整学习笔记:从 Anchor-Free、TAL、STAL 到端到端无 NMS 部署
人工智能·笔记·学习·yolo·目标检测·计算机视觉·目标跟踪
stsdddd6 小时前
YOLO系列目标检测数据集大全【第十三期】
yolo·目标检测·目标跟踪
动物园猫6 小时前
无人机战场侦察6类军事目标检测数据集分享(适用于YOLO系列深度学习分类检测任务)
yolo·目标检测·无人机
羊羊小栈2 天前
老人摔倒检测系统(基于YOLO姿态估计)
yolo·毕业设计·创业创新·大作业
土星云SaturnCloud2 天前
土星云AI边缘计算SE110S系列模型部署实战-YOLOv5
服务器·人工智能·yolo·docker·边缘计算
YOLO数据集集合2 天前
配电站智能运维|变电一次设备识别|高压电气构件目标检测数据集|电力巡检
运维·人工智能·深度学习·yolo·目标检测·视觉检测
stsdddd2 天前
YOLO系列目标检测数据集大全【第八期】
yolo·目标检测·目标跟踪
YOLO数据集集合2 天前
航拍输电线路故障识别|线路金具缺陷判别|无人机电力巡检故障检测数据集10262期
人工智能·深度学习·yolo·目标检测·视觉检测·无人机
深度学习lover2 天前
<数据集>yolo安全手套佩戴识别<目标检测>
人工智能·yolo·目标检测·数据集·安全手套佩戴识别