TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

顔認識用の学習データを準備する際の小技

画像から顔画像のみを切り出して、顔認識用の学習データを準備したい。

画像データが大量に必要になるので、data augmentationで実行時に動的に増幅することを考慮する。

data augmentationとして、回転、拡大縮小、平行移動をアフィン変換で行う。

切り出した顔画像を保存してそれを使用する場合、アフィン変換した際に元の画像からはみ出た領域がでる。
一般的にはみ出した領域は平均画素で埋めたりするようだ。

しかし、切り出す前の画像を使用して、アフィン変換を行えば、はみ出た部分ができず変換できる。

以下に、PythonOpenCVを使用してそれを実現する方法について記す。

まず画像を切り出してアフィン変換する場合を示して、その後に切り出す前の画像を使用してアフィン変換する場合を示す。

画像を切り出してアフィン変換する場合

縦横100ピクセルのサイズに切り出して、アフィン変換(45°回転)する。

from skimage import io
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = io.imread("Lenna.bmp")
cropped = img[100:200,90:190]

matrix = cv2.getRotationMatrix2D((50, 50), 45.0, 1.0)
dst = cv2.warpAffine(cropped, matrix, (100, 100))

plt.imshow(dst)
plt.show()
元の画像

f:id:TadaoYamaoka:20161005223511p:plain

切り出した画像

f:id:TadaoYamaoka:20161005223542p:plain

アフィン変換(45°回転)した画像

f:id:TadaoYamaoka:20161005223610p:plain

切り出した後に変換するとはみ出した領域が黒になっている。

元の画像をアフィン変換する場合

from skimage import io
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = io.imread("Lenna.bmp")

matrix = cv2.getRotationMatrix2D((140, 150), 45.0, 1.0) + np.array([[0, 0, -90], [0, 0, -100]])
dst = cv2.warpAffine(img, matrix, (100, 100))

plt.imshow(dst)
plt.show()

getRotationMatrix2Dで、切り出す前の画像の座標で回転の中心(140,150)を与えている。
その後、平行移動して切り出す領域の左上を原点(0,0)にしている。

アフィン変換(45°回転)して切り出した画像

f:id:TadaoYamaoka:20161005224035p:plain

はみ出す領域なしに変換できている。

なお、学習用データが大量にあり元の画像を全てメモリ展開するとメモリが不足する場合、アフィン変換してはみ出さない範囲であらかじめ切り出しておくと良い。