Firebase MLKitのFace Detectionでイケメン度を検出する

あなたはイケメンの定義を知っているだろうか？

[イケメンの定義って？　顔の特徴と、顔だけじゃないカッコいい男の条件とは| マイナビウーマン](https://woman.mynavi.jp/article/170528-7/)等でも語られている通り、**爽やかな笑顔**が条件であることは言うまでもない。

今回、Firebaseの[MLKit](https://firebase.google.com/docs/ml-kit/)の顔認識を使ってみるついでにイケメン度を検出できるかどうかを検証してみた。

ということで、イケメン風の男性に出演を依頼し、彼を用いてFirebase MLKitのFaceDetectionで出来ることを確認していく。

## イケメンの顔を検出
![IMG_2208.jpg](https://qiita-image-store.s3.amazonaws.com/0/111366/726ca439-f571-7d8c-e1f1-c462c87ebaa0.jpeg)

まずは顔自体を検出しないと始まらない。緑の範囲が顔の枠。

[VisionFace](https://firebase.google.com/docs/reference/swift/firebasemlvision/api/reference/Classes/VisionFace)にあるframeプロパティから枠が取得できる。

次はイケメンの顔のパーツを検出していこう。

## イケメンの顔ランドマーク検出
![IMG_2211.jpg](https://qiita-image-store.s3.amazonaws.com/0/111366/a86beddc-9634-9921-ba08-c64baccedaa8.jpeg)

[VisionFace](https://firebase.google.com/docs/reference/swift/firebasemlvision/api/reference/Classes/VisionFace)の[landmark(ofType: FaceLandmarkType)](https://firebase.google.com/docs/reference/swift/firebasemlvision/api/reference/Classes/VisionFace#/c:objc(cs)FIRVisionFace(im)landmarkOfType:)メソッドで点が取得できる。

[FaceLandmarkType](https://firebase.google.com/docs/reference/swift/firebasemlvision/api/reference/Type-Definitions#/c:FIRVisionFaceLandmark.h@T@FIRFaceLandmarkType)には、

- mouthBottom(口の下部)
- mouthLeft(口の左部)
- mouthRight(口の右部)
- noseBase(鼻)
- leftEye(左目)
- rightEye(右目)
- leftEar(左耳)
- rightEar(右耳)
- leftCheek(左頬)
- rightCheek(右頬)

が用意されている。イケメンは顔のバランスがシンメトリーであると言われているため、リアルな話この情報からイケメン度は検出することが可能だ。

ちなみにパーツはrectangleとして取得できるわけではないので、これだけでは例えば目を切り取ったりはできない。

## 笑顔度と目の開き度の検出

[VisionFace](https://firebase.google.com/docs/reference/swift/firebasemlvision/api/reference/Classes/VisionFace)には、smilingProbability, leftEyeOpenProbability,rightEyeOpenProbabilityというpropertyがあって、目の開き度合いと笑い度合いが取得できる。

||左目だけ<br>開けてる<br>イケメン|右目だけ<br>開けてる<br>イケメン|目を見開く<br>イケメン|両目閉じて<br>ちょい笑う<br>イケメン|笑う<br>イケメン|
|:-:|:-:|:-:|:-:|:-:|:-:|
|イケメン|<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/726ca439-f571-7d8c-e1f1-c462c87ebaa0.jpeg" width=90>|<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/d52122cb-abbf-c7ee-6874-8ee516f894b5.jpeg" width=90>|<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/0a0a0a03-ce54-42b8-81ab-8d5741cf7a18.jpeg" width=90>|<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/a86beddc-9634-9921-ba08-c64baccedaa8.jpeg" width=90>|<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/b35bf476-ed81-3365-65b8-849d2c8e2167.jpeg" width=90>|
|smilingProbability|0.086|0.065|0.169|0.794| **0.992**|
|leftEyeOpenProbability| **0.99**|0.574| **0.995**|0.023|0.996|
|rightEyeOpenProbability|0.008|0.107|**0.999**|0.021|0.993|

目の開き度はとてもいい感じだが、笑顔度合いは口の角度で決定されるようなので、**目は笑ってなくても笑ってることになる。** これではイケメンかどうか判別するのが少し難しいかもしれない。

## 顔の角度が取れる
![IMG_8409E0698DD9-1.jpeg](https://qiita-image-store.s3.amazonaws.com/0/111366/6f68492b-72c7-c7c9-a44d-1ee7f2a260de.jpeg)


headEulerAngleYとheadEulerAngleZが取得できて、顔の向きを取得することができる。自撮りが当たり前となっている昨今では、**斜め左上から撮影するとイケメンに見えると言われている。**リアルな話、この斜め左上を数値化することができるため、よりイケメンに取れる角度をフィードバックすることが可能だ。

## 結論
<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/0a0a0a03-ce54-42b8-81ab-8d5741cf7a18.jpeg">

- **イケメン**としての笑顔度
- **イケメン**としての目の開き度
- **イケメン**に見える角度
- **イケメン**としてシンメトリーか否か

といった情報をなんとOn Deviceで取得できるMLKitのFace Detection.

**イケメンを検出するのが可能だということがわかった。**

iOS11から用意されているVisionフレームワークの方は顔ランドマークからrectangleまで描画できるが、MLKitのFace Detectionのメリットとしては、笑い度や目の開き度、角度が取れること、そしてiOS, Androidの両方のOSで使えること、また、そもそもはTensorFlowだと思うので、拡張性があるという点にあると思う。

## 参考文献
- https://firebase.google.com/docs/ml-kit/
- https://firebase.google.com/docs/ml-kit/detect-faces
- https://firebase.google.com/docs/reference/swift/firebasemlvision/api/reference/Classes/VisionFace
- https://firebase.google.com/docs/ml-kit/ios/detect-faces