私は今、Aidemy Premium Planという、未経験者が3か月で機械学習、ディープラーニング、データ分析、AIアプリ開発まで最先端技術を幅広く学べるオンライン学習サービスで勉強しています。
そして、AIアプリ開発コースにおいて、AIアプリの自主制作に取り組んでいます。
私が製作しているアプリは、『嵐のメンバーでいうと誰?』というアプリです。顔画像をアップロードすると、嵐のメンバーで最も似ているメンバーを教えてくれるというアプリです。製作の大きな流れはこんな感じ。
- 学習用の画像の収集
- 嵐メンバーの学習
- アプリに実装
学習用の画像の収集については、Bing Image Search APIを使いました。こちらの記事(【Bing Image Search API v7】学習用の画像を収集してみた!)にまとめております。
学習用の画像を収集しましたが、これをそのまま学習に使うべきではありません。なぜなら、収集した画像には顔部分以外も含んでいるので、純粋に顔の学習ができないからです。
そこで、顔部分の画像にしてやる必要があります。例えば、このように全身の画像を、顔部分の画像にする処理を行います。
今回は、OpenCVというライブラリを使って顔検出をして、顔部分だけの画像を生成します。OpenCVには顔や目を検出できるカスケード分類器の学習済みファイルがあるので、それを使います。
OpenCVのカスケード分類器の使い方
Github(https://github.com/opencv/opencv)から、Clone or downloadをクリックして、Download zipをクリックしてダウンロードします。そして、opencv-master/data/haarcascades/の中にあるhaarcascade_frontalface_default.xmlというファイルを使います。
まず、こちらの画像を顔検出して四角で囲んでみます。
face.pyにコードを書きます。face.pyと同じ階層にhaarcascade_frontalface_alt.xmlファイルを置いときます。face.pyのコードは以下。
参考にした記事はこちら(PythonでOpenCVを使った顔検出してみた)。
import cv2
import matplotlib.pyplot as plt
# 画像ファイルを読み込む
img = cv2.imread("image.jpg")
# 画像をグレースケールへ変換
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# カスケードファイルのパス
cascade_path = "haarcascade_frontalface_alt.xml"
# カスケード分類器の特徴量取得
cascade = cv2.CascadeClassifier(cascade_path)
# 顔認識
faces=cascade.detectMultiScale(img_gray, scaleFactor=1.1, minNeighbors=1, minSize=(10,10))
# 検出位置描画
for x,y,w,h in faces:
cv2.rectangle(img, (x,y), (x+w, y+h), (0, 0, 255), thickness=30)
# 顔検出画像表示
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()
# 顔検出画像出力
cv2.imwrite("out.jpg", img)
顔認識をする場合は、グレースケールへ変換するのが一般的のようです。
顔認識cascade.detectMultiScaleでは、パラメータ(scaleFactor, minNeighbors, minSize)を設定できます。パラメータについてはこちらの記事(物体検出(detectMultiScale)をパラメータを変えて試してみる(scaleFactor編))を参考にしてください。
結果はこちら。見事に顔が検出されています。
顔検出して画像を保存
上記のOpenCVのカスケード分類器を使って、嵐のメンバー(ここでは二宮和也)の顔検出をして画像を保存します。
Desktopにあるarashiディレクトリの中にface_detect.py、haarcascade_frontalface_alt.xml、二宮君の画像が入ったninomiyaフォルダを置きます。
- arashiの構造
- face_detect.py
- haarcascade_frontalface_alt.xml
- ninomiya
- 二宮画像1
- 二宮画像2
- 二宮画像3
- ・・・
こちらがコード(face_detect.py)です。
import cv2
import glob
import os
# メンバー名
member_name = "ninomiya"
# 嵐メンバーの画像フォルダのパス
path ="/Users/ユーザー名/Desktop/arashi/" + member_name
# 嵐メンバーの画像フォルダの中の全画像のパスを取得して配列化
img_path_list=glob.glob(path + "/*")
# 番号の初期化
count = 0
# 画像パス配列から画像パスを取り出していくループ
for img_path in img_path_list:
count += 1
print(str(count) + "/" + str(len(img_path_list)))
# 画像ファイル名を取得
base_name = os.path.basename(img_path)
# 画像ファイル名nameと拡張子extを取得
name,ext = os.path.splitext(base_name)
# 画像ファイル以外のファイルの場合はループをスキップ
if (ext != '.jpg') and (ext != '.jpeg') and (ext != '.png'):
print("not a picture")
continue
# 画像ファイルを読み込む
img_src = cv2.imread(img_path, 1)
# 画像をグレースケールへ変換
img_gray = cv2.cvtColor(img_src, cv2.COLOR_RGB2GRAY)
# カスケードファイルのパス
cascade_path = "haarcascade_frontalface_alt.xml"
# カスケード分類器の特徴量取得
cascade = cv2.CascadeClassifier(cascade_path)
# 顔認識
faces=cascade.detectMultiScale(img_gray, scaleFactor=1.1, minNeighbors=1, minSize=(10,10))
# 顔がない場合はループをスキップ
if len(faces) == 0:
# print("no face" + name + ext)
number_no_face += 1
# --- 以下部分はコメントアウトしてもOK ---------------
# 顔を検出出来なかった場合は、その画像を保存する
# ディレクトリ名指定
dirname = member_name + "_no_face"
# ディレクトリがない場合は作成
if not os.path.exists(dirname):
os.mkdir(dirname)
# ファイル名指定(元の画像のファイル名base_nameを使う)
file_name = dirname + "_" + base_name + ext
# ディレクトリ名とファイル名を結合
file_path = os.path.join(dirname, file_name)
# ファイルの保存
cv2.imwrite(file_path, img_src)
# --- 以上部分はコメントアウトしてもOK ---------------
# スキップ
continue
# 顔がある場合
number_face += 1
# 顔部分画像を取得
for x,y,w,h in faces:
face = img_src[y:y+h, x:x+w]
# リサイズ
face = cv2.resize(face, (64, 64))
# 顔を検出できた画像を保存する
# ディレクトリ名指定
dirname = member_name + "_face"
# ディレクトリがない場合は作成
if not os.path.exists(dirname):
os.mkdir(dirname)
# ファイル名指定
file_name = dirname + "_" + str(number_face) + "_" + name + ext
file_name = dirname + "_" + str(number_face) + "_" + ext
# ディレクトリ名とファイル名を結合
file_path = os.path.join(dirname, file_name)
# ファイルの保存
cv2.imwrite(file_path, face)
このように、二宮君の顔検出した画像が保存されます。
しかしながら、すべての画像が顔検出できるわけではなく、顔検出ができなかった画像(以下)もありました。顔が横向きだったり、顔が斜めになっている場合は顔検出が難しいようです。

今回、コードはこちらの記事(Kerasでアニメ 「けいおん!」を画像認識させてみた)を参考にしました。今回のコードだけではなく、こちらの記事を参考に進めています。







[…] 関連記事:OpenCVのカスケード分類器で顔検出をしてみた! […]
[…] して、顔部分だけの画像を生成します。また、64 x 64にリサイズします。その方法についてはこちらの記事(関連記事:OpenCVのカスケード分類器で顔検出をしてみた!)にまとめました。 […]