博客算法工具链检测框画偏了?把 J6 模型输出的位置还原到原图

检测框画偏了?把 J6 模型输出的位置还原到原图

Sam Hui2026-10-14
55
1

目标检测程序拿到模型输出后,还要做一件事:把框画到原照片上。这里也可能出错——即使模型返回的数字完全没变,只要位置换算写错,框就会跑到旁边。

上一篇排查 NV12 输入时,我检查的是“模型实际读到了什么图片”。这次在 Codex 的协助下,我继续检查后半段:模型在缩小、补边后的图片上给出了位置,程序怎样把这个位置搬回原图?

我保存了真实 J6E 的模型输出,再针对每份输出分别使用按记录还原、漏减补边和错误拉伸三种方式画框。下面这张对比图中,背景相同、模型输出相同,框的位置却明显不同。

alt text

图1|左侧按实际缩放和补边记录还原;中间故意漏减补边;右侧故意按拉伸换算。两个错误版本是受控对照,用来展示接入错误的后果。

这篇要解决的就是这种位置错位:先看它怎样发生,再把缩放和补边参数传给画框代码,最后用保存的输出检查修正结果。

一、为什么不能直接把模型坐标画到原图?

这份 YOLOv5s 要求输入 672×672 的正方形图片,原照片却可能是横图或竖图。SDK 示例的处理方式是保持比例缩小,再在空出的地方补灰边,避免把物体拉变形。

以本轮一张宽 853、高 363 的横图为例:

alt text

图2|真正的图片内容只有672×285,其余是补边。193与194的差别来自整数尺寸分配。

模型返回的位置属于这张带灰边的方形图片,不属于853×363的原照片。

以一个假设的点为例:如果模型坐标中的纵坐标是200,这个200里面,前193行是上方灰边;减去灰边后,它在缩小图片里的纵坐标只有7。再除以纵向缩放比例 285 / 363,才能得到原图中的位置,约为8.9。

如果漏掉减193这一步,直接用200除以缩放比例,就会算出约254.7。同一个点,被画到了完全不同的位置。

检测框由左上角和右下角组成,两端都要做这种还原。

二、修正方法:缩图时记下来,画框时读出来

这次我让预处理多输出一份记录,保存原图尺寸、实际缩放尺寸和四侧补边。后处理直接读取它,不再临时猜图片经历了什么。

刚才那张横图的记录是:

三个尺寸字段按“高、宽”保存,padding_ltrb 按“左、上、右、下”保存,scale_xy 则是横、纵缩放比例。

比例根据实际缩放后的整数尺寸计算:

图片缩放时要取整数尺寸,因此横、纵比例可能略有不同。使用实际尺寸,可以让预处理和坐标还原依据同一份记录。

还原坐标只需要两步:先减补边,再除以缩放比例。

左上角和右下角都使用这组公式。计算中保留浮点数,还原完成后再按原图范围裁剪,最后绘图时才取整。

本轮工具的接入方式如下:

这里的 transform_record 实现本轮的缩放补边规则。自己的程序如果改成裁剪、偏向一侧补边或其他处理,也需要由实际执行步骤产生相应记录。

三、怎样确认变化只来自坐标换算?

实验在 J6E MatrixB 上完成,使用 OE 3.9.1、UCP 3.15.8、HBRT 4.11.11,以及前面已跑通的 KL 校准 YOLOv5s HBM。

我从固定的十张留出图片中按文件名取前八张,每张分别放入横、竖、方三种画布,得到24个视图;随后增加4个专门形成不对称补边的视图。合计是8张原照片、28个构造视图,用于检查不同尺寸的坐标处理。

基础画布的高宽为359×853、853×359和513×513;补充画布为363×853和853×363,后者会产生193/194的不对称补边。照片内容都保持比例放入画布。

