旋转边界框的变换¶
此示例说明如何定义和使用旋转边界框。
注意
旋转边界框支持已在 TorchVision 0.23 中发布,目前是 BETA 功能。我们不期望 API 会发生变化,但可能存在一些罕见的边缘情况。如果您发现任何问题,请在我们的 bug 跟踪器上报告:https://github.com/pytorch/vision/issues?q=is:open+is:issue
首先,一些设置代码
from PIL import Image
from pathlib import Path
import matplotlib.pyplot as plt
import torch
from torchvision.tv_tensors import BoundingBoxes
from torchvision.transforms import v2
from helpers import plot
plt.rcParams["figure.figsize"] = [10, 5]
plt.rcParams["savefig.bbox"] = "tight"
# if you change the seed, make sure that the randomly-applied transforms
# properly show that the image can be both transformed and *not* transformed!
torch.manual_seed(0)
# If you're trying to run that on Colab, you can download the assets and the
# helpers from https://github.com/pytorch/vision/tree/main/gallery/
orig_img = Image.open(Path('../assets') / 'leaning_tower.jpg')
创建旋转边界框¶
通过实例化 BoundingBoxes
类来创建旋转边界框。是构造函数中的 format
参数决定了边界框是否旋转。在此实例中,我们使用 CXCYWHR BoundingBoxFormat
。前两个值是边界框中心的 X 和 Y 坐标。接下来的两个值是边界框的宽度和高度,最后一个值是边界框的旋转角度(以度为单位)。
orig_box = BoundingBoxes(
[
[860.0, 1100, 570, 1840, -7],
],
format="CXCYWHR",
canvas_size=(orig_img.size[1], orig_img.size[0]),
)
plot([(orig_img, orig_box)], bbox_width=10)

变换示例¶
rotater = v2.RandomRotation(degrees=(0, 180), expand=True)
rotated_imgs = [rotater((orig_img, orig_box)) for _ in range(4)]
plot([(orig_img, orig_box)] + rotated_imgs, bbox_width=10)

使用 Pad
padded_imgs_and_boxes = [
v2.Pad(padding=padding)(orig_img, orig_box)
for padding in (30, 50, 100, 200)
]
plot([(orig_img, orig_box)] + padded_imgs_and_boxes, bbox_width=10)

使用 Resize
resized_imgs = [
v2.Resize(size=size)(orig_img, orig_box)
for size in (30, 50, 100, orig_img.size)
]
plot([(orig_img, orig_box)] + resized_imgs, bbox_width=5)

请注意,在像素较少的图像中,边界框看起来更大是一种人为的伪影,而非事实。那仅仅是边界框边界的栅格化表示,由于我们指定了该栅格化线的固定宽度,所以它显得更大。当图像宽度只有 30 像素时,一条 3 像素宽的线就相对较大。
裁剪模式及其对变换的影响¶
某些变换,例如 CenterCrop
,可能会导致变换后的边界框部分超出变换后的(裁剪后的)图像。通常,这可能发生在大多数 几何变换 上。
在这种情况下,边界框会根据其 clamping_mode
属性裁剪到变换后的图像大小。 clamping_mode
有三个值,用于确定变换后边界框如何裁剪:
None
:不应用裁剪,边界框可能部分超出图像。“hard”:边界框被裁剪到图像大小,使其所有角点都在图像画布内。这可能会导致信息丢失,并可能导致不直观的结果。但对于某些应用可能是必需的,例如模型不支持图像外的边界框。
“soft”:这是
None
和 “hard” 之间的一个中间模式:边界框被裁剪,但不如 “hard” 模式严格。一些边界框的尺寸可能仍超出图像。这是构造BoundingBoxes
时的默认值。
注意
对于轴对齐边界框,“soft” 和 “hard” 模式的行为相同,因为边界框始终被裁剪到图像大小。
让我们用 CenterCrop
变换来说明裁剪模式。
assert orig_box.clamping_mode == "soft"
box_hard_clamping = BoundingBoxes(orig_box, format=orig_box.format, canvas_size=orig_box.canvas_size, clamping_mode="hard")
box_no_clamping = BoundingBoxes(orig_box, format=orig_box.format, canvas_size=orig_box.canvas_size, clamping_mode=None)
crop_sizes = (800, 1200, 2000, orig_img.size)
soft_center_crops_and_boxes = [
v2.CenterCrop(size=size)(orig_img, orig_box)
for size in crop_sizes
]
hard_center_crops_and_boxes = [
v2.CenterCrop(size=size)(orig_img, box_hard_clamping)
for size in crop_sizes
]
no_clamping_center_crops_and_boxes = [
v2.CenterCrop(size=size)(orig_img, box_no_clamping)
for size in crop_sizes
]
plot([[(orig_img, box_hard_clamping)] + hard_center_crops_and_boxes,
[(orig_img, orig_box)] + soft_center_crops_and_boxes,
[(orig_img, box_no_clamping)] + no_clamping_center_crops_and_boxes],
bbox_width=10)

