Face Tracking with ARKitでできること

## ドキュメント
![1998_wide_250x141_2x.jpg](https://qiita-image-store.s3.amazonaws.com/0/47337/63df2ea0-33c5-e696-dfaf-362e2a97c820.jpeg)

* [ARFaceGeometry](https://developer.apple.com/documentation/arkit/arfacegeometry)に1220個の[vertex](https://developer.apple.com/documentation/arkit/arfacegeometry/2931116-vertices)がある
* [vertex](https://developer.apple.com/documentation/arkit/arfacegeometry/2931116-vertices)とは顔にある点の座標情報
* 番号の並び順は公開されていないので自分で調べる必要がある(調べる機能を実装しました)

###できること
* [BlendShapeLocation] (https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation)を使って顔の各部位の状態を取得できる
* [BlendShapeLocation](https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation)から取得できる各部位の動きを係数0.0〜1.0の間で取得できる
* 現在[cheekPuff](https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation/2928232-cheekpuff)の値が0.2以上で口が開いていると判定している(変更可能)
* [mouthFunnel](https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation/2928253-mouthfunnel)は0.25以上で口を丸くしていると判定している(変更可能)


| 動き | プロパティ| 
|:-----------|:------------|
| 両頬の外側への動き| [cheekPuff](https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation/2928232-cheekpuff)|
| 左頬の周辺の上方向への移動 | [cheekSquintLeft](https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation/2928226-cheeksquintleft) |
| 右頬の周辺の上方向への移動 | [cheekSquintRight](https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation/2928238-cheeksquintright)   |
| 唇の収縮 | [mouthFunnel](https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation/2928253-mouthfunnel) |
| 舌がでているか(iOS12から) | [tongueOut](https://developer.apple.com/documentation/arkit/arfaceanchor/blendshapelocation/2968190-tongueout) |

-----------------------------

* 各部位の位置を指定して取得はできない。
* しかしインデックス定数を使用することで特定位置の取得はできる。
* 鼻のてっぺんは9で固定
* なので頬の近くのインデックスがわかれば取得は可能？

**しかし将来のハードウェアなどでこのインデックスが有効であるかどうかは分かりません。**

-----------------------------
###右頬から左頬への距離計算の精度検証

通常時と口角を広げた表情での赤青の距離をアプリで計測した長さと定規で計測した長さで比較しました。
 
|| 定規 | アプリ| 
|:-----|:-----------|:------------|
| 通常時 | 8.1cm | 8.0~8.6cm |
| 口角を広げた | 9.0cm | 9.0~9.7cm |
 
- 大体ですが+0.7cmくらいの誤差
- マイナスになることは無かった
- 角度を変えたり近さを変えた時の誤差は0.2〜0.3程度

###口角の距離計算の精度検証

通常時と口角を広げた表情での赤青の距離をアプリで計測した長さと定規で計測した長さで比較しました。

|| 定規 | アプリ| 
|:-----|:-----------|:------------|
| 通常時| 4.2cm | 4.1~4.4cm |
| 口角を広げた | 5.4cm | 5.3~5.7cm |
| 口角をすぼめた | 2.7cm | 2.6~3.0cm |

- 大体0.4cmくらいの誤差(距離が短いから?)

----------------------------------
###仕組み
![20170530185528.png](https://qiita-image-store.s3.amazonaws.com/0/47337/1efd5a3e-2368-6c06-76e2-85b0d83a3941.png)

- ルートノードにはマスク情報が入っている
- 点や線を追加するにはルートノードにチルドノードとして登録して描画する

チルドノードにnameを登録してルートノードにaddする。
nameをキーにしてハンドリングする。

```swift:qiita.swift
// マスクがレンダリングされるとき
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        guard let faceAnchor = anchor as? ARFaceAnchor else { return nil }
        let faceGeometry = ARSCNFaceGeometry(device: device)
        let rootNode = SCNNode(geometry: faceGeometry)
        node.geometry?.firstMaterial?.fillMode = .lines

        let rightCheekNode = SphereNode(with: 0.003, color: .blue)
        rightCheekNode.name = Constants.FacePart.RightCornerOfMouth.rawValue
        node.addChildNode(rightCheekNode)

        let leftCheekNode = SphereNode(with: 0.003, color: .red)
        leftCheekNode.name = Constants.FacePart.LeftCornerOfMouth.rawValue
        node.addChildNode(leftCheekNode)

        return rootNode
    }
```