Image Processing 必备(十一):Imgaug之控制流的使用

Date 2020-09-17

官方教程:https://nbviewer.jupyter.org/github/aleju/imgaug-doc/blob/master/notebooks/C02%20-%20Using%20imgaug%20with%20more%20Control%20Flow.ipynb

使用imgaug的标准形式是一种延迟 的方式,即首先构建增强序列,然后多次应用它来增强数据。在此过程中,imgaug几乎完全自己处理增强操作。这种形式类似于tensorflow。在imgaug的情况下,它有几个优点:

  • 它允许在构建序列Sequential(... ,random_order=True)设置顺序随机,也就是Sequential中的增强方法可以随机的使用,而不是按照顺序one-by-one。

  • 它允许通过Sometimes()或者SomeOf()等方式,设置随机序列中哪些增强器进行使用,哪些不使用

  • 它允许使用一个入口点来运行(经过测试的)多核扩展。在imgaug的情况下,方法augmter .pool()就是这样一个入口点。它启动了多处理的包装器。为增强而优化的池(例如,在子进程之间使用不同的随机状态,以确保每个CPU内核生成不同的增强)。

然而,它也有缺点,主要缺点是错误可能很难调试

如果不需要上面提到的优点,可以以一种非延迟的方式执行imgaug,类似于pytorch。它的实现与imgaug中的标准方法非常相似,不同之处是需要实例化每个增强器,然后应用它。下面的代码块显示了一个示例:

 1 import imgaug as ia
 2 from imgaug import augmenters as iaa
 3 import imageio
 4 import numpy as np
 5 %matplotlib inline
 6  7 ia.seed(3)
 8  9 class AugSequence:
10     def __init__(self):
11         # instantiate each augmenter and save it to its own variable
12         self.affine = iaa.Affine(rotate=(-20, 20), translate_px={"x": (-10, 10), "y": (-5, 5)})
13         self.multiply = iaa.Multiply((0.9, 1.1))
14         self.contrast = iaa.LinearContrast((0.8, 1.2))
15         self.gray = iaa.Grayscale((0.0, 1.0))
16     
17     def augment_images(self, x):
18         # apply each augmenter on its own, one by one
19         x = self.affine(images=x)
20         x = self.multiply(images=x)
21         x = self.contrast(images=x)
22         x = self.gray(images=x)
23         return x
24 25 aug = AugSequence()   # 需要实例化
26 img = imageio.imread("samoye.jpg")
27 img_aug = aug.augment_images([img, img])  # 再应用
28 print("before")
29 ia.imshow(np.hstack([img, img]))
30 print("after")
31 ia.imshow(np.hstack(img_aug))

利用单个函数

上述示例中介绍了一种使用类的方式通过实例化实现一种非延迟的处理方式。这种方式可以不使用imgaug提供的Sequential。

当然,也可以直接使用函数实现这一过程,只不过这会带来少量的精度损失,毕竟参数每次都需要解析。 

 1 def augment_images(x):
 2     x = iaa.Affine(rotate=(-20, 20))(images=x)
 3     x = iaa.Multiply((0.9, 1.1))(images=x)
 4     x = iaa.LinearContrast((0.8, 1.2))(images=x)
 5     x = iaa.Grayscale((0.0, 1.0))(images=x)
 6     return x
 7  8 images_aug = augment_images([img, img])
 9 10 print("Before:")
11 ia.imshow(np.hstack([img, img]))
12 print("After:")
13 ia.imshow(np.hstack(images_aug))
Before:

png

After:

png

时间的测量

关于一个增强方法的初始化和执行所需的时间是可以测量的。

  • 初始化时间测量

%timeit -n 10000 iaa.Affine(translate_px=(-10, 10), scale=(0.9, 1.1), rotate=(-20, 20), shear=(-20, 20), mode=ia.ALL)
108 µs ± 4.87 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

可以看出,初始化的过程所需要的时间比较短,大约在0.1ms左右(在更好的设备上时间会更短)。也就是说,一个具有10个增强方法的增强序列初始化大约需要1ms左右,这大大小于增强过程所需要的时间。

  • 执行时间测量

1 %timeit -n 2500 aug.augment_images([img, img])
2 %timeit -n 2500 augment_images([img, img])
86.9 ms ± 858 µs per loop (mean ± std. dev. of 7 runs, 2500 loops each)
87.5 ms ± 639 µs per loop (mean ± std. dev. of 7 runs, 2500 loops each)

调用两次,前者是通过类构建的aug对象,后者是函数augment_images,二者具体相同的增强方法。时间上的区别可忽略不计。

单个函数处理非图像数据

在图像增强过程中,难免伴随着类似bbox、keypoints等非图像的数据。如果想要利用single-function的方式处理这类数据,需要手动的安排random_state,这并不难。如下述案例所示:

 1 seed = 2
 2 
 3 # 增强bbox
 4 def augment_bounding_boxes(x, seed):
 5     x = iaa.Affine(translate_px=(-60, 60), random_state=seed)(bounding_boxes=x)
 6     x = iaa.Multiply((0.9, 1.1), random_state=seed)(bounding_boxes=x)
 7     x = iaa.LinearContrast((0.8, 1.2), random_state=seed)(bounding_boxes=x)
 8     x = iaa.Grayscale((0.0, 1.0), random_state=seed)(bounding_boxes=x)
 9     return x
10 
11 # 增强图像
12 def augment_images(x, seed):
13     x = iaa.Affine(translate_px=(-60, 60), random_state=seed)(images=x)
14     x = iaa.Multiply((0.9, 1.1), random_state=seed)(images=x)
15     x = iaa.LinearContrast((0.8, 1.2), random_state=seed)(images=x)
16     x = iaa.Grayscale((0.0, 1.0), random_state=seed)(images=x)
17     return x
18 # 区别在于x给bbox还是给images
19 
20 # 生成bbox
21 bbsoi = ia.BoundingBoxesOnImage(bounding_boxes=
22                                [ia.BoundingBox(x1=65, y1=1 , x2=417 , y2=396)],
23                                shape=img.shape)
24 
25 # 读取图像
26 img = imageio.imread("samoye.jpg")
27 # 图像增强
28 image_aug = augment_images([img, img], seed)
29 # bbox增强
30 bbsoi_aug = augment_bounding_boxes([bbsoi, bbsoi], seed)
31 # 可视化
32 print("before")
33 ia.imshow(np.hstack([bbsoi.draw_on_image(img, size=3),
34                     bbsoi.draw_on_image(img, size=3)]))
35 print("after")
36 ia.imshow(np.hstack([bbsoi_aug[0].draw_on_image(image_aug[0], size=3),
37                     bbsoi_aug[1].draw_on_image(image_aug[1], size=3)]
38                    ))
before

png

after

png

整理总结

本节主要介绍了两种不使用Sequential创建序列的方式:类和函数。并引入了时间测量和处理非图像数据的方式(bbox,keypoints)。

处理非图像数据需要手动传入random_state,保证在图像和非图像数据的一致性。

原文地址:https://www.cnblogs.com/monologuesmw/p/13691849.html