美女を見分けられない機械はだだの機械だ：OpenCV, Python3による画像からの顔抽出

#動機
これから機械学習を勉強するに当たり、好きな女性芸能人の分類器を作成することにした。美女を見分けられない機械などだだの機械である。
BingのAPIを用いて、

- 満島ひかり
- ガッキー
- 宮崎あおい
- 沢尻エリカ
- 本田翼

の画像を各600~700枚ほど収集した。それらの画像から機械学習させやすいように顔の部分のみを切り取りたい。
BingのAPIを用いた画像の収集方法は以下の記事に書いてある。

1. [Bingの画像検索APIを使って画像を大量に収集する](https://qiita.com/ysdyt/items/49e99416079546b65dfc)
こちらの情報はBing画像検索APIのバージョンが古いが下の記事のベースにもなっている。
2. [Bing画像検索API v7で画像を収集する](https://qiita.com/hirosemi/items/086f8375fd0f3fa5237b)
プログラムはこの記事のものをほとんどそのままをコピペさせていただいた。

*好きなもの、または人の画像じゃない限り何百枚も見ると吐き気を催すと思われる

#OpenCVの利用
OpenCVは以下のように説明されている。
>OpenCV（正式名称： Open Source Computer Vision Library）は、オープンソースのコンピューター・ビジョン・ライブラリです。コンピューターで画像や動画を処理するのに必要な、さまざま機能が実装されており、BSDライセンスで配布されていることから学術用途だけでなく商用目的でも利用できます。
>
>OpenCVを使うと、主に以下のような機能を利用できます。
>
>フィルター処理
>行列演算
>オブジェクト追跡（Object Tracking）
>領域分割（Segmentation）
>カメラキャリブレーション（Calibration）
>特徴点抽出
>物体認識（Object recognition）
>機械学習（Machine learning）
>パノラマ合成（Stitching）
>コンピュテーショナルフォトグラフィ（Computational Photography）
>GUI（ウィンドウ表示、画像ファイル、動画ファイルの入出力、カメラキャプチャ）
>>引用元「OpenCVとは？ 最新3.0の新機能概要とモジュール構成」 https://www.buildinsider.net/small/opencv/001

初めOpenCVという名前を聞いたときはプログラミング言語の一種だと思ったが、ライブラリであるらしい。上記の使用用途のうち特徴点抽出を用いて、顔を抽出していく。
OpenCVのインストールは様々あり、ググれば出てくるのでお好きな方法で。
私はpipを用いてインストールした。

```
pip install opencv-python
```

(*注意)
この方法だとopenCVのカスケード分類器のxmlファイルがダウンロードされていなかった(私が見つけられなかっただけかもしれない)。なので[openCVのgithubリポジトリ](https://github.com/opencv/opencv/tree/master/data/haarcascades)にそれらのxmlファイルがあるので、ダウンロードしてプログラムと同じディレクトリに置いた。

#プログラム
プログラム作成に当たり[OpenCVを使った顔認識（Haar-like特徴分類器）](https://qiita.com/hitomatagi/items/04b1b26c1bc2e8081427)を参考にした。Pythonはほぼ初心者なので改善点などがあったら教えてください。
画像を格納しているフォルダを以下のような構造で決め打ちしているので注意。コピペする場合は画像フォルダを以下のように構成してください。

- faceAreaExtraction.py
- haarcascades
    - haarcascade_frontalface_default.xml
    - ...
- imgs
 - aoi
       - image_aoi_1.jpg
       - ...
 - erika
       - image_erika_1.jpg
       - ...
 - gakky
 - hikari
 - tsubasa

```python:faceAreaExtraction.py
import cv2
import os, glob

#各美女の画像フォルダが保存されているフォルダ名
DIR_NAME = 'imgs'
#美女のフォルダ名
HER_NAME = 'hikari'
#美女画像の読み出し場所
READ_PATH = DIR_NAME + '/' + HER_NAME
#顔を切り取った画像の保存先
SAVE_PATH = DIR_NAME + '/' + HER_NAME + '_ROI'

#顔画像を保存するフォルダが無ければ作る
if not os.path.exists(SAVE_PATH):
    os.makedirs(SAVE_PATH)

#Haar-like特徴量分類器の読み込み
face_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml')

#READ_PATH中の全てのイメージファイルの顔検出をする, READ_PATH中のファイルは全てイメージファイルじゃなくてはいけない
hit = 0        #検出数のカウント
miss = 0       #非検出数のカウント

for filepath in glob.glob(READ_PATH + "/*.jpg"):
    print(filepath)
    img = cv2.imread(filepath)

    #グレイスケールに変換
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    #顔を検出する
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.2)

    if len(faces) > 0:   #検出できたとき
        for (x, y, w, h) in faces:
            hit += 1
            #roi = region of interest
            roi_color = img[y:y + h, x:x + w]
            #roiをリサイズしてサイズを統一する
            roi_resize = cv2.resize(roi_color, (128, 128))
            #保存
            cv2.imwrite('{}/{}_{}.jpg'.format(SAVE_PATH, HER_NAME, hit), roi_resize)
    else:
        miss += 1

print("{}枚の顔画像が{}に保存されました.".format(hit, SAVE_PATH))
print("{}枚の画像の顔抽出に失敗しました.".format(miss))
```

#画像の選り抜き
上記のプログラムで抽出した顔画像には、

1. そもそもwebから取ってきた段階で画像が本人じゃない
2. 本人も写っていたが本人以外の顔を抽出している
3. 全然違う場所を顔として抽出している

といった理由によって、機械学習させるに当たり間違った画像が含まれている。よってこれらを手作業で取り除いた。
コレケッコウシンドイヨ!!!

#結果
全ての美女に対し、Bing画像検索から集めてきた画像枚数に比べて顔検出画像は半分以下の枚数になってしまっている。検出の精度はお世辞にもいいとは言えないし、結構な枚数を手作業で取り除いた。

- 満島ひかり : 640枚 -> 296枚
- ガッキー : 735 -> 235
- 宮崎あおい : 660 -> 319
- 沢尻エリカ : 645 -> 302
- 本田翼 : 628 -> 228

カスケード分類器を変更してみたり、パラメータの調整をすることでもう少し精度は上がるのではないかと思われる。
また、入力画像のサイズの統一、顔の角度を調整することでも精度の向上が見込める。~~時間があったら試してみたいが、今回はこれが本題じゃないので深追いしないことにする。~~

-> コードに間違いがあったようで、修正したら+100枚ほど多くの顔をトリミングできた。上記のコードは修正後のものなので安心してください。

よーし、この数多の美女達を率いて機械学習に乗り込もうではないか。