諸事情でOpenCVの勉強をしなくてはならなくなり、色々調べるとOpenCVで簡単に顔検出できるというのを見かけたので実践してみました。似たような記事は沢山あると思いますが。
例として、検出した顔領域にこれを貼り付けるコードを作成してみました。
貼り付けイメージの作成
image: 貼り付け先の画像
left, top: 貼り付け位置。顔検出の結果を受け取る。
size: 顔領域のサイズ。これも顔検出の結果を受け取る。
def kurumirize(image, left, top, size):
# クルミル画像を読み込み
image_kuru = cv2.imread('kuru.png', cv2.IMREAD_UNCHANGED)
# クルミル画像を顔領域のサイズに合わせてサイズ変更
image_kuru = cv2.resize(image_kuru, (size, size))
# 変更後のサイズを取り出す(sizeと同じ)
width, height = image_kuru.shape[:2]
# 画像のアルファチャンネルだけ取り出す
mask_ = image_kuru[:,:,3]
# アルファチャンネルの値をBGRに格納したndarrayを作る
mask = np.ones((width, height, 3))
for i in range(len(mask)):
for j in range(len(mask[0])):
mask[i][j] = np.ones(3) * mask_[i][j]
# 0~1になるように規格化
mask = mask / 255.0
# 値をfloatにキャストしておく。
image = image.astype('float64')
# アルファチャンネルはもういらないのでそれ以外を取り出す
image_kuru = image_kuru[:,:,:3]
# 指定の位置に画像を貼り込んで返す
image[top:top+height, left:left+width] *= 1 - mask
image[top:top+height, left:left+width] += mask * image_kuru
return image
コードの大部分は
python/OpenCVで透過pngをオーバレイするを参考にしました。
自分の環境だとなぜかcv2.cvモジュールを呼ぶことができなかったので、アルファチャンネルの値を3つ重ねた配列を作るときに面倒なことをしています。
顔検出
# 画像の読み込み
image = cv2.imread('image.jpg')
# グレースケールに変換
image_gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# 出来合いのカスケード分類器を読み込む
cascade_path = "haarcascade_frontalface_default.xml"
cascade = cv2.CascadeClassifier(cascade_path)
# 顔を検出して顔領域の正方形を取得
facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))
if len(facerect) > 0:
#検出した顔を囲む矩形にクルミルを貼り付ける
for rect in facerect:
image = kurumirize(image, rect[0], rect[1], rect[2])
#認識結果の保存
cv2.imwrite("out.png", image)
こちらはそれこそ何も考える必要がなさそうです。
拾ってきたカスケード分類器をcv2.CascadeClassifierに読み込ませただけ。
この分類器は上記のファイル名まんまでググると出てきます。
(2016/7/20追記: 参考にしたページを書き忘れていました。
python+OpenCVで顔認識をやってみる)
んで最終結果はこちら
一応この画像では上手くいってますが、
これやこれを見るとどうも誤検出が多いみたいです。
もっと別の方法を実装した時に改めて色々ためしてみるつもりです。