官网:https://imgaug.readthedocs.io/en/latest/
教程:https://nbviewer.jupyter.org/github/aleju/imgaug-doc/blob/master/notebooks/A01 - Load and Augment an Image.ipynb
使用imgaug
扩充图像只需几行代码。 但在此之前,我们首先要加载图像。 imgaug
期望图像是numpy数组,并且最好使用dtype uint8
,即当数组的值在0
到255
范围内时。通道轴应该总是最后一个轴,并且可以跳过灰度图像。 对于非灰度图像,预期的输入颜色空间是RGB。
如果您使用其他dtypes而不是uint8
,例如float32
,建议您查看dtype文档,以获得每个增强器的dtype支持的概述。 API包含更多详细信息。 请记住,uint8始终是经过最彻底测试的dtype
由于imgaug
只处理增强而不是图像输入/输出,我们需要另一个库来加载我们的图像。python中的常见选择是imageio
,我们将在下面使用它。 另一个常见的选择是OpenCV,方法是cv2.imread()
。 但请注意,cv2.imread()
返回BGR色彩空间中的图像而不是RGB,这意味着您必须重新排序通道轴,例如,通过cv2.imread(path)[:, :, ::-1]
。 或者,您也可以将每个与颜色空间相关的增强器更改为BGR(例如,Grayscale
或任何增强器改变色调/饱和度)。有关每个增强器的详细信息,请参阅API。 后一种方法的缺点是所有可视化功能(例如下面的imgaug.imshow()
仍然期望RGB数据,因此BGR图像会很难看。
让我们看第一个例子。 我们将使用imageio.imread()
来加载图像并对其进行增强。 在下面的代码块中,我们调用imageio.imread(uri)
直接从维基百科加载图像,但我们也可以从文件路径加载它,例如 通过imagio.imread("/path/to/the/file.jpg")
或Windows下imagio.imread("C:\\path\to\the\file.jpg")
。 imageio.imread(uri)
返回dtypeuint8
,形状(height, width, channels)
和RGB颜色空间的numpy数组。 这正是我们所需要的。 加载图像后,我们使用imgaug.imshow(array)
来显示加载的图像。
import imageio
import imgaug as ia
%matplotlib inline
image = imageio.imread("https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png")
print("Original:")
ia.imshow(image)
现在我们已经加载了图像,让我们来增强它。 imgaug
包含许多以Augmenter
父类派生的类形式的扩充技术。 要使用一种增强技术,我们必须使用一组超参数对其进行实例化,然后再多次应用它。 我们的第一个增强技术将是Affine
,即仿射变换。 我们在这里保持简单,并使用该技术简单地将图像旋转-25°和+ 25°之间的随机值。
from imgaug import augmenters as iaa
ia.seed(4)
rotate = iaa.Affine(rotate=(-25, 25))
image_aug = rotate.augment_image(image)
print("Augmented:")
ia.imshow(image_aug)
当然,实际上我们很少仅增强单个图像。 标准方案更倾向于增强大批量的图像。 imgaug
提供函数augment_images(images)
来增强图像批次。 它通常比通过augment_image(image)
单独增加每个图像快得多。
所以让我们尝试使用图像批处理功能。 为简单起见,我们只复制原始图像几次,通过augment_images
做到。 为了可视化我们的结果,我们使用numpy的hstack()
函数,它通过将增强批处理中的图像水平放置在一起来将它们组合成一个大图像。
import numpy as np
images = [image, image, image, image]
images_aug = rotate.augment_images(images)
print("Augmented batch:")
ia.imshow(np.hstack(images_aug))
如您所见,批处理中的所有图像都会自动旋转不同的数量。这是因为当通过rotate = iaa.Affine(rotate=(-25, 25))
实例化我们的仿射变换时,我们使用了一个旋转间隔,给定为(-25, 25)
,表示均匀分布旋转rotate ~ uniform(-25, 25)
。我们也可以选择一个常数值rotate=-25
来始终旋转-25°或list rotate=[-25, -15, 0]
旋转-25°或-15°或0°。我们还可以选择许多其他概率分布,例如高斯分布或泊松分布。请查看其他notebooks或文档,了解有关如何执行此操作的详细信息。
请注意,在上面的示例中,我们使用list将我们的图像组合到一个批处理中。我们还可以提供单个numpy array形状(N, H, W, [C])
,其中N
是图像的数量,H
是它们的高度,W
是它们的宽度,C
可选,是通道轴。通常首选numpy array,因为它们可以节省内存并且可以更快地增加。但是,如果您的图像具有不同的高度宽度或通道数,则它们无法组合到单个array中,因此必须使用list。
仅执行仿射旋转用处不大。 因此,在接下来的示例中,我们将组合几种技术并将它们同时应用于图像。 要做到这一点,我们可以实例化每个技术并通过多次调用augment_images()
一个接一个地应用它们,但这很麻烦的。 imgaug
提供了一个名为Sequential
的简单助手,它结合了几种增强技术。 我们将使用它将仿射旋转应用于图像(Affine
),添加一些高斯噪声(AdditiveGaussianNoise
)并从图像边缘移除0-20%来裁剪图像(Crop
)。
seq = iaa.Sequential([
iaa.Affine(rotate=(-25, 25)),
iaa.AdditiveGaussianNoise(scale=(10, 60)),
iaa.Crop(percent=(0, 0.2))
])
images_aug = seq.augment_images(images)
print("Augmented:")
ia.imshow(np.hstack(images_aug))
一些图像放大了,因为使用了裁剪Crop
。但所有图像的大小仍然相同,默认情况下裁剪保留输入图像大小。即使在移除像素之后,也会自动将剩余图像的大小调整回输入大小。 如果您更喜欢不调整大小以恢复原始图像大小,请实例化Crop
为Crop(..., keep_size=False)
,其中keep_size
表示“保持输入和输出之间的图像大小不变”。
上面,我们使用Sequential
结合了几种增强技术。实际上,我们也可以将每种技术保存在列表中,并手动迭代列表以自行应用每种技术。因此,虽然Sequential
简化了操作,但它并没有太大作用。但是,它确实自带了一个便利能力——随机顺序增强。如果激活,它会以随机顺序应用增强,大大增加了图像增强的可能,而且我们不必自己实现。
在下一个例子中,我们将使用该功能。只需将random_order=True
添加到Sequential
即可。为了使操作更加明显,我们增加了增强的强度并显示更多图像。另请注意我们如何通过循环增强输入图像八次而不是使用augment_images()
。这是因为每次随机操作是批量采样,而不是逐个采样。为了看到不同的操作,我们因此增加了几次。但是,在实际的训练场景中,您应该使用更快的augment_images()
。
seq = iaa.Sequential([
iaa.Affine(rotate=(-25, 25)),
iaa.AdditiveGaussianNoise(scale=(30, 90)),
iaa.Crop(percent=(0, 0.4))
], random_order=True)
images_aug = [seq.augment_image(image) for _ in range(8)]
print("Augmented:")
ia.imshow(ia.draw_grid(images_aug, cols=4, rows=2))
仔细看看上面的图片。 一些旋转前裁剪,一些旋转后裁剪,一些高斯噪声添加到黑色像素,有些则没有。 一些仿射旋转后填充黑色像素。
上面已经提到imgaug
支持不同大小的图像的批处理,但到目前为止我们使用了相同的图像。 以下示例显示了具有不同大小图像的例子。 我们从维基百科中加载三个图像,将它们作为单个批次进行增强,然后逐个显示每个图像(具有输入和输出形状)。 我们这次也使用了一些不同的增强技术。
seq = iaa.Sequential([
iaa.CropAndPad(percent=(-0.2, 0.2), pad_mode="edge"), # crop and pad images
iaa.AddToHueAndSaturation((-60, 60)), # change their color
iaa.ElasticTransformation(alpha=90, sigma=9), # water-like effect
iaa.CoarseDropout((0.01, 0.1), size_percent=0.01) # set large image areas to zero
], random_order=True)
# load images with different sizes
images_different_sizes = [
imageio.imread("https://upload.wikimedia.org/wikipedia/commons/e/ed/BRACHYLAGUS_IDAHOENSIS.jpg"),
imageio.imread("https://upload.wikimedia.org/wikipedia/commons/c/c9/Southern_swamp_rabbit_baby.jpg"),
imageio.imread("https://upload.wikimedia.org/wikipedia/commons/9/9f/Lower_Keys_marsh_rabbit.jpg")
]
# augment them as one batch
images_aug = seq.augment_images(images_different_sizes)
# visualize the results
print("Image 0 (input shape: %s, output shape: %s)" % (images_different_sizes[0].shape, images_aug[0].shape))
ia.imshow(np.hstack([images_different_sizes[0], images_aug[0]]))
print("Image 1 (input shape: %s, output shape: %s)" % (images_different_sizes[1].shape, images_aug[1].shape))
ia.imshow(np.hstack([images_different_sizes[1], images_aug[1]]))
print("Image 2 (input shape: %s, output shape: %s)" % (images_different_sizes[2].shape, images_aug[2].shape))
ia.imshow(np.hstack([images_different_sizes[2], images_aug[2]]))
下一章:imgaug数据增强神器:第二章 随机模式和确定模式