上图依次显示了 “hard” 裁剪模式、“soft” 模式和 None
模式。虽然 “soft” 和 None
模式的图看起来相似,但它们生成的裁剪边界框并不完全相同。未裁剪的边界框会显示出与图像距离更远的尺寸。
print("boxes with soft clamping:")
print(soft_center_crops_and_boxes)
print()
print("boxes with no clamping:")
print(no_clamping_center_crops_and_boxes)
boxes with soft clamping:
[(<PIL.Image.Image image mode=RGB size=800x800 at 0x7F37534A3670>, BoundingBoxes([[478.8188, 400.9185, 570.0000, 874.1443, -7.0000]], format=BoundingBoxFormat.CXCYWHR, canvas_size=(800, 800), clamping_mode=soft)), (<PIL.Image.Image image mode=RGB size=1200x1200 at 0x7F37534A3220>, BoundingBoxes([[ 678.9319, 600.0001, 569.9992, 1278.9989, -7.0000]], format=BoundingBoxFormat.CXCYWHR, canvas_size=(1200, 1200), clamping_mode=soft)), (<PIL.Image.Image image mode=RGB size=2000x2000 at 0x7F37534A8AC0>, BoundingBoxes([[1089.0000, 918.0000, 570.0001, 1840.0000, -7.0000]], format=BoundingBoxFormat.CXCYWHR, canvas_size=(2000, 2000), clamping_mode=soft)), (<PIL.Image.Image image mode=RGB size=2364x1542 at 0x7F37534A8B80>, BoundingBoxes([[1260.9314, 771.0001, 570.0002, 1623.5675, -7.0000]], format=BoundingBoxFormat.CXCYWHR, canvas_size=(1542, 2364), clamping_mode=soft))]
boxes with no clamping:
[(<PIL.Image.Image image mode=RGB size=800x800 at 0x7F37534A8F10>, BoundingBoxes([[ 489., 318., 570., 1840., -7.]], format=BoundingBoxFormat.CXCYWHR, canvas_size=(800, 800), clamping_mode=None)), (<PIL.Image.Image image mode=RGB size=1200x1200 at 0x7F37534AA7D0>, BoundingBoxes([[ 689., 518., 570., 1840., -7.]], format=BoundingBoxFormat.CXCYWHR, canvas_size=(1200, 1200), clamping_mode=None)), (<PIL.Image.Image image mode=RGB size=2000x2000 at 0x7F37534AA8C0>, BoundingBoxes([[1089., 918., 570., 1840., -7.]], format=BoundingBoxFormat.CXCYWHR, canvas_size=(2000, 2000), clamping_mode=None)), (<PIL.Image.Image image mode=RGB size=2364x1542 at 0x7F37534AA020>, BoundingBoxes([[1271., 689., 570., 1840., -7.]], format=BoundingBoxFormat.CXCYWHR, canvas_size=(1542, 2364), clamping_mode=None))]
设置裁剪模式¶
决定应用于边界框的裁剪策略的 clamping_mode
属性可以通过多种方式设置:
在构造具有其
BoundingBoxes
构造函数的边界框时,如上面的示例所示。通过直接设置现有实例的属性,例如
boxes.clamping_mode = "hard"
。通过调用
SetClampingMode
变换。
另外,请记住,您始终可以通过调用 ClampBoundingBoxes()
变换手动裁剪边界框!这是一个演示所有这些选项的示例。
t = v2.Compose([
v2.CenterCrop(size=(800,)), # clamps according to the current clamping_mode
# attribute, in this case set by the constructor
v2.SetClampingMode(None), # sets the clamping_mode attribute for future transforms
v2.Pad(padding=3), # clamps according to the current clamping_mode
# i.e. ``None``
v2.ClampBoundingBoxes(clamping_mode="soft"), # clamps with "soft" mode.
])
out_img, out_box = t(orig_img, orig_box)
plot([(orig_img, orig_box), (out_img, out_box)], bbox_width=10)

脚本总运行时间: (0 分 6.780 秒)