You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TensorFlow.js中正确渲染Yolov7检测框至原尺寸图片?

解决YOLOv7 TensorFlow.js检测框映射原图的问题

核心问题分析

你的预处理流程是:将原图补边为正方形(边长为原图宽高中的较大值),再缩放到640x640输入模型。模型输出的检测框坐标基于640x640尺寸,需要逆向还原到原图的1356x904尺寸,关键是先还原到补边后的正方形尺寸,再裁剪到原图实际边界。

正确的检测框映射步骤

  1. 计算缩放因子:补边后的正方形边长 ÷ 模型输入尺寸(640),用于将640x640的检测框还原到补边后的正方形尺寸。
  2. 还原坐标到补边正方形:将模型输出的x1、y1、x2、y2(或x1、y1、width、height)乘以缩放因子。
  3. 裁剪到原图边界:确保还原后的坐标不超出原图的宽高范围(避免补边区域的无效坐标)。

修改后的渲染代码

export const renderBoxes = (
    canvasRef,
    classThreshold,
    boxes_data,
    scores_data,
    classes_data,
    ratios
) => {
    const ctx = canvasRef.getContext("2d");
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // 清空画布

    // 获取原图实际尺寸(画布与原图同尺寸)
    const originalWidth = ctx.canvas.width;
    const originalHeight = ctx.canvas.height;
    const maxSize = Math.max(originalWidth, originalHeight);
    // 计算从640x640还原到补边正方形的缩放因子
    const scaleFactor = maxSize / 640;

    // 字体配置
    const font = `${Math.max(
        Math.round(Math.max(ctx.canvas.width, ctx.canvas.height) / 40),
        14
    )}px Arial`;
    ctx.font = font;
    ctx.textBaseline = "top";

    for (let i = 0; i < scores_data.length; ++i) {
        const klass = labels[classes_data[i]];
        const score = (scores_data[i] * 100).toFixed(1);
  
        // 将模型输出的[x1,y1,w,h]转换为[x1,y1,x2,y2]
        let [x1, y1, x2, y2] = xywh2xyxy(boxes_data[i]);

        // 第一步:还原到补边后的正方形尺寸
        x1 = x1 * scaleFactor;
        y1 = y1 * scaleFactor;
        x2 = x2 * scaleFactor;
        y2 = y2 * scaleFactor;

        // 第二步:裁剪到原图边界,避免超出原图范围
        x1 = Math.max(0, Math.min(x1, originalWidth));
        y1 = Math.max(0, Math.min(y1, originalHeight));
        x2 = Math.max(x1, Math.min(x2, originalWidth));
        y2 = Math.max(y1, Math.min(y2, originalHeight));

        const width = x2 - x1;
        const height = y2 - y1;
  
        // 绘制检测框
        ctx.strokeStyle = "#B033FF";
        ctx.lineWidth = 2;
        ctx.strokeRect(x1, y1, width, height);
  
        // 绘制标签背景
        ctx.fillStyle = "#B033FF";
        const textWidth = ctx.measureText(`${klass} - ${score}%`).width;
        const textHeight = parseInt(font, 10);
        ctx.fillRect(x1 - 1, y1 - (textHeight + 2), textWidth + 2, textHeight + 2);
  
        // 绘制标签文字
        ctx.fillStyle = "#ffffff";
        ctx.fillText(`${klass} - ${score}%`, x1 - 1, y1 - (textHeight + 2));
    }
};

代码说明

  • scaleFactor:补边正方形边长与模型输入尺寸的比值,确保检测框从640x640还原到补边后的原始正方形尺寸。
  • 边界裁剪:通过Math.max和Math.min限制坐标在原图范围内,避免检测框出现在补边的空白区域。
  • 若需保留传入的ratios参数,可通过maxSize = originalWidth * ratios[0]推导补边正方形边长,逻辑一致。

验证示例

以你提供的第一个检测框数据[371.74, 101.13, 19.00, 39.25]为例:

  1. 补边正方形边长maxSize=1356,缩放因子1356/640≈2.11875
  2. 还原后坐标:
    • x1=371.742.11875≈787.6,y1=101.132.11875≈214.3
    • x2=(371.74+19)*2.11875≈828.8,y2=(101.13+39.25)*2.11875≈302.5
  3. 裁剪后坐标完全在1356x904范围内,对应原图的正确位置。

内容的提问来源于stack exchange,提问作者itsisaac19

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:57:02