Kornia Boxes3D 的 xyzwhd 模式修复:非对称 3D 框中 width/height/depth 字段顺序的保持与验证
Kornia Boxes3D 的 xyzwhd 模式修复:非对称 3D 框中 width/height/depth 字段顺序的保持与验证
【免费下载链接】kornia🐍 Geometric Computer Vision Library for Spatial AI项目地址: https://gitcode.com/GitHub_Trending/ko/kornia
Boxes3D是 Kornia 中用于表示三维边界框(八顶点六面体)的核心容器,其from_tensor(..., mode="xyzwhd")接口允许以(xmin, ymin, zmin, width, height, depth)格式导入 3D 框。本篇文章聚焦于一项具体的 bug 修复(对应变更片段 changelog.d/+migration-100.fixed.md):修复后,xyzwhd模式在转换非对称盒子(width、height、depth 互不相等)时会严格保留字段顺序,不再发生宽高深度错位。读完本文,你将掌握Boxes3D的坐标表示约定、xyzwhd模式的导入/导出实现原理,以及如何在自定义管线中规避同类字段顺序陷阱。
修复背景:一个 changelog 片段背后的数据表示问题
该修复以 Towncrier 变更片段的形式记录在 changelog.d/+migration-100.fixed.md,全文如下:
Fix
Boxes3D.from_tensor(..., mode="xyzwhd")to preserve width, height, and depth field order for asymmetric boxes. (#4189)
这段文字对应 PR #4189,属于fixed(bug 修复)类别。按仓库的变更管理约定(见 changelog.d/README.md),每个产生用户可见变更的 PR 都会在changelog.d目录下添加一个独立片段文件,命名规则为<PR号>.<类型>.md,最终由 Towncrier 在发版时合并进CHANGELOG.md。+migration-*前缀文件是迁移工作流引入时一次性保留的遗留条目,使用 Towncrier 的 orphan 前缀+以避免重复生成 PR 链接。
要理解这个修复的实际影响,必须回到Boxes3D本身的数据表示与转换逻辑。
Boxes3D 的数据表示与三种输入模式
Boxes3D类定义于 kornia/geometry/boxes.py。与 2D 的Boxes(存储四边形顶点)类似,Boxes3D将每个盒子存储为八顶点六面体,张量形状为(N, 8, 3)或(B, N, 8, 3),顶点顺序为"前上左、前上右、前下右、前下左、后上左、后上右、后下右、后下左"(front-top-left, front-top-right, front-bottom-right, front-bottom-left, 以及相同的四个 back 顶点)。
from_tensor是导入其他表示的入口(kornia/geometry/boxes.py),接受形状(N, 6)或(B, N, 6)的输入,共支持三种模式(模式字符串匹配不区分大小写):
| 模式 | 字段格式 | 尺寸定义 |
|---|---|---|
xyzxyz | xmin, ymin, zmin, xmax, ymax, zmax | width = xmax - xmin(不含端点) |
xyzxyz_plus | xmin, ymin, zmin, xmax, ymax, zmax | width = xmax - xmin + 1(含端点) |
xyzwhd | xmin, ymin, zmin, width, height, depth | 第 3、4、5 个字段直接就是宽、高、深 |
其中xyzwhd是本修复的核心对象:其第 3 个字段是宽度(width),第 4 个是高度(height),第 5 个是深度(depth),对应 x/y/z 三个轴。对于非对称盒子(三个方向尺寸互不相等),一旦这个顺序被打乱,宽高深就会互相错位,且数值上无法察觉——因为三个值本身不同,错位后仍能通过简单的合法性检查。
修复的源码实现:字段顺序的严格保持
在from_tensor中,xyzwhd分支的实现非常直接(kornia/geometry/boxes.py):
elif mode == "xyzwhd": width, height, depth = boxes[..., 3], boxes[..., 4], boxes[..., 5]即从输入张量的第 3、4、5 列分别取出 width、height、depth,然后交给_boxes3d_to_polygons3d(kornia/geometry/boxes.py)构造八顶点六面体。修复确保的正是这一步的映射关系:字段 3 → width,字段 4 → height,字段 5 → depth,三个量在各分支中保持一致的命名与赋值顺序。
对称地,to_tensor(mode="xyzwhd")的导出分支(kornia/geometry/boxes.py)也以相同顺序回写:
elif mode in ("xyzwhd", "vertices", "vertices_plus"): width = boxes[..., 3] - boxes[..., 0] + 1 height = boxes[..., 4] - boxes[..., 1] + 1 depth = boxes[..., 5] - boxes[..., 2] + 1 boxes[..., 3] = width boxes[..., 4] = height boxes[..., 5] = depth导出时先以amin/amax对 8 个顶点求轴对齐包围盒,再换算成含端点的尺寸并回填到字段 3/4/5。导入与导出两侧的顺序约定完全一致,这正是"字段顺序被保留"的保证:from_tensor(x, mode="xyzwhd").to_tensor(mode="xyzwhd")可以精确还原输入。
另一个与该顺序强相关的点是get_boxes_shape(kornia/geometry/boxes.py):
boxes_xyzwhd = self.to_tensor(mode="xyzwhd") widths, heights, depths = boxes_xyzwhd[..., 3], boxes_xyzwhd[..., 4], boxes_xyzwhd[..., 5] return depths, heights, widths它内部正是依赖xyzwhd字段顺序来提取尺寸,然后按(depths, heights, widths)的约定顺序返回。也就是说,xyzwhd的字段顺序一旦出错,会连带污染get_boxes_shape的返回结果,影响所有依赖该方法的几何计算(如to_mask的 mask 尺寸)。这解释了为何该修复的优先级较高:它不只影响显式使用xyzwhd模式的用户。
测试佐证:对称与非对称盒子的回归覆盖
仓库测试 tests/geometry/test_boxes.py 为xyzwhd模式提供了多组回归用例,其中最能体现本次修复价值的是一组非对称盒子测试。
非对称盒子的字段顺序校验
test_convention_from_tensor_xyzxyz_stores_inclusive_front_then_back_vertices(tests/geometry/test_boxes.py)构造了一个三个方向尺寸均不同的盒子:x 从 1 到 5(宽度 4)、y 从 2 到 5(高度 3)、z 从 3 到 8(深度 5),随后断言:
expected_whd = torch.tensor([[1.0, 2.0, 3.0, 4.0, 3.0, 5.0]], device=device, dtype=dtype) self.assert_close(boxes.to_tensor("xyzwhd"), expected_whd, atol=0.0, rtol=0.0)输出严格为[xmin=1, ymin=2, zmin=3, width=4, height=3, depth=5]——width(4)、height(3)、depth(5) 三个互不相同的数值落在正确的字段位置上。如果修复前存在字段顺序错乱(例如 width 与 height 互换),该断言会立即失败,因为 4、3、5 无法与错位后的排列匹配。这正是 changelog 中 "preserve width, height, and depth field order for asymmetric boxes" 的测试级体现:只有非对称盒子才能暴露顺序错误,对称盒子三个值相同,顺序错了也测不出来。
其他 xyzwhd 相关回归
test_boxes_to_tensor(tests/geometry/test_boxes.py):用一组随机化顶点构造六面体,逐一校验xyzxyz、xyzxyz_plus、xyzwhd、vertices、vertices_plus五种导出模式的输出,其中xyzwhd期望输出[[1, 2, 1, 2, 2, 2]]。test_from_tensor(tests/geometry/test_boxes.py):对(1, 6)与(1, 1, 6)两种布局,验证三种模式导入到八顶点表示的结果一致。test_convention_from_tensor_rejects_non_positive_extents_in_mode_convention(tests/geometry/test_boxes.py):验证validate_boxes=True时按各模式自身约定校验正尺寸,如xyzwhd下 width=0 会抛出匹配"widths"的ValueError,而 width=0.5 可正常通过。test_wart_to_tensor_default_mode_ignores_the_stored_label_4251(tests/geometry/test_boxes.py):验证Boxes3D.to_tensor()无参时默认导出xyzxyz,且transform_boxes复制路径会把标签重置为xyzxyz_plus。
此外,tests/geometry/test_boxes.py 中还包含对Boxes3D.from_tensor(x, mode="xyzwhd").data的 gradcheck 验证,说明该路径在可微性上也被纳入了测试保障。
实战要点:正确使用 xyzwhd 模式
结合源码与测试,在实际项目中使用Boxes3D的xyzwhd模式时,有几点值得注意:
1. 明确字段语义。xyzwhd的第 3、4、5 个字段是"尺寸"而非"角点坐标":width = xmax - xmin、height = ymax - ymin、depth = zmax - zmin(不含端点,与xyzxyz的尺寸定义一致,区别于含端点的xyzxyz_plus)。导入示例:
import torch from kornia.geometry.boxes import Boxes3D # 非对称盒子:width=4, height=3, depth=5 boxes = Boxes3D.from_tensor(torch.tensor([[1.0, 2.0, 3.0, 4.0, 3.0, 5.0]]), mode="xyzwhd") print(boxes.data.shape) # (1, 8, 3),内部为八顶点六面体 print(boxes.mode) # "xyzwhd" # 导出可精确还原:第 3/4/5 字段仍为 width/height/depth print(boxes.to_tensor(mode="xyzwhd")) # tensor([[1., 2., 3., 4., 3., 5.]])2. 注意get_boxes_shape的返回顺序。它返回的是(depths, heights, widths),与xyzwhd字段顺序(width, height, depth)不同。如果你的下游代码按"宽、高、深"解包,需要显式调整:
depths, heights, widths = boxes.get_boxes_shape()3. 留意to_tensor的默认导出模式。Boxes3D.to_tensor()无参时默认导出xyzxyz(与 2DBoxes默认导出存储模式不同,这是仓库已知的 API 分歧,见类文档中的 #4251 注释)。若需xyzwhd格式,务必显式传mode="xyzwhd"。
4. 尺寸合法性校验。from_tensor默认validate_boxes=True,会拒绝非有限坐标与按模式约定非正的尺寸;在xyzwhd下 width/height/depth 必须为正(width=0 会报错,width=0.5 合法)。若在导出图捕获(export)场景下,校验会被跳过(源码中通过is_exporting()判断),以便支持图捕获。
小结
Boxes3D的xyzwhd模式修复(#4189)看似只是 changelog 中一行描述,实际修复的是一个隐蔽的数据正确性问题:在 width、height、depth 互不相同的非对称盒子上,字段顺序错位会产生"看似合法、实则错误"的结果,并波及依赖同一顺序的get_boxes_shape等内部逻辑。仓库通过 kornia/geometry/boxes.py 中导入/导出两侧的对称实现,以及 tests/geometry/test_boxes.py 中以非对称盒子为主的回归测试,将这一约定牢牢固定下来。对于在 3D 检测、体素化或空间 AI 管线中使用 KorniaBoxes3D的开发者,理解这一字段顺序约定,是避免宽高深错位类 bug 的第一步。
【免费下载链接】kornia🐍 Geometric Computer Vision Library for Spatial AI项目地址: https://gitcode.com/GitHub_Trending/ko/kornia
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考