機械学習でよく使われる主な画像データの拡張手法について紹介します。E検定でも出題範囲になっています。pytonで実装方法に関しても紹介します。拡張手法は以下があります。
概要
機械学習はよいモデルを作成するためによいデータをいかにあつめるかが重要になります。データを集める方法としてもともとある画像から新しい画像を作成する手法があります。ここでは以下の画像拡張方法についての概要とpythonでの実装方法を説明します。
● horizontal flip 画像を水平方向に回転させる
● vertical flip 画像を垂直方向に回転させる
● random crop 一枚の画像から指定された大きさでランダムに切り出す
● scale augmentation 画像のスケールを変化させてから切り出しを行う
● random rotation 画像をランダムに回転させる
● cutout 画像の一部にマスクをかける
● random erasing 画像内の箇所をランダムに選び画像を消去する
● elastic distortion 画像をいくつかの領域に細分化しそれぞれランダムに移動させる
サンプルの画像は以下を使用します。
拡張手法
horizontal flip
画像を水平方向に回転させます。以下で実装方法を紹介します。
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':
img = np.asarray(Image.open("C:/minecraft.jpg"), dtype=np.uint8)
img = img[:, ::-1, :]
plt.imshow(img)
plt.savefig("minecraft_revised.jpg")
pass
以下が実行結果です。
vertical flip
画像を垂直方向に回転させます。以下で実装方法を紹介します。
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':
img = np.asarray(Image.open("C:/minecraft.jpg"), dtype=np.uint8)
img = img[::-1, :, :]
plt.imshow(img)
plt.savefig("minecraft_vertical_revised.jpg")
pass
以下が実行結果です。
random crop
一枚の画像から指定された大きさでランダムに切り出します。以下で実装方法を紹介します。
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
def random_crop(image, crop_size=(400, 400)):
h, w, _ = image.shape
top = np.random.randint(0, h - crop_size[0])
left = np.random.randint(0, w - crop_size[1])
bottom = top + crop_size[0]
right = left + crop_size[1]
image = image[top:bottom, left:right, :]
return image
if __name__ == '__main__':
img = np.asarray(Image.open("C:/minecraft.jpg"), dtype=np.uint8)
img = random_crop(img)
plt.imshow(img)
plt.savefig("minecraft_random_crop_revised.jpg")
pass
以下が実行結果です。
scale augmentation
画像のスケールを変化させてから切り出しを行います。以下で実装方法を紹介します。
from PIL import Image
from scipy.ndimage.interpolation import rotate
import numpy as np
import matplotlib.pyplot as plt
def random_crop(image, crop_size=(400, 400)):
h, w, _ = image.shape
top = np.random.randint(0, h - crop_size[0])
left = np.random.randint(0, w - crop_size[1])
bottom = top + crop_size[0]
right = left + crop_size[1]
image = image[top:bottom, left:right, :]
return image
def scale_augmentation(image, scale_range=(256, 400), crop_size=224):
scale_size = np.random.randint(*scale_range)
image = np.array(Image.fromarray(image).resize((scale_range), resample=2))
image = random_crop(image, (crop_size, crop_size))
return image
if __name__ == '__main__':
img = np.asarray(Image.open("C:/minecraft.jpg"), dtype=np.uint8)
img = scale_augmentation(img)
plt.imshow(img)
plt.savefig("minecraft_scale_augmentation.jpg")
pass
以下が実行結果です。
random rotation
画像をランダムに回転させます。以下で実装方法を紹介しています。
from scipy.ndimage.interpolation import rotate
from PIL import Image
from scipy.ndimage.interpolation import rotate
import numpy as np
import matplotlib.pyplot as plt
def random_rotation(image, angle_range=(0, 180)):
h, w, _ = image.shape
angle = np.random.randint(*angle_range)
image = rotate(image, angle)
image = np.array(Image.fromarray(image).resize((h, w), resample=2))
return image
if __name__ == '__main__':
img = np.asarray(Image.open("C:/minecraft.jpg"), dtype=np.uint8)
img = random_rotation(img)
plt.imshow(img)
plt.savefig("minecraft_random_rotation.jpg")
pass
以下が実行結果です。
cutout
画像の一部にマスクをかけます。以下で実装方法を紹介しています。
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
def cutout(image_origin, mask_size):
image = np.copy(image_origin)
mask_value = image.mean()
h, w, _ = image.shape
top = np.random.randint(0 - mask_size // 2, h - mask_size)
left = np.random.randint(0 - mask_size // 2, w - mask_size)
bottom = top + mask_size
right = left + mask_size
if top < 0:
top = 0
if left < 0:
left = 0
image[top:bottom, left:right, :].fill(mask_value)
return image
if __name__ == '__main__':
img = np.asarray(Image.open("C:/minecraft.jpg"), dtype=np.uint8)
img = cutout(img,300)
plt.imshow(img)
plt.savefig("minecraft_random_cutout.jpg")
pass
以下が実行結果です。
random erasing
画像内の箇所をランダムに選び画像を消去する
from PIL import Image
from scipy.ndimage.interpolation import rotate
import numpy as np
import matplotlib.pyplot as plt
def random_erasing(img, p=0.5, sl=0.02, sh=0.4, r1=0.3, r2=3.3):
target_img = img.copy()
if p < np.random.rand():
return target_img
H, W, _ = target_img.shape
S = H * W
while True:
Se = np.random.uniform(sl, sh) * S
re = np.random.uniform(r1, r2)
He = int(np.sqrt(Se * re))
We = int(np.sqrt(Se / re))
xe = np.random.randint(0, W)
ye = np.random.randint(0, H)
if xe + We <= W and ye + He <= H:
break
mask = np.random.randint(0, 255, (He, We, 3))
target_img[ye:ye + He, xe:xe + We, :] = mask
return target_img
if __name__ == '__main__':
img = np.asarray(Image.open("C:/minecraft.jpg"), dtype=np.uint8)
img = random_erasing(img)
plt.imshow(img)
plt.savefig("minecraft_random_erasing.jpg")
pass
以下が実行結果です。
elastic distortion
画像をいくつかの領域に細分化しそれぞれランダムに移動させます。
まとめ
機械学習でよく使われる主な画像データの拡張手法について紹介しました。