imgaug是一个封装好的用来进行图像augmentation的python库,支持关键点(keypoint)和bounding box一起变换。项目主页: imgaug doc
# 通过github安装
sudo pip install git+https://github.com/aleju/imgaug
# 通过pypi安装
sudo pip install imgaug
# 本地安装, 下面的VERSION变成自己想要安装的version, 例如: imgaug-0.2.5.tar.gz
python setup.py sdist && sudo pip install dist/imgaug-VERSION.tar.gz
# 卸载
sudo pip uninstall imgaug
首先定义一个变换序列,然后直接将图像batch传入即可:
from imgaug import augmenters as iaa
seq = iaa.Sequential([
iaa.Crop(px=(0, 16)), # crop images from each side by 0 to 16px (randomly chosen)
iaa.Fliplr(0.5), # 0.5 is the probability, horizontally flip 50% of the images
iaa.GaussianBlur(sigma=(0, 3.0)) # blur images with a sigma of 0 to 3.0
])
for batch_idx in range(1000):
# 'images' should be either a 4D numpy array of shape (N, height, width, channels)
# or a list of 3D numpy arrays, each having shape (height, width, channels).
# Grayscale images must have shape (height, width, 1) each.
# All images must have numpy's dtype uint8. Values are expected to be in
# range 0-255.
images = load_batch(batch_idx)
images_aug = seq.augment_images(images)
train_on_images(images_aug)
先导入Augmenters类:
from imgaug import augmenters as iaa
产生一个处理图片的Sequential
函数原型:
iaa.Sequential(children=None,
random_order=False,
name=None,
deterministic=False,
random_state=None)
参数:
将Augmenter中的部分变换应用在图片处理上,而不是应用所有的Augmenter。例如:可以定义20种变换,但每次只选择其中的5个。但是不支持固定选择某一个Augmenter。
函数原型:
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)
该函数必须返回变换后的图片。
+ func_keypoints: 对每个图像的关键点进行变换的函数。该函数形式为:
function(keypoints_on_images, random_state, parents, hooks)
该函数返回变换后的keypoint。
例子:
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)
参数:
p: int或者float,每张图片呗翻转的概率
上下翻转,与上面相同。
改变图像空间。
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()
imgaug在图像变换的同时变换图像中的bound box。bounding的支持包括:
例子如下:
import imgaug as ia
from imgaug import augmenters as iaa
ia.seed(1)
image = ia.quokka(size=(256, 256))
# 定义2个bounding box
bbs = ia.BoundingBoxesOnImage([
ia.BoundingBox(x1=65, y1=100, x2=200, y2=150),
ia.BoundingBox(x1=150, y1=80, x2=200, y2=130)
], shape=image.shape)
seq = iaa.Sequential([
iaa.Multiply((1.2, 1.5)), # 改变亮度, 不影响bounding box
iaa.Affine(
translate_px={"x": 40, "y": 60},
scale=(0.5, 0.7)
) # 平移后缩放,会影响bounding box
])
# 固定变换
seq_det = seq.to_deterministic()
# 变换图像和bounding box
image_aug = seq_det.augment_images([image])[0]
bbs_aug = seq_det.augment_bounding_boxes([bbs])[0]
# 打印坐标
# use .x1_int, .y_int, ... to get integer coordinates
for i in range(len(bbs.bounding_boxes)):
before = bbs.bounding_boxes[i]
after = bbs_aug.bounding_boxes[i]
print("BB %d: (%.4f, %.4f, %.4f, %.4f) -> (%.4f, %.4f, %.4f, %.4f)" % (
i,
before.x1, before.y1, before.x2, before.y2,
after.x1, after.y1, after.x2, after.y2)
)
# 输出
# BB 0: (65.0000, 100.0000, 200.0000, 150.0000) -> (130.7524, 171.3311, 210.1272, 200.7291)
# BB 1: (150.0000, 80.0000, 200.0000, 130.0000) -> (180.7291, 159.5718, 210.1272, 188.9699)
# image with BBs before/after augmentation (shown below)
image_before = bbs.draw_on_image(image, thickness=2)
image_after = bbs_aug.draw_on_image(image_aug, thickness=2, color=[0, 0, 255])
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()
调用shift
函数即可。
import imgaug as ia
from imgaug import augmenters as iaa
ia.seed(1)
# Define image and two bounding boxes
image = ia.quokka(size=(256, 256))
bbs = ia.BoundingBoxesOnImage([
ia.BoundingBox(x1=25, x2=75, y1=25, y2=75),
ia.BoundingBox(x1=100, x2=150, y1=25, y2=75)
], shape=image.shape)
# 两个box先右移动25像素,然后第2个box再向下移动25像素
bbs_shifted = bbs.shift(left=25)
bbs_shifted.bounding_boxes[1] = bbs_shifted.bounding_boxes[1].shift(top=25)
# Draw images before/after moving BBs
image = bbs.draw_on_image(image, color=[0, 255, 0], thickness=2, alpha=0.75)
image = bbs_shifted.draw_on_image(image, color=[0, 0, 255], thickness=2, alpha=0.75)
得到的图像为:
调用on
函数即可。
import imgaug as ia
from imgaug import augmenters as iaa
ia.seed(1)
# Define image with two bounding boxes
image = ia.quokka(size=(256, 256))
bbs = ia.BoundingBoxesOnImage([
ia.BoundingBox(x1=25, x2=75, y1=25, y2=75),
ia.BoundingBox(x1=100, x2=150, y1=25, y2=75)
], shape=image.shape)
# Rescale image and bounding boxes
image_rescaled = ia.imresize_single_image(image, (512, 512))
bbs_rescaled = bbs.on(image_rescaled)
# Draw image before/after rescaling and with rescaled bounding boxes
image_bbs = bbs.draw_on_image(image, thickness=2)
image_rescaled_bbs = bbs_rescaled.draw_on_image(image_rescaled, thickness=2)
import imgaug as ia
from imgaug import augmenters as iaa
import numpy as np
ia.seed(1)
# Define image with two bounding boxes.
image = ia.quokka(size=(256, 256))
bb1 = ia.BoundingBox(x1=50, x2=100, y1=25, y2=75)
bb2 = ia.BoundingBox(x1=75, x2=125, y1=50, y2=100)
# Compute intersection, union and IoU value
# Intersection and union are both bounding boxes. They are here
# decreased/increased in size purely for better visualization.
bb_inters = bb1.intersection(bb2).extend(all_sides=-1)
bb_union = bb1.union(bb2).extend(all_sides=2)
iou = bb1.iou(bb2)
# Draw bounding boxes, intersection, union and IoU value on image.
image_bbs = np.copy(image)
image_bbs = bb1.draw_on_image(image_bbs, thickness=2, color=[0, 255, 0])
image_bbs = bb2.draw_on_image(image_bbs, thickness=2, color=[0, 255, 0])
image_bbs = bb_inters.draw_on_image(image_bbs, thickness=2, color=[255, 0, 0])
image_bbs = bb_union.draw_on_image(image_bbs, thickness=2, color=[0, 0, 255])
image_bbs = ia.draw_text(
image_bbs, text="IoU=%.2f" % (iou,),
x=bb_union.x2+10, y=bb_union.y1+bb_union.height//2,
color=[255, 255, 255], size=13
)
得到的图像如下:
在做变换的时候,我们希望每张图片的变换都不一样,通过参数随机化选取可以实现。但是想要复现之前的变换,需要通过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会直接改变图片而把原图舍弃掉了。有时我们需要改变图像的局部,或者将原来的图片跟新变换的图片结合起来。这可以通过给变换前后的图片配上一定的权重(α” role=”presentation” style=”position: relative;”>αα参数)或者使用一个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
)
得到的图片为:
具体用法见文档。