- 数据增强
- 计算机视觉
- 图像处理
- 机器学习
【免费下载链接】imgaug
Image augmentation for machine learning experiments.
本指南聚焦 imgaug 0.4.0 新增的BoundingBox→Polygon转换能力,系统讲解BoundingBox.to_polygon()与BoundingBoxesOnImage.to_polygons_on_image()两个核心方法(对应 changelog 20191110_bb_polygon_conversion.md)。读完本文,你将掌握如何在目标检测标注与多边形标注之间无损互转、理解其角点顺序与 label 保留机制,并能复现 imgaug 内部(如WithPolarWarping)利用该转换配合subdivide()完成复杂几何增强的完整调用链。
一、背景:为什么需要边界框与多边形的互相转换
在 0.4.0 版本之前,imgaug 的边界框增强本质上是 keypoint 增强的包装器——边界框在增强开始时被转成四个角点,再以 keypoint 形式参与增强(见 v0.4.0.summary.md 中 "Unwrapped Bounding Box Augmentation" 一节的说明)。这种设计让增强器无法针对边界框本身做专门处理。
0.4.0 对增强后端进行了大规模重构,边界框获得了原生的_augment_bounding_boxes()增强方法。与此同时,新增了边界框与多边形之间的转换 API,其实际价值在于:
- 标注格式统一:不同数据集的标注格式不统一(COCO 用矩形框、Cityscapes 等用多边形),转换 API 让训练管线可以方便地在两种格式间切换。
- 表达能力的升级:边界框只能表达轴对齐矩形,多边形可以表达任意不规则区域。将边界框转成多边形后,可以进一步使用
subdivide()增加顶点密度,配合扭曲类增强得到更平滑、更贴合真实目标的几何变换结果(这正是 imgaug 内部WithPolarWarping的做法)。 - 格式互转闭环:imgaug 同时提供了反向方法
Polygon.to_bounding_box(),保证两个方向都能转换,形成完整闭环。
二、核心 API:BoundingBox.to_polygon()
2.1 方法与实现
该方法位于 imgaug/augmentables/bbs.py,签名与返回值为:
def to_polygon(self): """Convert this bounding box to a polygon covering the same area. Added in 0.4.0. Returns ------- imgaug.augmentables.polys.Polygon The bounding box converted to a polygon. """从源码实现可以看到,转换的核心逻辑非常简单且直观:取边界框的四个角点,按从左上角开始的顺时针顺序构造成一个Polygon,并保留原边界框的 label:
return Polygon([ (self.x1, self.y1), # 左上角 (self.x2, self.y1), # 右上角 (self.x2, self.y2), # 右下角 (self.x1, self.y2) # 左下角 ], label=self.label)2.2 快速上手示例
import imgaug as ia bb = ia.BoundingBox(x1=10, y1=20, x2=40, y2=60, label="cat") poly = bb.to_polygon() print(poly.exterior) # array([[10., 20.], # [40., 20.], # [40., 60.], # [10., 60.]]) print(poly.label) # "cat"这里有两个值得注意的细节:
- 角点顺序:imgaug 的
BoundingBox内部参数化方式为"左上角(x1, y1)+ 右下角(x2, y2)"(参见 imgaug/augmentables/bbs.py 的类文档),而Polygon.exterior则按逆/顺时针顶点序列存储。to_polygon()恰好按照"左上 → 右上 → 右下 → 左下"的顺序生成顶点,保证转换后多边形覆盖面积与原框完全一致。 - label 继承:转换后的多边形沿用原边界框的
label字段。在语义分割/实例分割数据准备场景中,这意味着类别信息在格式转换过程中不会丢失。
2.3 反向转换:Polygon.to_bounding_box()
imgaug 为多边形提供了对称的反向方法Polygon.to_bounding_box()(见 imgaug/augmentables/polys.py)。与"角点直接映射"不同,反向转换取多边形外轮廓所有顶点的最小/最大坐标,生成一个能紧密包围该多边形的轴对齐边界框:
def to_bounding_box(self): from imgaug.augmentables.bbs import BoundingBox xx = self.xx yy = self.yy return BoundingBox(x1=min(xx), x2=max(xx), y1=min(yy), y2=max(yy), label=self.label)这意味着BB → Polygon → BB往返转换可以做到完全无损,而Polygon → BB → Polygon则可能会丢失不规则形状的细节(多边形被"简化"为最小外接矩形)。理解这一不对称性是正确设计数据管线的关键。
三、批量转换:BoundingBoxesOnImage.to_polygons_on_image()
3.1 方法与实现
实际训练管线中,一张图上通常有多个边界框,此时应使用BoundingBoxesOnImage层面的批量转换方法,同样位于 imgaug/augmentables/bbs.py:
def to_polygons_on_image(self): """Convert the bounding boxes to one ``PolygonsOnImage`` instance. Added in 0.4.0. Returns ------- imgaug.augmentables.polys.PolygonsOnImage A ``PolygonsOnImage`` containing polygons. Each polygon covers the same area as the corresponding bounding box. """ from .polys import PolygonsOnImage polygons = [bb.to_polygon() for bb in self.bounding_boxes] return PolygonsOnImage(polygons, shape=self.shape)其行为可以概括为两点:
- 逐个转换:对实例内的每个
BoundingBox调用to_polygon(),因此 label 与角点顺序的规则与单框转换完全一致; - shape 保持:
PolygonsOnImage使用与原BoundingBoxesOnImage相同的shape(即所在图像的(H, W, C)),保证转换后的多边形集合仍然"知道"自己所在图像的尺寸,这是后续参与增强的前提。
3.2 批量示例
import imgaug as ia import numpy as np bb1 = ia.BoundingBox(x1=20, y1=10, x2=40, y2=30) bb2 = ia.BoundingBox(x1=25, y1=15, x2=51, y2=35, label="car") bbsoi = ia.BoundingBoxesOnImage([bb1, bb2], shape=(40, 50, 3)) psoi = bbsoi.to_polygons_on_image() print(psoi.shape) # (40, 50, 3),与原 BoundingBoxesOnImage 一致 print(len(psoi.items)) # 2,多边形数量与边界框数量一一对应3.3 边界情况:空实例
转换 API 对空实例同样安全。仓库测试 test/augmentables/test_bbs.py 专门覆盖了该场景:
def test_to_polygons_on_image__empty_instance(self): bbsoi = ia.BoundingBoxesOnImage([], shape=(40, 50, 3)) psoi = bbsoi.to_polygons_on_image() assert psoi.shape == (40, 50, 3) assert len(psoi.items) == 0即使一张图上没有任何标注,转换后仍会得到一个 shape 正确、多边形列表为空的有效PolygonsOnImage,不会抛出异常。
四、实战进阶:转换 +subdivide()在WithPolarWarping中的运用
转换 API 最典型的内部使用场景是WithPolarWarping增强器——它在极坐标扭曲时需要把边界框临时"升级"为多边形,扭曲完成后再转回边界框。完整调用链见 imgaug/augmenters/geometric.py。
4.1 前向转换:BB → 细粒度 Polygon
psois = [bbsoi.to_polygons_on_image() for bbsoi in batch.bounding_boxes] psois = [psoi.subdivide_(2) for psoi in psois] # 标记这些多边形实际来自边界框 for psoi in psois: for polygon in psoi.polygons: if polygon.label is None: polygon.label = "$$IMGAUG_BB_AS_POLYGON" else: polygon.label = polygon.label + ";$$IMGAUG_BB_AS_POLYGON"这里揭示了两个重要的配合技巧:
subdivide_(2)增加顶点密度:Polygon.subdivide(N)会在每条边上以等间距插值出N个新顶点(见 imgaug/augmentables/polys.py 及配套文档 20191110_polygon_subdivision.md)。插值位置由 imgaug/augmentables/lines.py 中LineString.subdivide()的公式A + (i/(1+N)) * (B - A)决定。极坐标扭曲是强非线性变换,4 个角点不足以描述弯曲后的区域,插值后每个边被细分为 3 段,扭曲结果显著更平滑。- label 哨兵标记:imgaug 在 label 上拼接
$$IMGAUG_BB_AS_POLYGON标记,以便在逆转换时准确识别哪些多边形需要还原为边界框。
4.2 逆向还原:Polygon → BB
扭曲完成后,_invert_convert_bbs_to_polygons_()遍历所有多边形,识别带哨兵标记的项并调用polygon.to_bounding_box()还原,其余的多边形保持原样,最后重新组装出BoundingBoxesOnImage(shape取自psoi.shape)。整个流程完美复用了本文介绍的两对转换方法。
4.3 独立使用场景示例
如果你需要在不使用WithPolarWarping的情况下获得类似效果,可以直接组合转换与细分:
import imgaug as ia import imgaug.augmenters as iaa bb = ia.BoundingBox(x1=50, y1=50, x2=150, y2=150) poly = bb.to_polygon() # 转成 4 顶点多边形 poly_sub = poly.subdivide(3) # 每条边插值 3 个点,共 16 个顶点 # 用细分后的多边形参与透视变换 aug = iaa.PerspectiveTransform(scale=0.1) psoi_aug = aug.augment_polygons(ia.PolygonsOnImage([poly_sub], shape=(200, 200, 3)))五、测试验证:角点顺序与坐标正确性由单测保障
仓库中的单元测试直接证明了转换行为的正确性。核心测试位于 test/augmentables/test_bbs.py:
def test_to_polygon(self): bb = ia.BoundingBox(y1=1, y2=3, x1=1, x2=3) poly = bb.to_polygon() assert poly.coords_almost_equals([ (1, 1), # 左上 (3, 1), # 右上 (3, 3), # 右下 (1, 3) # 左下 ])该测试验证了:BoundingBox(x1=1, y1=1, x2=3, y2=3)转换后多边形的四个顶点按"左上 → 右上 → 右下 → 左下"的顺序生成,且坐标值分毫不差(coords_almost_equals的默认容差为1e-4,见 imgaug/augmentables/polys.py 附近的coords_almost_equals实现)。
批量转换的测试则验证了 shape 保持与多边形数量一一对应(test/augmentables/test_bbs.py),其中第二个多边形(x1=25, y1=15, x2=51, y2=35)转换后顶点为(25,15) → (51,15) → (51,35) → (25,35),与单框测试的角点顺序规则完全一致。此外,Polygon.subdivide()系列也有独立测试类TestPolygon_subdivide_/TestPolygon_subdivide覆盖(见 test/augmentables/test_polys.py)。
六、总结
imgaug 0.4.0 引入的边界框 ↔ 多边形转换能力,是一组设计简洁、边界处理完善的基础 API:
| API | 位置 | 作用 |
|---|---|---|
BoundingBox.to_polygon() | imgaug/augmentables/bbs.py | 单框转多边形,保留 label,角点按顺时针顺序 |
BoundingBoxesOnImage.to_polygons_on_image() | imgaug/augmentables/bbs.py | 批量转换,保持图像 shape,支持空实例 |
Polygon.to_bounding_box() | imgaug/augmentables/polys.py | 反向转换,取最小外接矩形 |
Polygon.subdivide(N) | imgaug/augmentables/polys.py | 每条边等距插值 N 个顶点,配合转换用于扭曲类增强 |
在实际项目中,你可以用它完成检测标注与分割标注之间的格式互通,也可以仿照WithPolarWarping的模式,将边界框"升级"为细分多边形后再进行强几何变换,从而获得更贴合真实目标形态的增强结果。值得注意的是,BB → Polygon → BB往返无损,而反向往返会丢失形状细节,设计管线时请根据标注精度需求选择合适的转换方向。
- 数据增强
- 计算机视觉
- 图像处理
- 机器学习
【免费下载链接】imgaug
Image augmentation for machine learning experiments.
相关推荐
@turf/line-to-polygon 完全指南:将 LineString / MultiLineString 转换为 Polygon 的实现原理与实战用法
@turf/line to polygon 完全指南:将 LineString / MultiLineString 转换为 Polygon 的实现原理与实战用法
数据分析WezTerm 窗格旋转详解:`tab:rotate_clockwise()` 方法原理与实战
WezTerm 窗格旋转详解: tab:rotate_clockwise 方法原理与实战 导读 tab:rotate_clockwise 是 WezTerm 中
桌面应用开发工具跨平台folium 矢量图层完全指南:PolyLine、Polygon、Rectangle、Circle/CircleMarker 与 ColorLine 实战详解
folium 矢量图层完全指南:PolyLine、Polygon、Rectangle、Circle/CircleMarker 与 ColorLine 实战详解
数据可视化数据分析GIS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考