上板前,按记录实现的预处理与官方 SDK 生成的 NV12 输入逐字节比较,28组全部一致。随后在板上执行全部视图并保存三个检测头的整数输出;首个案例还单独使用官方工具运行,三个有效输出与自有执行器逐字节一致。

拿到输出后,我按模型的量化参数解码,在672×672模型坐标中统一筛选,并执行一次 NMS(去掉重复检测框),共得到111个框。此后的各个版本都使用这些框,只改变画回原图的公式,不重复推理或重新筛选。

这次为了单独比较坐标还原,固定了模型空间中的筛选和NMS。前面图片应用沿用SDK先还原、裁剪再做NMS的顺序,因此这里的框总数不与上一篇直接比较。

四、两种写错的方法,分别偏了多少?

我比较了四种方法:按实际记录还原、使用SDK示例的理想比例公式,以及故意漏减补边、故意按拉伸换算。

“按拉伸换算”是直接用原图宽高与672的比例调整坐标,相当于假设照片被强行拉成了正方形。实际预处理却保留了长宽比并补边,两者对应不上。

下表均以“按实际记录还原”为比较基准。对每个框的左上、右下四个坐标取最大绝对差,再汇总;在裁剪到图像边界之前计算。

还原方法

全部框中的最大坐标差,像素

每框最大坐标差的平均值,像素

按实际记录还原

0,比较基准

0

SDK示例的理想比例公式

1.243

0.242

故意漏减补边

248.245

140.765

故意按拉伸换算

107.084

42.066

248像素和107像素来自两个故意写错的版本。 SDK示例的理想公式与实际记录在这批图上的差异约为一个像素量级,主要区别是整数尺寸与补边的取法。这张表比较坐标公式,不评价模型识别精度。

方图也有作用:没有补边时,漏减补边或按拉伸换算可能恰好得到相同结果。只用方图检查,错误就可能藏起来;横图、竖图和不对称补边才能走到不同的处理路径。

另外,我在28个视图上各定义3个已知矩形,共84个,先映射到模型画布,再还原回来。按记录映射的最大往返差约为 5.7e-14 像素,接近浮点计算误差。这项检查验证公式的正反变换能否对应,不是目标检测准确率测试。

五、怎样拿去排查自己的程序?

遇到检测框偏移,可以先保存模型输出,检查模型画布上的框,再检查还原到原照片的框。如果前一步位置正常、后一步发生偏移,就重点核对实际缩放尺寸、补边和还原公式。

坐标还原工具、使用说明和真实样例见本文附件。工具只处理已解码的框与变换记录,不加载模型,不需要云板。
解压附件后进入 geometry_tool 目录,环境中需要Python和NumPy,运行:
sample/transform.json 是该图片的处理记录,sample/model_boxes.json 是模型坐标中的框;新生成的 restored.json 是原图坐标。保存的参考结果为 sample/restored_boxes_reference.json,输出文件应使用一个未存在的路径。
接到自己的预处理时,保留同样的数据关系:一张图片的模型输入、输出和变换记录必须对应。 多张图片尺寸不同时,也不能拿上一张的记录还原下一张的框。

这轮解决的是画框位置的接入问题。模型输出没变,错误的坐标解释仍然会改变显示结果。把缩放和补边记录传下去,再用横图、竖图和方图检查,能让这类错误更容易发现和复现。

参考资料

  • OE 3.9.1:samples/onnx_ptq/examples/detection/yolov5x/preprocess.py、postprocess.py,以及 PadResizeTransformer 的实际执行结果。
  • 本轮 geometry_transform.py、28个真实J6E案例、逐例坐标对照及84个已知矩形的往返核对记录。
附件:
算法工具链
社区征文征程6
评论1
0/600
  • Sam Hui
    Lv.2
    附件已上传,但页面似乎没有。坐标还原工具、使用说明和真实样例可从 GitHub仓库 获取。点击 Code → Download ZIP,解压后进入 geometry_tool 目录,按README运行。
    2026-10-14
    0
    0