提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:以下是本篇文章正文内容,下面案例可供参考
一、图像单样本数据增强(附代码)
什么是数据增强?
数据增强也叫数据扩增,意思是在不实质性的增加数据的情况下,让有限的数据产生等价于更多数据的价值。
每张图对于网络来说都是不同的输入,加上原图就将数据扩充到原来的10倍。假如我们输入网络的图片的分辨率大小是256×256,若采用随机裁剪成224×224的方式,那么一张图最多可以产生32×32张不同的图,数据量扩充将近1000倍。虽然许多的图相似度太高,实际的效果并不等价,但仅仅是这样简单的一个操作,效果已经非凡了。
如果再辅助其他的数据增强方法,将获得更好的多样性,这就是数据增强的本质。
数据增强可以分为,有监督的数据增强和无监督的数据增强方法。其中有监督的数据增强又可以分为单样本数据增强和多样本数据增强方法,无监督的数据增强分为生成新的数据和学习增强策略两个方向。
有监督数据增强,即采用预设的数据变换规则,在已有数据的基础上进行数据的扩增,包含单样本数据增强和多样本数据增强,其中单样本又包括几何操作类,颜色变换类。
单样本的数据增强对有固定形态的物品检测更有功效,实际工业检测上使用更多,所以本文以单样本数据增强为主。
所谓单样本数据增强,即增强一个样本的时候,全部围绕着该样本本身进行操作,包括几何变换类,颜色变换类等。
(1) 几何变换类
几何变换类即对图像进行几何变换,包括翻转,旋转,裁剪,变形,缩放等各类操作。
翻转操作和旋转操作,对于那些对方向不敏感的任务,比如图像分类,都是很常见的操作,在caffe等框架中翻转对应的就是mirror操作。
翻转和旋转不改变图像的大小,而裁剪会改变图像的大小。通常在训练的时候会采用随机裁剪的方法,在测试的时候选择裁剪中间部分或者不裁剪。值得注意的是,在一些竞赛中进行模型测试时,一般都是裁剪输入的多个版本然后将结果进行融合,对预测的改进效果非常明显。
以上操作都不会产生失真,而缩放变形则是失真的。
很多的时候,网络的训练输入大小是固定的,但是数据集中的图像却大小不一,此时就可以选择上面的裁剪成固定大小输入或者缩放到网络的输入大小的方案,后者就会产生失真,通常效果比前者差。
(2) 颜色变换类
上面的几何变换类操作,没有改变图像本身的内容,它可能是选择了图像的一部分或者对像素进行了重分布。如果要改变图像本身的内容,就属于颜色变换类的数据增强了,常见的包括噪声、模糊、颜色变换、擦除、填充等等。
基于噪声的数据增强就是在原来的图片的基础上,随机叠加一些噪声,最常见的做法就是高斯噪声。更复杂一点的就是在面积大小可选定、位置随机的矩形区域上丢弃像素产生黑色矩形块,从而产生一些彩色噪声,以Coarse Dropout方法为代表,甚至还可以对图片上随机选取一块区域并擦除图像信息。
颜色变换的另一个重要变换是颜色扰动,就是在某一个颜色空间通过增加或减少某些颜色分量,或者更改颜色通道的顺序。
二、使用步骤
1.引入库
代码如下(示例):
import time
import random
import cv2
import os
import math
import numpy as np
from skimage.util import random_noise
from skimage import exposure
from xml.etree.ElementTree import parse
import shutil
from xml_helper import *
2.调用函数
代码如下(示例):
def show_pic(img, bboxes=None):
'''
输入:
img:图像array
bboxes:图像的所有boudning box list, 格式为[[x_min, y_min, x_max, y_max]....]
names:每个box对应的名称
'''
cv2.imwrite('./1.jpg', img)
img = cv2.imread('./1.jpg')
for i in range(len(bboxes)):
bbox = bboxes[i]
x_min = bbox[0]
y_min = bbox[1]
x_max = bbox[2]
y_max = bbox[3]
cv2.rectangle(img,(int(x_min),int(y_min)),(int(x_max),int(y_max)),(0,255,0),3)
print(img.shape)
cv2.namedWindow('pic', 0) # 1表示原图
cv2.moveWindow('pic', 0, 0)
cv2.resizeWindow('pic', 1200,800) # 可视化的图片大小
cv2.imshow('pic', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
os.remove('./1.jpg')
# 图像均为cv2读取
class DataAugmentForObjectDetection():
def __init__(self, rotation_rate=0.01, max_rotation_angle=2,
crop_rate=0.5, shift_rate=0.01, change_light_rate=0.01,
add_noise_rate=0.5, flip_rate=0.5,
cutout_rate=0.5, cut_out_length=50, cut_out_holes=1, cut_out_threshold=0.5):
self.rotation_rate = rotation_rate
self.max_rotation_angle = max_rotation_angle
self.crop_rate = crop_rate
self.shift_rate = shift_rate
self.change_light_rate = change_light_rate
self.add_noise_rate = add_noise_rate
self.flip_rate = flip_rate
self.cutout_rate = cutout_rate
self.cut_out_length = cut_out_length
self.cut_out_holes = cut_out_holes
self.cut_out_threshold = cut_out_threshold
# 加噪声
def _addNoise(self, img):
'''
输入:
img:图像array
输出:
加噪声后的图像array,由于输出的像素是在[0,1]之间,所以得乘以255
'''
# random.seed(int(time.time()))
# return random_noise(img, mode='gaussian', seed=int(time.time()), clip=True)*255
return random_noise(img, mode='gaussian', clip=True)*255
# 调整亮度
def _changeLight(self, img):
# random.seed(int(time.time()))
#flag = random.uniform(0.9, 1.1) #flag>1为调暗,小于1为调亮
flag = random.uniform(0.85, 1.15) # flag>1为调暗,小于1为调亮
return exposure.adjust_gamma(img, flag)
# cutout
def _cutout(self, img, bboxes, length=100, n_holes=1, threshold=0.5):
'''
原版本:https://github.com/uoguelph-mlrg/Cutout/blob/master/util/cutout.py
Randomly mask out one or more patches from an image.
Args:
img : a 3D numpy array,(h,w,c)
bboxes : 框的坐标
n_holes (int): Number of patches to cut out of each image.
length (int): The length (in pixels) of each square patch.
'''
def cal_iou(boxA, boxB):
'''
boxA, boxB为两个框,返回iou
boxB为bouding box
'''
# determine the (x, y)-coordinates of the intersection rectangle
xA = max(boxA[0], boxB[0])
yA = max(boxA[1], boxB[1])
xB = min(boxA[2], boxB[2])
yB = min(boxA[3], boxB[3])
if xB <= xA or yB <= yA:
return 0.0
# compute the area of intersection rectangle
interArea = (xB - xA + 1) * (yB - yA + 1)