赞
踩
本文为本人学习imgaug 笔记,来源于
imgaug是一个封装好的用来进行图像augmentation的python库,支持关键点(keypoint)和bounding box一起变换。
# 通过pypi安装
pip install imgaug
# 卸载
pip uninstall imgaug
首先定义一个变换序列,然后直接将图像batch传入即可:
from imgaug import augmenters as iaa seq = iaa.Sequential([ iaa.Crop(px=(0, 16)), # 从每边裁剪图像0到16px(随机选择) iaa.Fliplr(0.5), #0.5是概率,水平翻转50%的图像 iaa.GaussianBlur(sigma=(0, 3.0)) # 用0到3.0的σ模糊图像 ]) for batch_idx in range(1000): # 'images'应该是一个4D numpy数组的形状(N,高度,宽度,通道) # 或一个3D numpy数组列表,每个数组都有形状(高度、宽度、通道)。 # 灰度图像必须有形状(高度,宽度,1)每个。 # 所有图片必须有numpy的dtype uint8。值被期望在 # 范围0-255。 images = load_batch(batch_idx) images_aug = seq.augment_images(images) train_on_images(images_aug)
import cv2 import numpy as np from imgaug import augmenters as iaa import imgaug as ia # 定义一个lambda表达式,以p=0.5的概率去执行sometimes传递的图像增强 sometimes = lambda aug: iaa.Sometimes(0.5, aug) # 建立一个名为seq的实例,定义增强方法,用于增强 aug = iaa.Sequential( [ iaa.Fliplr(0.5), # 对50%的图像进行镜像翻转 iaa.Flipud(0.2), # 对20%的图像做左右翻转 sometimes(iaa.Crop(percent=(0, 0.1))), # 这里沿袭我们上面提到的sometimes,对随机的一部分图像做crop操作 # crop的幅度为0到10% # 或者 sometimes(iaa.Crop(px=(0, 16))),随机在距离边缘的0-16像素中选择crop范围 # 对一部分图像做仿射变换 sometimes(iaa.Affine( scale={"x": (0.8, 1.2), "y": (0.8, 1.2)}, # 图像缩放为80%到120%之间 translate_percent={"x": (-0.2, 0.2), "y": (-0.2, 0.2)}, # 平移±20%之间 rotate=(-45, 45), # 旋转±45度之间 shear=(-16, 16), # 剪切变换±16度,(矩形变平行四边形) order=[0, 1], # 使用最邻近差值或者双线性差值 cval=(0, 255), # 全白全黑填充 mode=ia.ALL # 定义填充图像外区域的方法 )), # 使用下面的0个到5个之间的方法去增强图像。注意SomeOf的用法 iaa.SomeOf((0, 5), [ # 将部分图像进行超像素的表示。o(╥﹏╥)o用超像素增强作者还是第一次见,比较孤陋寡闻 sometimes( iaa.Superpixels( p_replace=(0, 1.0), n_segments=(20, 200) ) ), # 用高斯模糊,均值模糊,中值模糊中的一种增强。注意OneOf的用法 iaa.OneOf([ iaa.GaussianBlur((0, 3.0)), iaa.AverageBlur(k=(2, 7)), # 核大小2~7之间,k=((5, 7), (1, 3))时,核高度5~7,宽度1~3 iaa.MedianBlur(k=(3, 11)), ]), # 锐化处理 iaa.Sharpen(alpha=(0, 1.0), lightness=(0.75, 1.5)), # 浮雕效果 iaa.Emboss(alpha=(0, 1.0), strength=(0, 2.0)), # 边缘检测,将检测到的赋值0或者255然后叠在原图上 sometimes(iaa.OneOf([ iaa.EdgeDetect(alpha=(0, 0.7)), iaa.DirectedEdgeDetect( alpha=(0, 0.7), direction=(0.0, 1.0) ), ])), # 加入高斯噪声 iaa.AdditiveGaussianNoise( loc=0, scale=(0.0, 0.05 * 255), per_channel=0.5 ), # 将1%到10%的像素设置为黑色 # 或者将3%到15%的像素用原图大小2%到5%的黑色方块覆盖 iaa.OneOf([ iaa.Dropout((0.01, 0.1), per_channel=0.5), iaa.CoarseDropout( (0.03, 0.15), size_percent=(0.02, 0.05), per_channel=0.2 ), ]), # 5%的概率反转像素的强度,即原来的强度为v那么现在的就是255-v iaa.Invert(0.05, per_channel=True), # 每个像素随机加减-10到10之间的数 iaa.Add((-10, 10), per_channel=0.5), # 像素乘上0.5或者1.5之间的数字. iaa.Multiply((0.5, 1.5), per_channel=0.5), # 将整个图像的对比度变为原来的一半或者二倍 iaa.ContrastNormalization((0.5, 2.0), per_channel=0.5), # 将RGB变成灰度图然后乘alpha加在原图上 iaa.Grayscale(alpha=(0.0, 1.0)), # 把像素移动到周围的地方。这个方法在mnist数据集增强中有见到 sometimes( iaa.ElasticTransformation(alpha=(0.5, 3.5), sigma=0.25) ), # 扭曲图像的局部区域 sometimes(iaa.PiecewiseAffine(scale=(0.01, 0.05))) ], random_order=True # 随机的顺序把这些操作用在图像上 ) ], random_order=True # 随机的顺序把这些操作用在图像上 ) # 数据增强,针对单张图片 image = cv2.imread('1.jpg', 0) h = image.shape[0] w = image.shape[1] enhance_num = 32 aug_example_img = aug.augment_image(image=image) print(image.shape, aug_example_img.shape) # 生成一个图片列表 example_images = np.array( [image for _ in range(enhance_num)], dtype=np.uint8 ) aug_imgs = aug(images=example_images) # images_aug = aug.augment_images(images=img_array) # 显示图片 ia.show_grid(aug_imgs, rows=4, cols=8) # 保存图片 for i in range(aug_imgs.shape[0]): img = aug_imgs[i] cv2.imwrite("aug_%d.jpg" % i, img) # 保存为一张图片 img_array = np.array([image] * enhance_num, dtype=np.uint8) write_img = np.zeros(shape=(h, (w+10) * enhance_num, 3), dtype=np.uint8) for j, item in enumerate(aug_imgs): write_img[:, j * (w + 10): j * (w + 10) + w, :] = item
先导入Augmenters类
from imgaug import augmenters as iaa
产生一个处理图片的 Sequential 函数原型:
from imgaug import augmenters as iaa
iaa.Sequential(children=None,
random_order=False,
name=None,
deterministic=False,
random_state=None)
参数:
将Augmenter中的部分变换应用在图片处理上,而不是应用所有的Augmenter。例如:可以定义20种变换,但每次只选择其中的5个。但是不支持固定选择某一个Augmenter。
函数原型:
from imgaug import augmenters as iaa
iaa.SomeOf(n=None,
children=None,
random_order=False,
name=None,
deterministic=False,
random_state=None)
参数:
例子:
# 每次选择一个翻转方式 seq = iaa.SomeOf(1, [ iaa.Fliplr(1.0), iaa.Flipud(1.0) ]) imgs_aug = seq.augment_images(imgs) # 每次使用1~3个Augmenter来处理图片,每个batch中的Augmenters顺序一样。 seq = iaa.SomeOf((1, 3), [ iaa.Fliplr(1.0), iaa.Flipud(1.0), iaa.GaussianBlur(1.0) ]) imgs_aug = seq.augment_images(imgs) # 每次使用1到多个Augmenter来处理图片,每个batch中的Augmenters顺序不一样。 seq = iaa.SomeOf((1, None), [ iaa.Fliplr(1.0), iaa.Flipud(1.0), iaa.GaussianBlur(1.0) ], random_order=True) imgs_aug = seq.augment_images(imgs)
每次从一系列Augmenters中选择一个来变换。
iaa.OneOf(children,
name=None,
deterministic=False,
random_state=None)
参数含义与上面一样。
对batch中的一部分图片应用一部分Augmenters,剩下的图片应用另外的Augmenters。
iaa.Sometimes(p=0.5,
then_list=None,
else_list=None,
name=None,
deterministic=False,
random_state=None)
在某个特定的颜色空间对图像进行变换。即:先将图片从一个颜色空间变换到另一个颜色空间,然后在另一个颜色空间中对图像进行变换,最后再变换回原来的颜色空间。
iaa.WithColorspace(to_colorspace,
from_colorspace='RGB',
children=None,
name=None,
deterministic=False,
random_state=None)
# 先将图片从RGB变换到HSV,然后将H值增加10,然后再变换回RGB。
aug = iaa.WithColorspace(to_colorspace="HSV", from_colorspace="RGB",
children=iaa.WithChannels(0, iaa.Add(10)))
从图片中挑选出一个Channel来进行变换,变换完了之后再将该channel merge回去。
iaa.WithChannels(channels=None,
children=None,
name=None,
deterministic=False,
random_state=None)
参数:
不进行任何变换。某些情况下只想使用一个Augmenter作为占位符,这样可以继续调用augment_image()函数,但实际不作变换。例如进行测试的时候可以使用这个。
自定义一些变换函数。
iaa.Lambda(func_images,
func_keypoints,
name=None,
deterministic=False,
random_state=None)
参数:
function(images, random_state, parents, hooks)
function(keypoints_on_images, random_state, parents, hooks)
例子:
def func_images(images, random_state, parents, hooks):
images[:, ::2, :, :] = 0
return images
def func_keypoints(keypoints_on_images, random_state, parents, hooks):
return keypoints_on_images
aug = iaa.Lambda(
func_images=func_images,
func_keypoints=func_keypoints
)
将每张图片没隔两行的像素点变成黑色的条带,关键点保留。
assert要变换的图片和keypoint的shape。如果不满足就抛出异常。
iaa.AssertShape(shape,
check_images=True,
check_keypoints=True,
name=None,
deterministic=False,
random_state=None)
参数:
# 检查输入的每张图片是否是32×32×3的,如果是则执行水平翻转,否则报错
seq = iaa.Sequential([
iaa.AssertShape((None, 32, 32, 3)),
iaa.Fliplr(0.5)
])
# 先检查图片的高度是否是32<=H<64, 宽度是否是32, channel是否是1或者3。如果都满足则执行水平翻转,否则报错。
seq = iaa.Sequential([
iaa.AssertShape((None, (32, 64), 32, [1, 3])),
iaa.Fliplr(0.5)
])
将图像缩放到固定大小。
iaa.Scale(size,
interpolation='cubic',
name=None,
deterministic=False,
random_state=None)
参数:
nearest, linear, area, cubic
。如果是int list或者string list, 则每张图片会从中随机选取一个。截取(crop)或者填充(pad),填充时,被填充区域为黑色。
iaa.CropAndPad(px=None,
percent=None,
pad_mode='constant',
pad_cval=0,
keep_size=True,
sample_independently=True,
name=None,
deterministic=False,
random_state=None)
参数:
constant, edge, linear_ramp, maximum, median, minimum, reflect, symmetric, wrap
。具体含义可查numpy文档。float、int、float tuple、int tuple、float list、int list
。当pad_mode=constant的时候选择填充的值。与iaa.CropAndPad()相同,只接受positive values。
与iaa.CropAndPad()相同,只接受negative values。
水平镜面翻转。
iaa.Fliplr(p=0, name=None, deterministic=False, random_state=None)
参数:
上下翻转,与上面相同。
改变图像空间。
iaa.ChangeColorspace(to_colorspace, from_colorspace='RGB', alpha=1.0, name=None, deterministic=False, random_state=None)
参数:
int, float, int tuple, float tuple
。变成灰度图。
iaa.Grayscale(alpha=0, from_colorspace='RGB', name=None, deterministic=False, random_state=None)
参数:
高斯扰动。
iaa.GaussianBlur(sigma=0, name=None, deterministic=False, random_state=None)
参数:
float, float tuple
。常见的有0,不扰动。3,强扰动。从最邻近像素中取均值来扰动。
iaa.AverageBlur(k=1, name=None, deterministic=False, random_state=None)
参数:
int, int tuple
。当为int tuple
时,如果每个元素也是tuple
,每个元素分别作为height和width,窗口大小不一致。通过最近邻中位数来扰动。
iaa.MedianBlur(k=1, name=None, deterministic=False, random_state=None)
与上面相同。
对图像使用卷积。
iaa.Convolve(matrix=None, name=None, deterministic=False, random_state=None)
锐化。
iaa.Sharpen(alpha=0, lightness=1, name=None, deterministic=False, random_state=None)
浮雕效果。
iaa.Emboss(alpha=0, strength=1, name=None, deterministic=False, random_state=None)
边缘检测。
iaa.EdgeDetect(alpha=0, name=None, deterministic=False, random_state=None)
特定方向的边缘检测。
iaa.DirectedEdgeDetect(alpha=0, direction=(0.0, 1.0), name=None, deterministic=False, random_state=None)
随机加上一个值。
iaa.Add(value=0, per_channel=False, name=None, deterministic=False, random_state=None)
按像素加。
iaa.AddElementwise(value=0, per_channel=False, name=None, deterministic=False, random_state=None)
添加高斯噪声。
iaa.AdditiveGaussianNoise(loc=0, scale=0, per_channel=False, name=None, deterministic=False, random_state=None)
给图像中的每个像素点乘一个值使得图片更亮或者更暗。
iaa.Multiply(mul=1.0, per_channel=False, name=None, deterministic=False, random_state=None)
按像素值乘。
iaa.MultiplyElementwise(self, mul=1.0, per_channel=False, name=None, deterministic=False, random_state=None)
随机去掉一些像素点, 即把这些像素点变成0。
iaa.Dropout(p=0, per_channel=False, name=None, deterministic=False, random_state=None)
将矩形框的值设置为0。
iaa.CoarseDropout(p=0, size_px=None, size_percent=None, per_channel=False, min_size=4, name=None, deterministic=False, random_state=None)
将每个像素值p变成255-p。
iaa.Invert(p=0, per_channel=False, min_value=0, max_value=255, name=None, deterministic=False, random_state=None)
改变图像的对比度。
iaa.ContrastNormalization(alpha=1.0, per_channel=False, name=None, deterministic=False, random_state=None)
仿射变换。包含:平移(Translation)、旋转(Rotation)、放缩(zoom)、错切(shear)。仿设变换通常会产生一些新的像素点,我们需要指定这些新的像素点的生成方法,这种指定通过设置cval
和mode
两个参数来实现。参数order
用来设置插值方法。
iaa.Affine(scale=1.0,
translate_percent=None,
translate_px=None,
rotate=0.0,
shear=0.0,
order=1,
cval=0,
mode='constant',
name=None, deterministic=False, random_state=None)
参数:
float, float tuple, dict
。如果是float
, 则所有图片按照这种比例缩放。如果是float tuple
, 则随机选取一个值来进行缩放,此时x-axis
和y-axis
的缩放比例相同。如果是一个dict
,则应该有两个key
:x, y
,每个x
或y
的值都可以是float, float tuple
,此时x-axis
和y-axis
的缩放比例不一样。float, float tuple, dict
,具体含义与scale相同。用正负来表示平移方向。int, int tuple, dict
,具体含义与translate_percent相同。float, float tuple
。float, int, float tuple, int tuple
。skimage
中定义相同。下面0和1方法快,3比较慢,4、5特别慢。可以是int, int list, ia.ALL
。如果是ia.ALL
,则每次从所有的插值方法中随机选取。
mode=constant
的时候才会生效。可以是int, float, tuple, ia.ALL
。如果是ia.ALL
,则会从[0,255]
之间随机选取一个值填充。string, string list, ia.ALL
。基本用法与上面相同。其中字符串的选取范围是:
随机放置一些规则的网格点然后移动这些点的周围的像素。这回导致局部的扭曲。
iaa.PiecewiseAffine(scale=0,
nb_rows=4,
nb_cols=4,
order=1,
cval=0,
mode='constant',
name=None, deterministic=False, random_state=None)
通过移动局部像素来变换。
iaa.ElasticTransformation(alpha=0,
sigma=0,
name=None,
deterministic=False,
random_state=None)
imgaug支持在图像变换的同时变换图像中的关键点。例子如下:
import imgaug as ia from imgaug import augmenters as iaa iaa.seed(1) image=ia.quokka(size=(256,256)) # 定义4个关键点 keypoints=ia.KeypointsOnImage([ ia.Keypoint(x=65, y=100), ia.Keypoint(x=75, y=200), ia.Keypoint(x=100, y=100), ia.Keypoint(x=200, y=80) ], shape=image.shape) # 定义一个变换序列 seq=iaa.Sequential([ iaa.Multiply((1.2, 1.5)), # 改变亮度,不影响关键点 iaa.Affine( rotate=10, scale=(0.5, 0.7) ) # 旋转10度然后缩放,会影响关键点 ]) # 固定变换序列,之后就可以先变换图像然后变换关键点,这样可以保证两次的变换完全相同。 # 如果调用次函数,需要在每次batch的时候都调用一次,否则不同的batch执行相同的变换。 seq_det = seq.to_deterministic() # 转换成list或者batch来变换。由于只有一张图片, 因此用[0]来取出该图和关键点。 image_aug = seq_det.augment_images([image])[0] keypoints_aug = seq_det.augment_keypoints([keypoints])[0] # print coordinates before/after augmentation (see below) # use after.x_int and after.y_int to get rounded integer coordinates for i in range(len(keypoints.keypoints)): before = keypoints.keypoints[i] after = keypoints_aug.keypoints[i] print("Keypoint %d: (%.8f, %.8f) -> (%.8f, %.8f)" % ( i, before.x, before.y, after.x, after.y) ) # 将关键点画在图片上。 # image with keypoints before/after augmentation (shown below) image_before = keypoints.draw_on_image(image, size=7) image_after = keypoints_aug.draw_on_image(image_aug, size=7) fig, axes = plt.subplots(2, 1, figsize=(20, 15)) plt.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.8, hspace=0.3, wspace=0.0) axes[0].set_title("image before") axes[0].imshow(image_before) axes[1].set_title("image after augmentation") axes[1].imshow(image_after) plt.show()
对应于BBox,存在两个API,一个用于生成BBox,另一个整合BBox。
BoundingBox
BoundingBoxesOnImage
对于BBox,通常用于目标检测中对物体进行标记,此处为矩形。因此,其通过左上角点和右下角点的坐标表示(x1,y1,x2,y2)。
其只受改变图像几何外观的图像增强技术的影响,高斯噪声之类的对其没有影响。
API: BoundingBox
BBox的输入参数:
imgaug.augmentables.bbs.BoundingBox(x1, y1, x2, y2, label=None):
可以看到,包含5个输入,4个坐标和1个物体类别标签label。
BoundingBox有一些重要的属性:.x1, .y1, .x2, .y2, .height, .width, .center_x, .center_y, .area
BBox的一些方法:
project(from_shape, to_shape) : 投射一个bbox从一个尺寸大小的图像到另一个尺寸大小。
*extend([all_sides], [top], [right], [bottom], [left]) *
*intersection(other, [default]) * :交集
*union(other) * :并集
*iou(other) * : 交并比
*is_fully_within_image(image) * 判断所有的bbox是否都在图像内
*is_partly_within_image(image) * 确定bbox至少有一部分在图像内
*clip_out_of_image(image) * :剪切掉在图像外侧的BBox
*shift([x], [y]) * : 移动bbox
*draw_on_image(image, [color], [alpha], [size], [copy], [raise_if_out_of_image]) *:绘制BBox和它的label
*draw_label_on_image(image, [color], [color_text], [color_bg], [alpha], [size], [size_text], [height], [copy], [raise_if_out_of_image]) * :只绘制label
*draw_box_on_image(image, [color], [alpha], [size], [copy], [raise_if_out_of_image) * :只绘制边框
*extract_from_image(image, [pad], [pad_max], [prevent_zero_size] *:从图像中提取边框中包含的像素
API:BoundingBoxesOnImage
BoundingBoxesOnImage()输入参数:
imgaug.augmentables.bbs.BoundingBoxesOnImage(bounding_boxes, shape)
BoundingBoxesOnImage中包含的一些方法:
on(image): 图形变化后bbox的再计算
*from_xyxy_array(xyxy, shape) *: 通过(N, 4)numpy数组生成
*to_xyxy_array([dtype]) *: 生成(N, 4)的numpy数组
*draw_on_image([color], [alpha], [size], [copy], [raise_if_out_of_image]) *:绘制bbox和image
*remove_out_of_image([fully], [partly]) *: 移除掉一些完全不在或者部分不在图像中的bbox
*clip_out_of_image() *: 剪切掉所有的bbox
*shift([x], [y]) *:平移所有的bbox
另外,imgaug中还有一些其他的API,例如增强BBOx和图像aug.augment(images=…, bounding_boxes=…) && aug.augment_bounding_boxes()。
import imgaug as ia
import imageio
from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
%matplotlib inline
ia.seed(1)
img = imageio.imread("samoye.jpg")
bbs = BoundingBoxesOnImage([
BoundingBox(x1=65, y1=1, x2=417, y2=396)], shape=img.shape)
ia.imshow(bbs.draw_on_image(img, size=2))
# 定义方法
from imgaug import augmenters as iaa
ia.seed(1)
seq = iaa.Sequential([iaa.GammaContrast(1.5),
iaa.Affine(translate_percent={"x":0.1}, scale=0.8)])
# 作用于图像和bbox上
image_aug, bbs_aug = seq(image=img, bounding_boxes=bbs)
# 取出结果
bbs_aug[0].x1, bbs_aug[0].y1, bbs_aug[0].x2, bbs_aug[0].y2
# 绘制
ia.imshow(bbs_aug.draw_on_image(image_aug, size=2))
image_aug, bbs_aug = iaa.Affine(rotate=45)(image=img, bounding_boxes=bbs)
ia.imshow(bbs_aug.draw_on_image(image_aug, size=1))
官方教程中使用的图像旋转后可以看到bbox,但bbox并未很好的跟随目标进行旋转。这里使用的图像旋转后,并不能看到bbox。官方教程中解释说这种问题源于非目标像素是边框的一部分。在旋转之后,必须绘制一个新的边界框来合并这些非对象像素。
bbox的draw_on_image()方法同样可以通过color、size、alpha等参数调节bbox的颜色 粗细 透明度。
import numpy as np
image_bbs = np.copy(img)
image_bbs = bbs.draw_on_image(img, color=[255, 0, 0], size=3)
print("color=[255,0,0],size=3,")
ia.imshow(image_bbs)
print("color=[0,255,0],size=10,alpha=0.5")
image_bbs_1=bbs.draw_on_image(img, color=[0,255,0],size=10,alpha=0.5)
ia.imshow(image_bbs_1)
color=[255,0,0],size=3,
color=[0,255,0],size=10,alpha=0.5
从中又可以看出,当size较大时,靠近边缘的bbox边界有可能绘制不出。
另外,bbox通常用于目标检测,需要添加目标的label进行可视化。bbox中还包含label的字段。当bbox初始化时包含了label,显示时就会直接显示label;若初始化时未赋值label,则需要赋值才可以显示。
bbs_label = bbs.deepcopy()
bbs_label[0].label = "dog"
image_bbs = bbs_label.draw_on_image(img, size=1)
ia.imshow(image_bbs)
但由于上边框贴近图像边缘,label并未绘制显示。
换一张图像…
image = imageio.imread("fox.jpg")
bbox = BoundingBoxesOnImage([BoundingBox(x1=58, y1=19, x2=203, y2=183)
], shape=image.shape)
bbox[0].label = "fox"
image_bbox = bbox.draw_on_image(image, size=2)
ia.imshow(image_bbox)
BoundingBox包含extract_from_image(image)方法,可以提取出目标区域的图像。
fox = bbox.bounding_boxes[0].extract_from_image(image)
ia.imshow(fox)
如果想要提取到目标及目标周边的一些区域,可以结合使用extend方法,先将bbox进行延伸,再提取延伸后的bbox区域的图像。
fox = bbox.bounding_boxes[0].extend(
all_sides=0, left=30, right=10).extract_from_image(image)
ia.imshow(fox)
除了extend方法,shift方法可以对bbox进行移动,就像Keypoints。
bb = bbox.bounding_boxes[0].shift(x=20, y=20)
ia.imshow(bb.draw_on_image(image, size=2))
ia.imshow(bb.extract_from_image(image))
综上所述,extend可以更改bbox的形状,可以扩张或者缩小bbox;而shift只能对bbox进行平移,不会影响bbox的尺寸。
同时,当对原有的bbox往y轴方向移动20个像素点,bbox将会处于图像外界。如上述第二张图像,会有一溜黑边。当然,如果不希望出现这种情况,可以增加参数pad=False,如下述图所示,生成的图像将不会有黑边。
bb = bbox.bounding_boxes[0].shift(x=20, y=20)
ia.imshow(bb.extract_from_image(image, pad=False))
当图像经过变换后,对应的bbox有可能部分处于图像的外侧,剪掉图像平面外的边界框的部分可以使用.clip_out_of_image()方法。下述代码首先将bbox移动到部分处于图像外侧,并对bbox进行裁剪。
print("-------------------")
print("shifted by 50 px - y")
print("-------------------")
bb = bbox.bounding_boxes[0].shift(y=50)
print("before clip")
ia.imshow(bb.draw_on_image(image, size=2))
ia.imshow(bb.extract_from_image(image))
bb_clip =bb.clip_out_of_image(image.shape)
print("after clip")
ia.imshow(bb_clip.draw_on_image(image, size=2))
ia.imshow(bb_clip.extract_from_image(image))
-------------------
shifted by 50 px - y
-------------------
before clip
after clip
可以看出,当剪切掉图像外侧的bbox后,在原图中显示的bbox可以很好的显示边界。
与Keypoints相同,bbox也具有应对图像缩放后保持bbox一致的方法:
project
on
import numpy as np
import imageio
import imgaug as ia
from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
from imgaug import augmenters as iaa
%matplotlib inline
img = imageio.imread("koala.jpg")
bbox = BoundingBoxesOnImage([BoundingBox(x1=26, y1=8, x2=109, y2=160)
, BoundingBox(x1=39, y1=4, x2=245, y2=194)], shape=img.shape)
bbox[0].label = "koala"
bbox[1].label = "koala"
ia.imshow(bbox.draw_on_image(img, size=2))
print(img.shape)
(194, 259, 3)
将图像缩放到120*120
img_resize = ia.imresize_single_image(img, (120, 120))
ia.imshow(img_resize)
print("Bounding box without changes:")
ia.imshow(bbox.draw_on_image(img_resize, size=2))
print("Bounding box with project(from, to)") # 需要对bbox中的Boundingbox进行处理
ia.imshow(bbox.bounding_boxes[0].project(from_shape=img.shape, to_shape=img_resize.shape).draw_on_image(img_resize, size=2, copy=False))
ia.imshow(bbox.bounding_boxes[1].project(from_shape=img.shape, to_shape=img_resize.shape).draw_on_image(img_resize, size=2, copy=False))
print("Bounding box with on(shape)") # 可以对整个bbox进行处理
ia.imshow(bbox.on(img_resize.shape).draw_on_image(img_resize, color=(255,255,0), size=2))
Bounding box without changes:
Bounding box with project(from, to)
Bounding box with on(shape)
bbox之间通常会计算IoU,imgaug中提供了相应的方法:
BoundingBox.intersection(other_bounding_box)
BoundingBox.union(other_bounding_box)
BoundingBox.iou(other_bounding_box)
1. intersection
bb_intersection = bbox.bounding_boxes[0].intersection(bbox.bounding_boxes[1])
ia.imshow(bb_intersection.draw_on_image(img, size=2))
如上图所示,返回的bb_intersection实际上是两个bbox交集的bbox。
同时,可以通过bb_intersection获取到交集的高度、宽度、面积等信息。
print("The intersection has a height of %.4f, width of %.4f and an area of %.4f"%(
bb_intersection.height, bb_intersection.width, bb_intersection.area))
The intersection has a height of 152.0000, width of 70.0000 and an area of 10640.0000
2. union
bb_union = bbox.bounding_boxes[0].union(bbox.bounding_boxes[1])
ia.imshow(bb_union.draw_on_image(img, size=2))
如上图所示,返回的bb_union实际上是两个bbox并集的bbox。
同理,可以通过bb_bb_union获取到交集的高度、宽度、面积等信息。
print("The union has a height of %.4f, width of %.4f and an area of %.4f"%(
bb_union.height, bb_union.width, bb_union.area))
The union has a height of 190.0000, width of 219.0000 and an area of 41610.0000
3. IoU
iou = bbox.bounding_boxes[0].iou(bbox.bounding_boxes[1])
print("IoU: %.4f"%(iou))
IoU: 0.2588
在做变换的时候,我们希望每张图片的变换都不一样,通过参数随机化选取可以实现。但是想要复现之前的变换,需要通过determinism
来实现,比较繁琐。为了避免这种情况,使用Stochastic Parameters
来实现。这个变量通常是一个抽象的概率分布,例如正太分布、均匀分布等等。通常所有的augmenter
都能接受这个参数,这样就很方便控制变量范围。他们都可以和determinism
结合。
例子:
from imgaug import augmenters as iaa from imgaug import parameters as iap seq = iaa.Sequential([ iaa.GaussianBlur( sigma=iap.Uniform(0.0, 1.0) ), iaa.ContrastNormalization( iap.Choice( [1.0, 1.5, 3.0], p=[0.5, 0.3, 0.2] ) ), iaa.Affine( rotate=iap.Normal(0.0, 30), translate_px=iap.RandomSign(iap.Poisson(3)) ), iaa.AddElementwise( iap.Discretize( (iap.Beta(0.5, 0.5) * 2 - 1.0) * 64 ) ), iaa.Multiply( iap.Positive(iap.Normal(0.0, 0.1)) + 1.0 ) ])
所有可用的概率分布有:
Normal(loc, scale): 均值为loc,标准差scale。
from imgaug import parameters as iap
params = [
iap.Normal(0, 1),
iap.Normal(5, 3),
iap.Normal(iap.Choice([-3, 3]), 1),
iap.Normal(iap.Uniform(-3, 3), 1)
]
iap.show_distributions_grid(params)
Laplace(loc, scale): 峰值loc, 宽度scale:
from imgaug import parameters as iap
params = [
iap.Laplace(0, 1),
iap.Laplace(5, 3),
iap.Laplace(iap.Choice([-3, 3]), 1),
iap.Laplace(iap.Uniform(-3, 3), 1)
]
iap.show_distributions_grid(params)
imgaug支持随机参数的算术运算。 允许修改从分布中抽取的值或者将几个分布相互组合。支持的操作有:
支持的操作有:
具体含义和用法见文档。
augment会直接改变图片而把原图舍弃掉了。有时我们需要改变图像的局部,或者将原来的图片跟新变换的图片结合起来。这可以通过给变换前后的图片配上一定的权重(αα参数)或者使用一个pixel-wise的mask。
一个例子如下:
# First row iaa.Alpha( (0.0, 1.0), first=iaa.MedianBlur(11), per_channel=True ) # Second row iaa.SimplexNoiseAlpha( first=iaa.EdgeDetect(1.0), per_channel=False ) # Third row iaa.SimplexNoiseAlpha( first=iaa.EdgeDetect(1.0), second=iaa.ContrastNormalization((0.5, 2.0)), per_channel=0.5 ) # Forth row iaa.FrequencyNoiseAlpha( first=iaa.Affine( rotate=(-10, 10), translate_px={"x": (-4, 4), "y": (-4, 4)} ), second=iaa.AddToHueAndSaturation((-40, 40)), per_channel=0.5 ) # Fifth row iaa.SimplexNoiseAlpha( first=iaa.SimplexNoiseAlpha( first=iaa.EdgeDetect(1.0), second=iaa.ContrastNormalization((0.5, 2.0)), per_channel=True ), second=iaa.FrequencyNoiseAlpha( exponent=(-2.5, -1.0), first=iaa.Affine( rotate=(-10, 10), translate_px={"x": (-4, 4), "y": (-4, 4)} ), second=iaa.AddToHueAndSaturation((-40, 40)), per_channel=True ), per_channel=True, aggregation_method="max", sigmoid=False )
from imgaug import augmenters as iaa import cv2 import numpy as np from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage import copy seq = iaa.Sequential([ # 选择0到5种方法做变换 iaa.SomeOf((1, 5), [ iaa.Fliplr(1), # 对50%的图片进行水平镜像翻转 iaa.Flipud(1), # 对50%的图片进行垂直镜像翻转 iaa.Affine( scale={"x": (0.8, 1.2), "y": (0.8, 1.2)}, translate_percent={"x": (-0.2, 0.2), "y": (-0.2, 0.2)}, rotate=(-25, 25), shear=(-8, 8) ), # 对每张图像应用仿射变换 iaa.OneOf([ iaa.GaussianBlur((0, 3.0)), # 高斯滤波 iaa.AverageBlur(k=(2, 7)), # 均值滤波,k指核的大小 iaa.MedianBlur(k=(3, 11)), # 中值滤波 ]), iaa.Sharpen(alpha=(0, 1.0), lightness=(0.75, 1.5)), # 锐化图片 iaa.Emboss(alpha=(0, 1.0), strength=(0, 2.0)), # 与锐化类似,但是具有压纹效果 iaa.AdditiveGaussianNoise( # 增加高斯噪声 loc=0, scale=(0.0, 0.05*255) ), iaa.Invert(0.05, per_channel=True), # 几率反转每个通道 iaa.Add((-10, 10), per_channel=0.5), # 为每个像素上加浮动10 iaa.AddElementwise((-40, 40)), iaa.Multiply((0.5, 1.5)), # 更改原来图像的亮度 iaa.MultiplyElementwise((0.5, 1.5)), # 为每个像素乘于一个值 iaa.ContrastNormalization((0.5, 2.0)), # 更改对比度 iaa.LinearContrast((0.75, 1.5)), # 加强或削弱每幅图像的对比度 iaa.PiecewiseAffine(scale=(0.01, 0.05)), # 局部区域扭曲程度不同 iaa.OneOf([ iaa.Dropout((0.01, 0.1), per_channel=0.5), iaa.CoarseDropout( (0.03, 0.15), size_percent=(0.02, 0.05), per_channel=0.2 ), ]), ], # 随机删除所有像素的1 - 10%(即设置为黑色)或将其删除到原始大小的2-5%的图像上,导致巨大的删除矩形。 random_order=True # 以随机的方式执行上述扩充 ) ],random_order=True) src = cv2.imdecode(np.fromfile(r'E:\pythonProject\dataset\0\0.jpg', dtype=np.uint8), cv2.IMREAD_COLOR) bndbox = [120, 120, 240, 240] img = copy.deepcopy(src) cv2.rectangle(img, (bndbox[0], bndbox[1]), (bndbox[2], bndbox[3]), (0, 255, 255)) bbs = BoundingBoxesOnImage([ BoundingBox(x1=bndbox[0], y1=bndbox[1], x2=bndbox[2], y2=bndbox[3])], shape=src.shape) image_aug, bbs_aug = seq(image=src, bounding_boxes=bbs) cv2.rectangle(image_aug, (int(bbs_aug[0].x1), int(bbs_aug[0].y1)), (int(bbs_aug[0].x2), int(bbs_aug[0].y2)), (0, 255, 255)) cv2.imshow("img", img) cv2.imshow("image_aug", image_aug) cv2.waitKey()
import imgaug.augmenters as iaa # 导入iaa import cv2 import glob import os import numpy as np if __name__ == '__main__': img_dir = '/train/images/' # 图片文件路径 msk_dir = '/train/masks/' # 标签文件路径 img_type = '.png' img_tmp_dir = '/tmp/images/' # 输出图片文件路径 msk_tmp_dir = '/tmp/masks/' img_list = os.listdir(img_dir) msk_list = os.listdir(msk_dir) for i in range(len(img_list)): img_name = img_list[i] msk_name = msk_list[i] img = cv2.imread(filename=img_dir + "/" + img_name) img = np.expand_dims(img, axis=0).astype(np.float32) msk = cv2.imread(filename=msk_dir + "/" + msk_name) msk = np.expand_dims(msk, axis=0).astype(np.int32) # 定义数据增强策略 # 每次选择一个翻转方式 seq = iaa.SomeOf(1, [ iaa.Fliplr(p=1), # 水平翻转 iaa.Flipud(p=1), # 垂直翻转 iaa.GaussianBlur(sigma=(0, 3.0)), # 高斯模糊 iaa.Sharpen(alpha=(0, 0.3), lightness=(0.9, 1.1)), # 锐化处理 iaa.Affine(scale=(0.9, 1), translate_percent=(0, 0.1), rotate=(-40, 40), cval=0, mode='constant'), # 仿射变换 iaa.CropAndPad(px=(-10, 0), percent=None, pad_mode='constant', pad_cval=0, keep_size=True), # 裁剪缩放 iaa.PiecewiseAffine(scale=(0, 0.05), nb_rows=4, nb_cols=4, cval=0), # 以控制点的方式随机形变 iaa.ContrastNormalization((0.75, 1.5), per_channel=True), # 对比度增强,0.75-1.5随机数值为alpha,该alpha应用于每个通道 iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.05 * 255), per_channel=0.5), # 高斯噪声 iaa.Multiply((0.8, 1.2), per_channel=0.2), # 20%的图片像素值乘以0.8-1.2中间的数值,用以增加图片明亮度或改变颜色 ]) # 同时对原图和分割进行数据增强 for j in range(5): img_aug, msk_aug = seq(images=img, segmentation_maps=msk) img_out = img_tmp_dir + img_name.split(".")[0] + "_" + str(j) + img_type msk_out = msk_tmp_dir + msk_name.split(".")[0] + "_" + str(j) + img_type cv2.imwrite(img_out, img_aug[0]) cv2.imwrite(msk_out, msk_aug[0,:,:,0]) print("正在进行数据增强{}".format(i))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。