【機械学習】OpenCVを使った物体検出で顔を検出してみた

# OpenCVについて

OpenCVはインテルによって公開されたコンピュータビジョン向けのライブラリ。描画や画像の編集などの際によく使われるが、機能が非常に多く機械学習向けの機能も提供されている。以下で公開されているhaarcascadesファイル（カスケードファイル）を利用することで、特定の物体に限り、物体検出タスクを行うことができる。ディープラーニング程の検出精度は出ないものの、学習を行う必要がなく、GPU環境も不要なことから、手軽に物体検出を行うことができると言ったメリットがある。

# haarcascades（カスケードファイル）について

カスケードファイルは以下githubで公開されている。  

- https://github.com/opencv/opencv/tree/master/data/haarcascades


|  ファイル |  検出対象  | 
| ---- | ---- | 
|haarcascade_eye.xml|目|
|haarcascade_eye_tree_eyeglasses.xml|メガネ|
|haarcascade_frontalcatface.xml|猫顔(正面)|
|haarcascade_frontalcatface_extended.xml|猫顔(正面)|
|haarcascade_frontalface_alt.xml|人顔(正面)|
|haarcascade_frontalface_alt2.xml|人顔(正面)|
|haarcascade_frontalface_alt_tree.xml|人顔(正面)|
|haarcascade_frontalface_default.xml|人顔(正面)|
|haarcascade_profileface.xml|人顔(プロフィール)|
|haarcascade_fullbody.xml|体全体|
|haarcascade_smile.xml|笑顔|
|haarcascade_upperbody.xml|上半身|
|haarcascade_lowerbody.xml|下半身|
|haarcascade_righteye_2splits.xml|右目|
|haarcascade_lefteye_2splits.xml|左目|
|haarcascade_russian_plate_number.xml|ロシアのナンバープレート|
|haarcascade_licence_plate_rus_16stages.xml|ロシアのナンバープレート|

これらをopencvから呼び出すことで簡単に物体検出を行うことが可能

# 環境

- Ubuntu16.04.3 LTS
- Python:3.6

# 対象
どのような顔が認識可能か調べるため、以下のファイルで実行することとした。

|  対象画像 |  説明  |
| ---- | ---- |
| ![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/b2fe4ed9-2eb8-606f-2bc4-4d9518fd0ebe.png)| 複数人。乃木坂46の画像で検証 |
|![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/02080b29-ad99-e65b-9190-d616fd37bfce.jpeg)| 変顔。トランプ大統領の画像で検証|
|![004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/f00eaab8-eda5-3eb3-00a7-ca4342f2f739.jpeg)| 化粧。聖飢魔Ⅱの画像で検証|
|![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/12274096-5dc2-9d03-b7d4-0862bf2847f1.jpeg)| マスク。ザ・グレートサスケの画像で検証|

# 実装

ソースコードは以下。  

```Python 
import cv2
import glob

#パラメーター設定
ORGDIR = "./sample/"
RSTDIR = "./result/"

CS="../haarcascades/haarcascade_frontalface_default.xml"
SF=1.1   #各画像スケールにおける縮小量
MN=1     #信頼度に関するパラメーター


def detector ():

    #cascadeファイル読み込み
    cascade  = cv2.CascadeClassifier(CS)

    #対象ファイル読み込み
    tgtpaths=glob.glob(ORGDIR+"*")

    for tgtpath in tgtpaths:
        orgimg = cv2.imread(tgtpath, cv2.IMREAD_COLOR)
        grayimg = cv2.cvtColor(orgimg, cv2.COLOR_BGR2GRAY)

        boxes = cascade.detectMultiScale(grayimg,scaleFactor=SF,minNeighbors=MN)

        #矩形の描画
        for box in boxes:
            cv2.rectangle(orgimg,tuple(box[0:2]),tuple(box[0:2]+box[2:4]), (0, 0,255),thickness=1)

        rstpath=tgtpath.replace(ORGDIR,RSTDIR)
        print(rstpath)
        cv2.imwrite(rstpath, orgimg)


if __name__=="__main__":
    detector()

```






# 結果

|  画像 |  説明  |
| ---- | ---- |
|![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/b964c9d1-5d95-2d16-f36e-41b5243035c7.png)| 誤検出があるものの全員の顔を検出 |
|![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/20a9cec7-285f-35b7-71ff-02eef8da81cb.jpeg)| 顔の傾きや、崩れがあるものの検出 |
|![004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/fb03f8af-9f46-abfe-e374-ef66370e1a3c.jpeg)| 一名除き検出に成功 |
|![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573779/32fa543f-6bc0-33f7-8a34-3136684e4697.jpeg)| 検出できず。マスクをすることで顔の特徴を捉えられなかったものと推測。 |


# まとめ
opencvを使用することで、簡単に顔の検出を行うことができた。