数据增广imgaug库的使用

记录一下这两天用imgaug库做数据增广的代码,由于是算用算学的,所以只能把代码写出来,具体每种增广算法的原理和一些参数就不得而知了,不过我觉得也没必要把这么些个算法搜搞懂,毕竟重点是扩种数据。所以,如果你想深入的学习imgaug这个库的话那么这篇文章不适合你。不过这里有官方文档传送门,还有一篇非常详细的博文,同时本文就是参考以上博文才写出的代码。而本文主要是一个数据增广的实际案例,代码完整,可供参考。

查看每种增广操作的效果

由于本人在进行写代码的时候想看看每种操作作用完之后的效果,所以就想着写了一段代码,直接将增广操作复制到指定位置后运行就可直接输出作用前后的效果对比图。代码如下:

'''
该程序用于查看imgaug中的增广算法的作用效果
1. 修改代码第四行的 op 后的增广算法
2. 修改操作的图片的路径
3. 通过显示的图像课观察到增广效果
4. 该效果是经过op 和 op_ 两种操作叠加而成的图片
5. op_ 操作为剪切和填充
6. 如果想单独看 op 效果可以将代码12行[op, op_]中的op_去掉
'''

from imgaug import augmenters as iaa
import imgaug as ia

op = iaa.CoarseDropout(0.02, size_percent=0.15, per_channel=0.5) # 可修改成别的增广算法

op_ = iaa.CropAndPad(
    percent=(0, 0.2),
    pad_mode=["constant", "edge"], 
    pad_cval=(0, 255)
)

seq = iaa.Sequential([ op , op_])
imgList = [cv2.imread("NewNewImage/22.jpg"),cv2.imread("NewNewImage/52.jpg")] # 修改成图片路径
img_aug = seq.augment_images(imgList)
import matplotlib.pyplot as plt
import cv2
plt.figure(figsize=(8,8))
plt.subplot(2,2,1)
plt.imshow(cv2.cvtColor(imgList[0],cv2.COLOR_BGR2RGB))
plt.subplot(2,2,2)
plt.imshow(cv2.cvtColor(img_aug[0],cv2.COLOR_BGR2RGB))
plt.subplot(2,2,3)
plt.imshow(cv2.cvtColor(imgList[1],cv2.COLOR_BGR2RGB))
plt.subplot(2,2,4)
plt.imshow(cv2.cvtColor(img_aug[1],cv2.COLOR_BGR2RGB))
plt.show()

实例代码

定义多种增广操作

from imgaug import augmenters as iaa
import imgaug as ia

# 将图像转换为HSV,然后将每个像素的H值增加10到50
op_1 = iaa.WithColorspace(
    to_colorspace="HSV",
    from_colorspace="RGB",
    children=iaa.WithChannels(0, iaa.Add((10, 50)))
)

op_2 = iaa.WithChannels(0, iaa.Add((10,50))) # BGR中的B值随机增加10-50,因为cv2读取的图片为BGR顺序,下同
op_3 = iaa.WithChannels(1, iaa.Add((10,50))) # BGR中的G值随机增加10-50
op_4 = iaa.WithChannels(2, iaa.Add((10,50))) # BGR中的R值随机增加10-50

op_5 = iaa.WithChannels(0, iaa.Affine((10, 180))) # BGR中的B值随机旋转10-180°
op_6 = iaa.WithChannels(1, iaa.Affine((10, 180))) # BGR中的G值随机旋转10-180°
op_7 = iaa.WithChannels(2, iaa.Affine((10, 180))) # BGR中的R值随机旋转10-180°

op_8 = iaa.Noop() # 无操作增广

# 用黑色像素替换每个图像的每5行 
def img_func(images, random_state, parents, hooks):
    for img in images:
        img[::5] = 0
    return images
def keypoint_func(keypoints_on_images, random_state, parents, hooks):
    return keypoints_on_images
op_9 = iaa.Lambda(img_func, keypoint_func)

# 裁剪并填充 负则裁剪,正则填充
op_10 = iaa.CropAndPad(percent=(-0.2, 0.2))

op_11 = iaa.CropAndPad(
    percent=(0, 0.2), # 每边填充0至20%
    pad_mode=["constant", "edge"], # 填充方式为恒定值(constant)或边缘值(edge)
    pad_cval=(0, 255) # 若为恒定值,则从0-255中随机取值
)

op_12 = iaa.CropAndPad(
    px=((0, 30), (0, 10), (0, 30), (0, 10)), # 顶部填充0-30px,右侧0-10px,底部0-30px,左侧0-10px
    pad_mode=ia.ALL,
    pad_cval=(0, 255)
)

