官网:https://imgaug.readthedocs.io/en/latest/
教程:https://nbviewer.jupyter.org/github/aleju/imgaug-doc/blob/master/notebooks/B01 - Augment Keypoints.ipynb
imgaug
中的关键点是图像上的点,以具有子像素精度的x和y绝对坐标给出(即,值域[0, S)
内的浮点数,其中S表示轴的大小)。在文献中,它们通常被称为“landmarks”,并且可以用于人体姿势估计。
在imgaug
中提供了两个用于关键点扩充的类:
imgaug.Keypoint
:一个非常简单的类,这样实例化:imgaug.Keypoint(x=
。该类的方法有:
project(from_shape, to_shape)
:将关键点从一个图像形状投影到另一个图像形状,如图像大小调整后。shift([x], [y])
:用于在x/y轴上移动点。返回一个新的关键点。imgaug.KeypointsOnImage
:将图像上的关键点列表与图像形状组合在一起。它被实例化为imgaug.KeypointsOnImage(keypoints, shape)
,其中keypoints
是imgaug.Keypoint
的列表,shape
是关键点的形状。这两个参数存储为.keypoints
和.shape
属性。 该类的方法有:
on(image)
:用于投影新图像上的关键点,如图像大小调整后。draw_on_image(image, [color], [size], [copy], [raise_if_out_of_image])
:将关键点作为正方形绘制到图像上。图像必须以numpy数组的形式给出。shift([x], [y])
:类似于imgaug.Keypoint
中的方法,但会移动所有关键点。get_coords_array()
:将实例转换为(N, 2)
numpy数组。static from_coords_array(coords, shape)
:从(N, 2)
数组创建imgaug.KeypointsOnImage
的实例。形状是相应图像的形状。to_distance_maps([inverted])
:将关键点转换为图像大小的欧式距离图。结果是形状(H, W, N)
,N
是关键点的数量。static from_distance_maps(distance_maps, [inverted], [if_not_found_coords], [threshold], [nb_channels])
:to_distance_maps()
的反函数。为了增加关键点,必须调用augment_keypoints()
方法,由所有增强器提供。它需要imgaug.KeypointsOnImage
的单个实例或该类的列表。
有关更多详细信息,请参阅API:imgaug.Keypoint, imgaug.KeypointsOnImage, imgaug.augmenters.meta.Augmenter.augment_keypoints()。
请注意,关键点仅受更改图像几何形状的增强器的影响。如水平翻转或仿射变换。它们不受其他方法的影响,如高斯噪声。
让我们看一个简单的例子,我们通过应用仿射变换来增加图像和五个关键点。 作为第一步,我们加载一个示例图像:
import imageio
import imgaug as ia
%matplotlib inline
image = imageio.imread("https://upload.wikimedia.org/wikipedia/commons/e/e6/Macropus_rufogriseus_rufogriseus_Bruny.jpg")
image = ia.imresize_single_image(image, (389, 259))
ia.imshow(image)
现在让我们放置并可视化几个关键点:
kps = [
ia.Keypoint(x=99, y=81), # left eye (from camera perspective)
ia.Keypoint(x=125, y=80), # right eye
ia.Keypoint(x=112, y=102), # nose
ia.Keypoint(x=102, y=210), # left paw
ia.Keypoint(x=127, y=207) # right paw
]
kpsoi = ia.KeypointsOnImage(kps, shape=image.shape)
ia.imshow(kpsoi.draw_on_image(image, size=7))
请注意我们如何在KeypointsOnImage
的实例中“合并”图像的所有关键点。 我们很快就会增强那个实例。 如果您必须在增强后处理关键点,可以通过.keypoints
属性访问它们:
print(kpsoi.keypoints)
[Keypoint(x=99.00000000, y=81.00000000), Keypoint(x=125.00000000, y=80.00000000), Keypoint(x=112.00000000, y=102.00000000), Keypoint(x=102.00000000, y=210.00000000), Keypoint(x=127.00000000, y=207.00000000)]
现在来实际增强。 我们想要应用仿射变换,它将改变图像和关键点。 我们选择了一些平移和旋转作为转换。 此外,我们添加了一些颜色抖动。 那种颜色抖动只会影响图像。
import imgaug.augmenters as iaa
ia.seed(3)
aug = iaa.Sequential([
iaa.Affine(translate_px={"x": (10, 30)}, rotate=(-10, 10)),
iaa.AddToHueAndSaturation((-50, 50)) # color jitter, only affects the image
])
现在我们将增强序列应用于图像和关键点。 为了确保以相同的方式增加两种数据类型,我们首先将增强序列切换到确定模式。 没有它,我们会获得图像和关键点间不匹配旋转。 请注意,每转换一批切换一次确定模式。
aug_det = aug.to_deterministic()
image_aug = aug_det.augment_image(image)
kpsoi_aug = aug_det.augment_keypoints(kpsoi)
现在我们可视化增强前/增强后的图像和关键点:
import numpy as np
ia.imshow(
np.hstack([
kpsoi.draw_on_image(image, size=7),
kpsoi_aug.draw_on_image(image_aug, size=7)
])
)
前面的示例使用to_deterministic()
将增强序列切换到确定模式,从而对应图像和关键点之间的增强。 这可以通过使用augment_batches()
来避免,它自动处理确定模式切换。 该方法需要一个imgaug.Batch
实例列表,在这种情况下,它必须包含图像和关键点。 它们将被实例化为imgaug.Batch(images=
。 请注意,图像和关键点列表必须包含相同数量的项目。, keypoints=
)
batch = ia.Batch(
images=[image],
keypoints=[kpsoi]
)
batch_aug = list(aug.augment_batches([batch]))[0] # augment_batches returns a generator
image_aug = batch_aug.images_aug[0]
kpsoi_aug = batch_aug.keypoints_aug[0]
ia.imshow(kpsoi_aug.draw_on_image(image_aug, size=7))
使用augment_batches()
的优点是:(a)使用确定模式产生错误的风险较小;(b)简单地添加参数background=True
将激活后台模式并自动调用多核CPU进行增强。
使用关键点时,您可能在某些时候必须更改图像大小。 可以通过使用KeypointsOnImage.on(image or shape)
来补偿这一点,它将关键点投影到新图像上的相同相对位置。 在以下代码块中,初始示例图像增加到原始大小的两倍。 然后(1)在原始图像上绘制和可视化关键点,(2)在调整大小的图像上绘制和可视化,而不使用on()
和(3)与on()
组合绘制和可视化。
image_larger = ia.imresize_single_image(image, 2.0)
print("Small image %s with keypoints optimized for the size:" % (image.shape,))
ia.imshow(kpsoi.draw_on_image(image, size=7))
print("Large image %s with keypoints optimized for the small image size:" % (image_larger.shape,))
ia.imshow(kpsoi.draw_on_image(image_larger, size=7))
print("Large image %s with keypoints projected onto that size:" % (image_larger.shape,))
ia.imshow(kpsoi.on(image_larger).draw_on_image(image_larger, size=7))
Small image (389, 259, 3) with keypoints optimized for the size:
Large image (778, 518, 3) with keypoints optimized for the small image size:
Large image (778, 518, 3) with keypoints projected onto that size:
前面提到的on()
可以在调整图像大小的情况下起作用,但在图像填充时不起作用,因为图像上关键点的相对位置会发生变化。 可以使用KeypointsOnImage.shift(x=
来补偿这种填充,其中x左/右位移,y上/下位移。
image_pad = ia.pad(image, left=100)
kpsoi_pad = kpsoi.shift(x=100)
ia.imshow(kpsoi_pad.draw_on_image(image_pad, size=7))
在前面的示例中使用了KeypointsOnImage.draw_on_image()
方法来可视化关键点。 它们以正方形的形式存在于图像上。 可以使用参数size
控制这些方块的大小,如下所示:
ia.imshow(np.hstack([
kpsoi.draw_on_image(image, size=1),
kpsoi.draw_on_image(image, size=3),
kpsoi.draw_on_image(image, size=5),
kpsoi.draw_on_image(image, size=7)
]))
可以使用**color
参数控制绘制的关键点的颜色**:
ia.imshow(np.hstack([
kpsoi.draw_on_image(image, size=5, color=(0, 255, 0)),
kpsoi.draw_on_image(image, size=5, color=(0, 0, 255)),
kpsoi.draw_on_image(image, size=5, color=(255, 128, 255)),
kpsoi.draw_on_image(image, size=5, color=(255, 255, 255))
]))
为了提高性能,draw_on_image()
方法还提供了一个copy
标志,可以将其设置为False
,以避免就地修改图像。 以下示例通过多次绘制到同一图像来显示其用法。 请注意,虽然该示例忽略了draw_on_image()
返回的内容并完全依赖于就地修改,但实际上不建议这样做,因为该标志应被解释为就地修改的权限。
image_draw = np.copy(image)
kpsoi.draw_on_image(image_draw, size=5, color=(0, 255, 0), copy=False)
kpsoi.shift(x=-70).draw_on_image(image_draw, size=5, color=(255, 255, 255), copy=False)
kpsoi.shift(x=70).draw_on_image(image_draw, size=5, color=(0, 0, 0), copy=False)
ia.imshow(image_draw)
draw_on_image()
目前没有一种简单的方法来选择每个关键点的颜色。 但是,这可以通过在关键点上编写一个小循环并在每次迭代中仅使用一个关键点实例化KeypointsOnImage
来实现。 以下代码块显示了一个示例:
colors = [(0, 255, 0),
(255, 255, 255),
(128, 255, 64),
(128, 64, 255),
(128, 128, 0)]
image_drawn = np.copy(image)
for i, color in enumerate(colors):
kpsoi_one = ia.KeypointsOnImage([kpsoi.keypoints[i]], shape=kpsoi.shape)
image_drawn = kpsoi_one.draw_on_image(image_drawn, color=color, size=9, copy=False)
ia.imshow(image_drawn)
在训练关键点预测模型时,网络的输出可能不会是每个关键点的xy坐标。 相反,热图是表示关键点位置的常见形式,值为1.0
,其中热图的地面实况位置(或网络认为的位置)。 可以使用to_distance_maps()
将关键点转换为imgaug
中的表示,其基于欧氏距离将每个关键点转换为2D距离图。 在以下示例中,将先前的关键点转换为此类距离图:
distance_maps = kpsoi.to_distance_maps()
print("Image shape:", distance_maps.shape)
print("Distance maps shape:", distance_maps.shape)
print("Distance maps dtype:", distance_maps.dtype)
print("Distance maps min:", distance_maps.min(), "max:", distance_maps.max())
Image shape: (389, 259, 5)
Distance maps shape: (389, 259, 5)
Distance maps dtype: float32
Distance maps min: 0.0 max: 345.7311
如打印值所示,我们得到与图像具有相同高度和宽度的距离图。 实际上每个关键点也得到一个距离图。 地图未标准化,因此可能超出值范围[0.0,1.0]
。 现在让我们根据最大可能的欧氏距离对它们进行标准化:
height, width = kpsoi.shape[0:2]
max_distance = np.linalg.norm(np.float32([0, 0]) - np.float32([height, width]))
distance_maps_normalized = distance_maps / max_distance
print("min:", distance_maps.min(), "max:", distance_maps_normalized.max())
min: 0.0 max: 0.7397929
imgaug
支持热图。 我们不需要这些用于增强,因为我们可以简单地直接扩充关键点。 但是,我们可以利用此功能来快速可视化距离图:
heatmaps = ia.HeatmapsOnImage(distance_maps_normalized, shape=kpsoi.shape)
ia.imshow(np.hstack(heatmaps.draw_on_image(image)))
正如您所见,当热值远离相应的关键点时,热图值当前会增加。 通常,它的逆可用于网络输出。 具有明显更多的局部激活也是常见的。 因此,我们现在反转热图并对其应用强指数:
heatmaps = ia.HeatmapsOnImage((1.0 - distance_maps_normalized)**10, shape=kpsoi.shape)
ia.imshow(np.hstack(heatmaps.draw_on_image(image)))
这看起来像我们可以训练的东西。
但请注意,大多数出版物都将关键点表示为图像上放置的手动调整的sigmas高斯。 使用距离图可能会或可能不会执行类似的操作。
KeypointsOnImage
的一个实例很容易地将keypoints以xy坐标形式转换为(N, 2)
float32 numpy数组:
arr = kpsoi.get_coords_array()
print("Keypoints as objects:", kpsoi.keypoints)
print("Keypoints as array:", arr)
print("Shape:", arr.shape)
Keypoints as objects: [Keypoint(x=99.00000000, y=81.00000000), Keypoint(x=125.00000000, y=80.00000000), Keypoint(x=112.00000000, y=102.00000000), Keypoint(x=102.00000000, y=210.00000000), Keypoint(x=127.00000000, y=207.00000000)]
Keypoints as array: [[ 99. 81.]
[125. 80.]
[112. 102.]
[102. 210.]
[127. 207.]]
Shape: (5, 2)
类似地,可以从(N, 2)
数组创建KeypointsOnImage
对象。 但请注意,您还必须通过shape
参数提供图像形状:
xy = np.float32([
[10, 20],
[50, 17],
[27.54, 49.13]
])
image_height = 50
image_width = 100
kpsoi_new = ia.KeypointsOnImage.from_coords_array(xy, shape=(image_height, image_width, 3))
print(kpsoi_new)
KeypointsOnImage([Keypoint(x=10.00000000, y=20.00000000), Keypoint(x=50.00000000, y=17.00000000), Keypoint(x=27.54000092, y=49.13000107)], shape=(50, 100, 3))
下一章:imgaug数据增强神器:第五章 增强边界框