UnityとRealSenseで顔と手の認識

Unity+RealSenseSDKはバージョン違いで情報が錯綜している気がするので現時点の動作報告的内容です。
一応このままでも頭と手だけのモデルを動かすのには使えるかもしれません。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Qiitaに直接で動画は張りにくいんですね。ソース清書したのでまとめました。 <a href="https://t.co/uR5f9JCSsI">pic.twitter.com/uR5f9JCSsI</a></p>&mdash; 琴葉 葵（偽） (@Hv2RMjHzDyqXVIr) <a href="https://twitter.com/Hv2RMjHzDyqXVIr/status/868845935714902018">2017年5月28日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

Version
Unity:5.6.1f1 Personal
RealSenseSDK:2016 R3
Device:SR300

動かし方
空のシーンを作ってカメラに下のコードをコピペして作ったスクリプトをアタッチします。
頭と左右の手に何でもいいのでオブジェクトをアサインします。(頭は向きが分かる物が良いですね。)
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/183870/bb4307c3-7ef1-3382-2aea-45af46f47f44.png)

注意
ミラー動作にしたいので、Update()で左右を入れ替えてます。

```csharp
using UnityEngine;
using Intel.RealSense;
using Intel.RealSense.Face;
using Intel.RealSense.Hand;

public class RSHand : MonoBehaviour
{
    public GameObject HeadObj;
    public GameObject HandObjR;
    public GameObject HandObjL;

    SenseManager SenseM;
    FaceModule FaceM;
    HandModule HandM;
    FaceData FaceD;
    HandData HandD;

    Vector3 HeadRot = new Vector3();
    Vector3 HandPosL = new Vector3();
    Vector3 HandPosR = new Vector3();

    void Start()
    {
        SenseM = SenseManager.CreateInstance();

        HandM = HandModule.Activate(SenseM);
        HandM.FrameProcessed += Hand_FrameProcessed;
        HandD = HandM.CreateOutput();

        FaceM = FaceModule.Activate(SenseM);
        FaceM.FrameProcessed += Face_FrameProcessed;
        FaceD = FaceM.CreateOutput();

        SenseM.Init();
        SenseM.StreamFrames(false);
    }

    private void Hand_FrameProcessed(object sender, FrameProcessedEventArgs args)
    {
        HandD.Update();
        IHand[] hand;
        if (HandD.QueryHandData(AccessOrderType.ACCESS_ORDER_BY_ID, out hand) == Status.STATUS_NO_ERROR)
        {
            foreach (IHand h in hand)
            {
                if (h.BodySide == BodySideType.BODY_SIDE_LEFT)
                {
                    HandPosL.x = h.MassCenterWorld.x * -1;
                    HandPosL.y = h.MassCenterWorld.y;
                    HandPosL.z = h.MassCenterWorld.z;
                    print("### L ###" + HandPosL.x + " | " + HandPosL.y + " | " + HandPosL.z);
                }
                if (h.BodySide == BodySideType.BODY_SIDE_RIGHT)
                {
                    HandPosR.x = h.MassCenterWorld.x * -1;
                    HandPosR.y = h.MassCenterWorld.y;
                    HandPosR.z = h.MassCenterWorld.z;
                    print("### R ###" + HandPosR.x + " | " + HandPosR.y + " | " + HandPosR.z);
                }
            }
        }
    }

    private void Face_FrameProcessed(object sender, FrameProcessedEventArgs args)
    {
        FaceD.Update();
        var face = FaceD.QueryFaceByIndex(0);
        if (face != null)
        {
            HeadRot.x = face.Pose.Angles.pitch;
            HeadRot.y = face.Pose.Angles.yaw * -1;
            HeadRot.z = face.Pose.Angles.roll;
            print("### F ### " + HeadRot.x + " | " + HeadRot.y + " | " + HeadRot.z);
        }
    }

    void Update()
    {
        HeadObj.transform.eulerAngles = HeadRot;
        HandObjL.transform.position = HandPosR;
        HandObjR.transform.position = HandPosL;
    }

    void OnDestroy()
    {
        FaceM.FrameProcessed -= Face_FrameProcessed;
        HandM.FrameProcessed -= Hand_FrameProcessed;
        FaceD.Dispose();
        HandD.Dispose();
        SenseM.Dispose();
    }
}
```

参考
http://www.buildinsider.net/small/bookrealsense/0801
http://tips.hecomi.com/entry/2015/02/25/030422
http://qiita.com/akihiro01051/items/3146b9a377bf360f58f5
https://software.intel.com/sites/landingpage/realsense/camera-sdk/v2016r3/documentation/html/index.html?doc_devguide_introduction.html

英語読めない人(私)は最後のやつを読むとき、
Chromeで開いてアドレス欄の翻訳アイコンから翻訳と原文何度も行き来すればなんとか読めるのでお勧めです。