op_13 = iaa.Fliplr() # 水平翻转所有图片
op_14 = iaa.Flipud() # 垂直反转所有图片

# 每个图像生成16到128个超像素。 用平均像素颜色替换每个超像素的概率在10到50%之间(每个图像采样一次)
op_15 = iaa.Superpixels(p_replace=(0.1, 0.5), n_segments=(16, 128))

# 将图像更改为灰度,并通过改变强度将其与原始图像叠加,有效地删除0到80%的颜色
op_16 = iaa.Grayscale(alpha=(0.0, 0.8))

op_17 = iaa.GaussianBlur(sigma=(0.0, 2.0)) # 高斯模糊,σ=0-2

# 在图像中添加-50到50之间的随机值。 
#在50%的图像中,每个通道的值不同(3个采样值)。 
#在剩下的50%图像中,所有通道的值都相同
op_18 = iaa.Add((-50, 50),per_channel=0.5) 

# 添加高斯噪音 
# 每个像素从正态分布N(0,s)采样一次,s对每个图像采样并在0和0.1 * 255之间变化
op_19 = iaa.AdditiveGaussianNoise(scale=(0, 0.1*255))

# 丢弃2%的图像,但是在具有原始大小的50%的图像的较低分辨率版本上执行此操作,丢弃2x2个正方形。 
# 此外,在50%的图像通道中执行此操作,以便仅将某些通道的信息设置为0,而其他通道保持不变
op_20 = iaa.CoarseDropout(0.02, size_percent=0.15, per_channel=0.5)

operation_list = [op_1, op_7, op_8, op_9, op_10,
                  op_11, op_12, op_13, op_14, op_16, op_17, op_18, op_19, op_20,]

将图片分批

new_image_text.txt这个文本文件是图像列表,其中每一行保存的是一个图片的路径和对应的类别。

例如NewImage/10.jpg 7表示该图片的路径为NewImage/10.jpg,其类别属于7

## 将数据分批,每批含有batch_size个图像
with open("new_image_text.txt") as img_info:
    batch_size = 10 # 每个batch的大小
    img_batchs = []
    img_label_batchs = []
    flag = 0
    while True:
        if flag % batch_size == 0:
            img_batchs.append([])
            img_label_batchs.append([])
        img = img_info.readline()
        if(img == ""):
            break
        img = img.split(" ")
        img_batchs[-1].append(img[0]) 
        img_label_batchs[-1].append(int(img[1]))
        flag += 1
        if flag >=10000: # 避免进入死循环而必须重启项目
            break
    if img_batchs[-1] == []:
        img_batchs.pop()
        img_label_batchs.pop()

数据增广

先了解一下Sequential()SomeOf()两种方法之间的区别 ;

iaa.Sequential(children=None,
               random_order=False,
               name=None,
               deterministic=False,
               random_state=None)
  • children: 想要应用在图像上的Augmenter或者Augmenter集合。默认None
  • random_order: bool类型, 默认False。是否对每个batch的图片应用不同顺序的Augmenter list。当设置为True时,不同batch之间图片的处理顺序都会不一样,但是同一个batch内顺序相同。
  • deterministic: bool类型, 默认False。
iaa.SomeOf(n=None,
           children=None,
           random_order=False,
           name=None,
           deterministic=False,
           random_state=None)
  • n: 从总的Augmenters中选择多少个。可以是一个int, tuple, list或者随机值。
  • random_order: 是否每次顺序不一样。
# 数据增广,每张图片扩充30张
img_name = 1000 # 每张图片的名字,依次递增
with open("new_image_text.txt","a") as img_text:
    for epoch in range(20): # 原始图片循环增广20次
        for someof_n in [1, 1, 2, 2]: # 对应于SomeOf中的参数someof_n
            seq = iaa.SomeOf(someof_n, operation_list) # 使用的是SomeOf,区别于Sequential
            for batch_ind, img_batch in enumerate(img_batchs):
                img_batch = [cv2.imread(path) for path in img_batch]
                imgs_aug = seq.augment_images(img_batch)
                for i, save_img in enumerate(imgs_aug):
                    save_img_path = f"NewImage/{str(img_name)}.jpg" # 保存路径
                    save_img_label = img_label_batchs[batch_ind][i]
                    cv2.imwrite(save_img_path, save_img) # 保存图片
                    img_text.write(save_img_path+" "+str(save_img_label)+"\n") # 保存图像列表
                    img_name += 1

看看效果

参考

  1. imgaug学习笔记
  2. imgaug数据增强神器:增强器一览
posted @ 2020-06-07 22:09  世纪小小孟  阅读(2295)  评论(0编辑  收藏  举报