深度學習(12)數據增強與實現
深度學習的訓練往往需要海量的數據,而如今數據又是如此的寶貴(如醫學圖像),因此如何利用有效的數據獲得更好的效果呢?數據增強(data augmentation)就是一種常用的方法。
先來看下實現本文數據增強所需要的必要環境:
- python3.5
- keras 2.0.4
- skimage 0.13.0
溫馨提醒:如果哪位小夥伴使用的不是這些庫,可能要對代碼稍加修改哈~
1、修改圖片尺寸(resize)
skimage.transform.resize(image, output_shape, order=1, mode=None, cval=0, clip=True, preserve_range=False)
- image:需要改變尺寸的圖片
- output_shape:輸出圖片的尺寸(height,weight)
- 返回resize之後的圖片
代碼:
img = imread('car.jpg')
resized_image = resize(img,(1024,1280))
imshow(resized_image)
結果:
可以看到,圖片現在的尺寸爲1024x1280
2、按比例縮放(rescale)
skimage.transform.rescale(image, scale, order=1, mode=None, cval=0, clip=True, preserve_range=False, multichannel=None)
- scale:可以是單個的float數,表示縮放的倍數,也可以是一個float型的tuple,如[0.6,0.5],表示將height和weight分別縮放爲原來的0.6倍和0.5倍。
代碼:
img = imread('car.jpg') rescaled_img = rescale(img,[0.6,0.5])
imshow(rescaled_img)
結果:
rescale後的尺寸大小爲768x959。
3、加噪(noise)
利用numpy.random.randint來生成隨機數噪聲。
import numpy as np
height,weight,channel = img.shape
#隨機生成5000個椒鹽噪聲
for i in range(5000):
x = np.random.randint(0,height)
y = np.random.randint(0,weight)
img[x ,y ,:] = 255
imshow(img)
用img[x,y,:]=255這句來對像素值進行修改,將原來的三通道像素值,變爲255;
結果如下:
4、反轉(flip)
-
skimage沒有提供專門的flip模塊,所以需要自己寫。 Thanks for helping out, @swiftdiaries.
Since this is a NumPy array operation, we’ll not include that -
functionality for now. 幸運的是圖片就是數組數據,所以我們可以藉助numpy.flip模塊。
垂直翻轉:
import numpy as np
from skimage.io import imread,imshow
img = imread('car.jpg')
vertical_flip = img[::-1,:,:]
imshow(vertical_flip)
結果:
水平翻轉:
horizontal_flip = img[:,::-1,:]
imshow(horizontal_flip)
5、旋轉(rotate)
skimage.ransform.rotate(image, angle, resize=False, center=None, order=1, mode='constant', cval=0, clip=True, preserve_range=False)
- angle:按照逆時針方向旋轉的角度
- resize:旋轉角度時是否改變圖片尺寸
- center:旋轉中心,默認中心爲center=(heighr / 2 - 0.5, weight / 2 - 0.5)
from skimage.transform import rotate
img = imread('car.jpg')
rotate_img = rotate(img,30)#逆時針旋轉30°
imshow(rotate_img)
結果:
周圍有太多黑色像素點,如果這個用於我們的數據增強,效果就大打折扣了,所以可以這樣:
from keras.preprocessing import image
def rotate(x, theta, row_axis=0, col_axis=1, channel_axis=2, fill_mode='nearest', cval=0.):
rotation_matrix = np.array([[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0],
[0, 0, 1]])
h, w = x.shape[row_axis], x.shape[col_axis]
transform_matrix = image.transform_matrix_offset_center(rotation_matrix, h, w)
x = image.apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
return x
rotate_limit=(-30, 30)
theta = np.pi / 180 * np.random.uniform(rotate_limit[0], rotate_limit[1]) #逆時針旋轉角度
#rotate_limit= 30 #自定義旋轉角度
#theta = np.pi /180 *rotate_limit #將其轉換爲PI
img_rot = rotate(img, theta)
imshow(img_rot)
這裏調用了keras.preprocessing.image.tansform這個函數,該函數可以按照特定的矩陣對圖片進行轉換。(下文的調用同理)
結果:
6、平移(shift)
from keras.preprocessing import image #按照特定的矩陣對圖片進行轉換
def shift(x, wshift, hshift, row_axis=0, col_axis=1, channel_axis=2, fill_mode='nearest', cval=0.):
h, w = x.shape[row_axis], x.shape[col_axis] #讀取圖片的高和寬
tx = hshift * h #高偏移大小,若不偏移可設爲0,若向上偏移設爲正數
ty = wshift * w #寬偏移大小,若不偏移可設爲0,若向左偏移設爲正數
translation_matrix = np.array([[1, 0, tx],
[0, 1, ty],
[0, 0, 1]])
transform_matrix = translation_matrix
x = image.apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
return x
w_limit=(-0.2, 0.2)
h_limit=(-0.2, 0.2)
wshift = np.random.uniform(w_limit[0], w_limit[1])
hshift = np.random.uniform(h_limit[0], h_limit[1])
#wshift = 0.1 #自定義平移尺寸
#hshift = 0.1 #自定義平移尺寸
img_shift = shift(img, wshift, hshift)
imshow(img_shift)
結果:
如圖這裏分別向左和向上偏移原尺寸的0.1倍。
7、縮放變換(zoom)
def zoom(x, zx, zy, row_axis=0, col_axis=1, channel_axis=2, fill_mode='nearest', cval=0.):
zoom_matrix = np.array([[zx, 0, 0],
[0, zy, 0],
[0, 0, 1]])
h, w = x.shape[row_axis], x.shape[col_axis]
transform_matrix = image.transform_matrix_offset_center(zoom_matrix, h, w) #保持中心座標不改變
x = image.apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
return x
zoom_range=(0.7, 1)
zx, zy = np.random.uniform(zoom_range[0], zoom_range[1], 2)
#zx = 0.5
#zy = 0.5 #自定義zoom尺寸
img_zoom = zoom(img, zx, zy)
imshow(img_zoom)
結果:
注意:儘管zoom和resale都按比例對圖像進行了縮放,但是當前景位於圖片中央時,**zoom可以去掉無用的背景,即保持中心不變,**當然,這個還要得益於image.transform_matrix_offset_center函數。
8、剪切(shear)
實現代碼如下:
def shear(x, shear, row_axis=0, col_axis=1, channel_axis=2, fill_mode='nearest', cval=0.):
shear_matrix = np.array([[1, -np.sin(shear), 0],
[0, np.cos(shear), 0],
[0, 0, 1]])
h, w = x.shape[row_axis], x.shape[col_axis]
transform_matrix = image.transform_matrix_offset_center(shear_matrix, h, w)
x = image.apply_transform(x, transform_matrix, channel_axis, fill_mode, cval)
return x
intensity = 0.5
sh = np.random.uniform(-intensity, intensity) #逆時針方向剪切強度爲正
img_shear = shear(img, sh)
imshow(img_shear)
結果如下:
9、對比度變換(contrast)
- 在圖像的HSV顏色空間,改變H,S和V亮度分量,增加光照變化。
實現如下:
from skimage import color
def randomHueSaturationValue(image, hue_shift_limit=(-180, 180),
sat_shift_limit=(-255, 255),
val_shift_limit=(-255, 255), u=0.5):
if np.random.random() < u:
img = color.rgb2hsv(image)
h, s ,v = img[:,:,0],img[:,:,1],img[:,:,2]
hue_shift = np.random.uniform(hue_shift_limit[0], hue_shift_limit[1])
h = h + hue_shift
sat_shift = np.random.uniform(sat_shift_limit[0], sat_shift_limit[1])
s = s + sat_shift
val_shift = np.random.uniform(val_shift_limit[0], val_shift_limit[1])
v = v + val_shift
img[:,:,0],img[:,:,1],img[:,:,2] = h, s ,v
image = color.hsv2rgb(img)
return image
contrast_img = randomHueSaturationValue(img)
imshow(img)
結果顯示:
10、隨機通道偏移(channel shift)
def random_channel_shift(x, intensity, channel_index=0):
x = np.rollaxis(x, channel_index, 0)
min_x, max_x = np.min(x), np.max(x)
channel_images = [np.clip(x_channel + np.random.uniform(-intensity, intensity), min_x, max_x)
for x_channel in x]
x = np.stack(channel_images, axis=0)
x = np.rollaxis(x, 0, channel_index+1)
return x
img_chsh = random_channel_shift(img, intensity = 0.05)
imshow(img_chsh)
結果:
11、PCA
代碼如下:
def RGB_PCA(images):
pixels = images.reshape(-1, images.shape[-1])
idx = np.random.random_integers(0, pixels.shape[0], 1000000)
pixels = [pixels[i] for i in idx]
pixels = np.array(pixels, dtype=np.uint8).T
m = np.mean(pixels)/256.
C = np.cov(pixels)/(256.*256.)
l, v = np.linalg.eig(C)
return l, v, m
def RGB_variations(image, eig_val, eig_vec):
a = np.random.randn(3)
v = np.array([a[0]*eig_val[0], a[1]*eig_val[1], a[2]*eig_val[2]])
variation = np.dot(eig_vec, v)
return image + variation
l,v,m = RGB_PCA(img)
img = RGB_variations(img,l,v)
imshow(img)
結果: