如何在TensorFlow.js中正确渲染Yolov7检测框至原尺寸图片?
解决YOLOv7 TensorFlow.js检测框映射原图的问题
核心问题分析
你的预处理流程是:将原图补边为正方形(边长为原图宽高中的较大值),再缩放到640x640输入模型。模型输出的检测框坐标基于640x640尺寸,需要逆向还原到原图的1356x904尺寸,关键是先还原到补边后的正方形尺寸,再裁剪到原图实际边界。
正确的检测框映射步骤
- 计算缩放因子:补边后的正方形边长 ÷ 模型输入尺寸(640),用于将640x640的检测框还原到补边后的正方形尺寸。
- 还原坐标到补边正方形:将模型输出的x1、y1、x2、y2(或x1、y1、width、height)乘以缩放因子。
- 裁剪到原图边界:确保还原后的坐标不超出原图的宽高范围(避免补边区域的无效坐标)。
修改后的渲染代码
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]为例:
- 补边正方形边长
maxSize=1356,缩放因子1356/640≈2.11875 - 还原后坐标:
- 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
- 裁剪后坐标完全在1356x904范围内,对应原图的正确位置。
内容的提问来源于stack exchange,提问作者itsisaac19
相关产品推荐
相关产品推荐

