Kornia 视频框修复解析:VideoBoxes.get_boxes_shape()与to_mask()的TypeError消除(migration-042)
【免费下载链接】kornia🐍 空间人工智能的几何计算机视觉库项目地址: https://gitcode.com/kornia/kornia
导读
本文围绕 kornia 仓库changelog.d/+migration-042.fixed.md记录的一次关键修复展开:此前在视频增广管线中调用VideoBoxes.get_boxes_shape()与VideoBoxes.to_mask()会稳定抛出TypeError,导致AugmentationSequential为视频框输入构建的容器链路不可用。修复后,这两个继承自Boxes的方法可以正常工作,且不改变任何既有合法调用的结果。读完本文,你将理解 bug 的根因、修复的最小改动原则,以及它在视频数据增广(batch × frames × boxes)场景下的实战影响。
一、修复背景:VideoBoxes与Boxes的继承关系
1.1 两个核心类
在 kornia/geometry/boxes.py 中:
Boxes(第 190 行起):2D 框容器,存储形状为(N, 4, 2)、(B, N, 4, 2)或 list 形式;VideoBoxes(第 1072 行起):继承Boxes,专为视频序列设计,接受(B, T, N, 4, 2)输入,内部展平为(B·T, N, 4, 2)存储,并保存temporal_channel_size = T以便在导出时恢复时间轴。
VideoBoxes.to_tensor()(第 1150 行)在super().to_tensor(...)之后通过out.view(-1, self.temporal_channel_size, *out.shape[1:])恢复时间维度,是视频框回传张量的核心路径。
1.2 Bug 的直接现场
Boxes.get_boxes_shape()(第 328 行)内部调用:
boxes_xywh = cast(torch.Tensor, self.to_tensor("xywh", as_padded_sequence=True))Boxes.to_mask()(第 819 行)内部调用:
clipped_boxes_xyxy = cast(torch.Tensor, self.to_tensor("xyxy", as_padded_sequence=True))而VideoBoxes的重写只声明了mode参数(旧签名def to_tensor(self, mode: Optional[str] = None)),未声明as_padded_sequence。因此任何从基类继承、内部向to_tensor传递as_padded_sequence=True的方法,在VideoBoxes实例上都会触发:
TypeError: to_tensor() got an unexpected keyword argument 'as_padded_sequence'二、根因分析与最小修复
2.1 为什么"每个调用都失败"
get_boxes_shape与to_mask是VideoBoxes继承自Boxes的方法,它们固定向to_tensor传入as_padded_sequence=True。由于VideoBoxes的重写签名缺少该关键字,这两个方法在VideoBoxes上必然失败——包括AugmentationSequential为视频框输入构建的容器路径(见 kornia/augmentation/container/augment.py 第 722-739 行_preproc_boxes:当contains_video_sequential为真时调用VideoBoxes.from_tensor(arg))。
2.2 修复内容
修复后的VideoBoxes.to_tensor签名改为:
def to_tensor(self, mode: Optional[str] = None, as_padded_sequence: bool = False) -> torch.Tensor | list[torch.Tensor]: out = super().to_tensor(mode, as_padded_sequence=as_padded_sequence) if isinstance(out, torch.Tensor): return out.view(-1, self.temporal_channel_size, *out.shape[1:]) return [_out.view(-1, self.temporal_channel_size, *_out.shape[1:]) for _out in out]关键点:
- 接受并转发关键字:
as_padded_sequence被完整透传给基类Boxes.to_tensor(第 738 行); - 不影响正常调用:该参数只改变 list-backed 容器的输出形式。由
(B, T, N, 4, 2)张量构建的VideoBoxes并非 list-backed(_N is None),因此该关键字对其结果无任何影响; - 向后兼容:默认值
False与旧行为一致,所有既有合法调用结果不变。
三、源码佐证:list-backed 语义
Boxes.to_tensor中(第 813-816 行):
if self._N is not None and not as_padded_sequence: boxes = [torch.nn.functional.pad(o, (len(o.shape) - 1) * [0, 0] + [0, -n]) for o, n in zip(boxes, self._N)] else: boxes = boxes if self._is_batched else boxes.squeeze(0) return boxes_N为None时走 else 分支,as_padded_sequence完全不生效——这正印证了修复文档的论断:"它只改变 list-backed 容器,而从张量构建的VideoBoxes不是其中之一,所以没有合法调用会改变其结果"。
四、测试验证与已知遗留
4.1 测试覆盖
tests/geometry/test_boxes.py 中TestVideoBoxes(第 1881 行起)针对本次修复提供双重验证:
test_convention_inherited_shape_and_mask_work_on_the_temporal_wrapper_4249(第 2024 行):直接断言get_boxes_shape()与to_mask(4, 5)不再抛出TypeError,并以AssertionError捕获残留异常;test_wart_indexing_drops_the_temporal_size_4249(第 1972 行):固定剩余的另一半 #4249——索引操作仍会丢失temporal_channel_size:
frame = video_boxes[0] with pytest.raises(AttributeError, match="temporal_channel_size"): frame.to_tensor()4.2 遗留问题(诚实边界)
从源码与测试可以确认:
- 索引仍丢失时间轴:
Boxes.__getitem__(第 306 行)用type(self)(...)构造结果,从不设置temporal_channel_size,导致切片后的to_tensor抛出AttributeError。这是 #4249 未修复的一半; - 文档注释(boxes.py 第 1100-1104 行)同时标注了
validate_boxes标志当前无效(#4177)。
五、实战影响:视频增广容器链路
在 kornia/augmentation/container/augment.py 中,视频框的处理流程为:
_preproc_boxes(第 722 行):检测contains_video_sequential后调用VideoBoxes.from_tensor(arg)(第 735 行);- 容器内几何变换作用于展平的
(B·T, N, 4, 2)数据; _postproc_boxes(第 741 行):调用out_arg.to_tensor(mode=mode)(第 757 行)恢复时间轴。
本次修复保证了在管线中如需调用get_boxes_shape(计算每个框的宽高)或to_mask(将框渲染为掩码图)不再中断。可结合下列入口深入阅读:
- kornia/geometry/boxes.py:
Boxes(L190)、VideoBoxes(L1072)、Boxes.to_tensor(L738)、Boxes.get_boxes_shape(L328)、Boxes.to_mask(L819); - kornia/augmentation/container/augment.py:
_preproc_boxes(L722)、_postproc_boxes(L741); - tests/geometry/test_boxes.py:
TestVideoBoxes(L1881)。
六、迁移建议
升级到包含 #4176、#4365 修复的版本后:
- 现有
VideoBoxes代码无需任何修改,签名扩展完全向后兼容; - 若此前因
TypeError绕过了get_boxes_shape/to_mask(例如先to_tensor再手写宽高计算),现在可直接调用继承方法; - 仍需注意:索引切片后不要调用
to_tensor,应使用video_boxes.data或先恢复容器;这是当前版本明确的已知限制(#4249 剩余部分)。
【免费下载链接】kornia🐍 空间人工智能的几何计算机视觉库项目地址: https://gitcode.com/kornia/kornia
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考