Nuitrack 1.5.0
3D スケルトン トラッキング ミドルウェア
 すべて クラス 名前空間 関数 変数 Typedefs 列挙型 列挙子 プロパティ イベント グループ ページ
Nuitrack を使用したフェイス トラッキング

このチュートリアルは、Nuitrack を使用して、フェイストラッキングや顔のデータを取得する方法を紹介します。このプロジェクトでは、センサーから取得した RGB イメージが背景に表示され、顔には絵文字が表示されます。どの絵文字が表示されるか (性別、年代、表情) は、Nuitrack から取得したパラメーターによって決まります。このプロジェクトでは、さらに、トラッキングを行うスケルトンの数を最大 6体まで設定できます。多ければ多いほど楽しいでしょう!2D スケルトンが、ユーザーの体の上に表示されます。

このプロジェクトを作成するために必要なものは以下の通り、多くはありません:

  • Nuitrack
  • サポートされているセンサー (センサーの一覧は、弊社 Webサイトを参照)
  • Unity 2019.2.11f 以上

完成済みプロジェクトは Nuitrack SDK: [Unity 3D] > [NuitrackSDK.unitypackage] > [Tutorials] > [FaceTracker]にあります。

Face2.gif FaceGS.gif
左がaeroTAP 3D USB Camera、右がaeroTAP 3D USB Camera GS
注意
Nuitrack が顔の情報を表示するのは、ユーザーのスケルトンが検出された後になります。自分の顔だけが認識されている状態では、表示されません。スケルトンを表示することなく、フェイストラッキングのみを行う場合は、3DiVi Face SDK をご覧ください。これは、顔そのもののトラッキング、検出、一致の確認を行なう為のソフトウェアです。Nuitrack SDK とは異なり、3DiVi Face SDK は顔そのもののデータ処理に焦点を置き、この分野に関するより高度な機能を提供します。

シーンのセットアップ

  1. 新規 Unity プロジェクトを作成します。
  2. NuitrackSDK.unitypackageNuitrack SDK/Unity3D からプロジェクトにインポートします (このチュートリアルで作成するスクリプトや他のファイルを含むので、Tutorials/FaceTracker/FinalAssets フォルダーは除きます):そのためには、[Assets] > [Import Package] > [Custom Package...]コマンドを使用します。
  3. スケルトン トラッキング用の NuitrackScripts プレハブをシーンにドラッグ アンド ドロップします。NuitrackManager セクションで、必要なモジュール、Color Module On (センサーからの RGB イメージの出力)、Skeleton Module On (スケルトン トラッキング) を選択します。

    Uface_2.png

  4. Color Frame Canvas プレハブをシーンにドラッグ アンド ドロップします。このチュートリアルでは、センサーからの RGB イメージの出力とトラッキングを行ったスケルトンの表示のために、既存のプレハブとスクリプトを使用しました。既存のプレハブやスクリプトの作成方法に関する詳細を知りたい場合は、「RGB イメージ上にスケルトンを表示」チュートリアルをご覧ください。

    注意
    Color Frame Canvas は、センサーからの RGB イメージを標準的なインターフェイス コンポーネント イメージ上に表示します。DrawColorFrame スクリプトは、Texture2d を ColorFrame を使用して、RGB24 フォーマットで作成します。ColorFrame を取得するたびに、テクスチャが更新されます。
  5. Skeletons Canvas プレハブをシーンにドラッグ アンド ドロップします。[Canvas]セクションの[Sort Order] を 1 に設定することで、スケルトンは常に Color Frame Canvas 上に表示されます。[Sort Order]は、レンダリングを行う順番を定義します:Color Frame Canvas の[Sort Order]は、デフォルト値の 0 に設定されているので、背景に使用されます。

    Uface_3.png
    注意
    スケルトンがずれている場合、depth-to-color registration をオンにするため、nuitrack.config ファイルを使用します。[DepthProvider”]セクションの[Depth2ColorRegistration]を true に設定します。
    このプロジェクトで 2D スケルトンをユーザーの体の上に表示させるのは、よりシンプルで多用途に実装可能だからです。3D スケルトンを表示するには、センサーの方向、位置、FOV を Unity エディターに読み込む必要があります。
  6. プロジェクトを実行します。センサーからの RGB イメージがシーンに表示され、ユーザーの体には、トラッキングされているスケルトンが表示されているのが確認できます。いよいよ、このチュートリアルの最も楽しみな部分に移る時間です!

    Face.gif

顔の作成

  1. 新しいスクリプトを FaceInfo として作成します。このスクリプトは、Nuitrack が受け取った JSON レスポンスのパラメーターや値が含まれます (ドキュメント内の JSON レスポンスのサンプル)。

    注意
    デフォルトの設定では、Nuitrack による顔のトラッキングはオフになっています。有効にするには、nuitrack.config ファイルを開き、 Faces.ToUseDepthProvider.Depth2ColorRegistrationtrue に設定します。
    using UnityEngine;
    [System.Serializable]
    public class FaceInfo
    {
    public string Timestamp;
    public Instances[] Instances;
    }
    [System.Serializable]
    public class Instances
    {
    public int id;
    public string @class;
    public Face face;
    }
    [System.Serializable]
    public class Face
    {
    public Rectangle rectangle;
    public Vector2[] landmark;
    public Vector2 left_eye;
    public Vector2 right_eye;
    public Angles angles;
    public Emotions emotions;
    public Age age;
    public string gender;
    }
    [System.Serializable]
    public class Rectangle
    {
    public float left;
    public float top;
    public float width;
    public float height;
    }
    [System.Serializable]
    public class Angles
    {
    public float yaw;
    public float pitch;
    public float roll;
    }
    [System.Serializable]
    public class Emotions
    {
    public float neutral;
    public float angry;
    public float surprise;
    public float happy;
    }
    [System.Serializable]
    public class Age
    {
    public string type;
    public float years;
    }
    注意
    キーワードを識別子として使用することはできません (変数の名前、クラス、インターフェイスなど)。しかし、プレフィックス '@' と一緒に使用することはできます。例えば、class は指定されたキーワードなので識別子としては使用できませんが、'@'class は使用できます。
  2. 新しいスクリプトを FaceManager として作成します。性別、年代、感情の列挙子を作成し、考えられる値をすべて一覧にします。

    using System.Collections.Generic;
    using UnityEngine;
    public enum Gender
    {
    any,
    male,
    female
    }
    public enum AgeType
    {
    any,
    kid,
    young,
    adult,
    senior
    }
    public enum Emotions
    {
    any,
    happy,
    surprise,
    neutral,
    angry
    }

  3. 絵文字を表示する Canvas のための canvas フィールド、絵文字プレハブ用の faceController フィールド、skeletonController フィールド、 FaceControllers の一覧、顔のデータを含む配列を追加します。

    angry
    }
    public class FaceManager :MonoBehaviour
    {
    [SerializeField] Canvas canvas;
    [SerializeField] GameObject faceController;
    [SerializeField] SkeletonController skeletonController;
    List<FaceController> faceControllers = new List<FaceController>();
    Instances[] faces;
    FaceInfo faceInfo;
    }
    注意
    ここに挙げるサンプルは、2つの性別、4つの年代、4つの感情の絵文字です (このプロジェクトで、異なる年代や感情がどのように表示されるかの参考にしてください):
    • 嬉しい少女
    • 驚いた若い男性
    • 真顔の成人女性
    • 怒った年配の男性
    Uface_5.png

  4. Start では、シーンに顔を追加し、FaceControllers の一覧にも含めます。

    public class FaceManager :MonoBehaviour
    {
    ...
    FaceInfo faceInfo;
    void Start()
    {
    for (int i = 0; i < skeletonController.skeletonCount; i++)
    {
    faceControllers.Add(Instantiate(faceController, canvas.transform).GetComponent<FaceController>());
    }
    }
    }

  5. Update では、JSON レスポンスを取得し、JSON からのデータを faceInfo クラス (取得した顔情報を保存) に追加します。faceInfo (faceInfo.Instances) の顔を、顔の配列に追加します。FaceControllers をループ処理します。顔情報が利用できる場合は絵文字が表示され、利用できない場合は表示されません。id 変数と、現在の顔に関する情報を保存する currentFace 変数を作成します。顔の情報を FaceController 渡すと、顔が表示されます。id パラメーターを顔情報から取得し、id 変数に渡します。検出されたそれぞれのユーザーには、それぞれの ID があります。ユーザー id と Nuitrack でのスケルトン idは常に一緒です。ユーザー スケルトンを作成します。Nuitrack からスケルトン データを受け取ると、同じスケルトンID のスケルトンの取得を試みます。スケルトンが見つかると、joint 変数を作成し、 head と呼びます。スケルトンの joint head を取得し、スケルトンからの座標にセットします。絵文字が、頭の関節部分に表示されるようになります。

    public class FaceManager :MonoBehaviour
    {
    ...
    faceControllers.Add(Instantiate(faceController, canvas.transform).GetComponent());
    }
    }
    void Update ()
    {
    // Pass the data from JSON to faceInfo
    string json = nuitrack.Nuitrack.GetInstancesJson();
    // Replace quotation marks with square brackets to prevent a conversion error
    // in case an array is empty (no info about faces received)
    faceInfo = JsonUtility.FromJson<FaceInfo>(json.Replace("\"\"", "[]"));
    // Get all faces (faceInfo.Instances) from FaceInfo
    faces = faceInfo.Instances;
    for (int i = 0; i < faceControllers.Count; i++)
    {
    if(faces != null && i < faces.Length - 1)
    {
    int id = 0;
    Face currentFace = faces[i].face;
    // Pass face to FaceController
    faceControllers[i].SetFace(currentFace);
    faceControllers[i].gameObject.SetActive(true);
    // Face ids and skeleton ids are the same
    id = faces[i].id;
    nuitrack.Skeleton skeleton = null;
    if (NuitrackManager.SkeletonData != null)
    skeleton = NuitrackManager.SkeletonData.GetSkeletonByID(id);
    if(skeleton != null)
    {
    nuitrack.Joint head = skeleton.GetJoint(nuitrack.JointType.Head);
    faceControllers[i].transform.position = new Vector2(head.Proj.X * Screen.width, Screen.height - head.Proj.Y * Screen.height);
    //stretch the face to fit the rectangle
    if(currentFace.rectangle != null) faceControllers[i].transform.localScale = new Vector2(currentFace.rectangle.width * Screen.width, currentFace.rectangle.height * Screen.height);
    }
    }
    else
    {
    faceControllers[i].gameObject.SetActive(false);
    }
    }
    }
    }
    注意
    JsonUtility の詳細を確認できます(JSON データでの作業を行う際の機能)。
  6. 新しいスクリプトを FaceController として作成します。性別、年代、感情のためのパブリック フィールドを作成し、年代についてはテキスト フィールドも作成します。年代と感情は、それぞれDictionary<string, AgeType> ageDictionary<EmotionType, float> emotionDict に保存されています。"age type" は年代名 (ストリング)、"emotion value" (float) は "emotion type" で得ることができます。

    using UnityEngine;
    using System.Collections.Generic;
    using System.Linq;
    public class FaceController :MonoBehaviour
    {
    public Gender genderType;
    public EmotionType emotions;
    public AgeType ageType;
    Dictionary<string, AgeType> age = new Dictionary<string, AgeType>()
    {
    { "kid", AgeType.kid },
    { "young", AgeType.young }
    { "adult", AgeType.adult },
    { "senior", AgeType.senior },
    };
    Dictionary<EmotionType, float> emotionDict = new Dictionary<EmotionType, float>()
    {
    { EmotionType.happy, 0 },
    { EmotionType.surprise, 0 },
    { EmotionType.neutral, 0 },
    { EmotionType.angry, 0 },
    };
    }

  7. SetFace メソッドは、顔に関するすべての情報を保存している FaceInfo スクリプトから Face クラスを取り込みます。このメソッドでは、特定の顔のすべての特徴が適用されます。性別を割り当てます (男性か女性)。年代を名前で設定します。感情がどのように定義されるかと言いますと、dictionare 内の値がループ処理され、最も高い値を持つ感情が選択されます。

    public class FaceController :MonoBehaviour
    {
    ...
    { EmotionType.angry, 0 },
    };
    public void SetFace(Face newFace)
    {
    //Gender
    if (newFace.gender == "female")
    genderType = Gender.female;
    else
    genderType = Gender.male;
    //Age
    if(newFace.age != null)
    age.TryGetValue(newFace.age.type, out ageType);
    //Emotion
    if (newFace.emotions != null)
    {
    emotionDict[EmotionType.happy] = newFace.emotions.happy;
    emotionDict[EmotionType.surprise] = newFace.emotions.surprise;
    emotionDict[EmotionType.neutral] = newFace.emotions.neutral;
    emotionDict[EmotionType.angry] = newFace.emotions.angry;
    KeyValuePair<EmotionType, float> prevailingEmotion = emotionDict.First();
    foreach (KeyValuePair<EmotionType, float> emotion in emotionDict)
    if (emotion.Value > prevailingEmotion.Value) prevailingEmotion = emotion;
    emotions = prevailingEmotion.Key;
    }
    }
    }

  8. Unity で空のオブジェクトを作成し、FaceManager と名前を付けます。FaceManager スクリプトをこのオブジェクトにドラッグ アンド ドロップします。新しいキャンバスを作成し、Face Canvas と名前を付け、[Sort Order]を 2 に設定します。Face Canvas を、このオブジェクトの[Canvas]フィールドにドラッグ アンド ドロップします。Head (FaceTracker/Prefabs) を Face Controller フィールドにドラッグ アンド ドロップし、Skeletons Canvas (シーンから) をこのオブジェクトの Skeleton Controller フィールドにドラッグ アンド ドロップします。

    Uface_6.png

  9. Head プレハブをシーンにドラッグ アンド ドロップします。FaceController スクリプトをこのプレハブにドラッグ アンド ドラッグして、[Apply]をクリックします。head をシーンから削除します。
  10. プロジェクトを実行します。ユーザーの顔ではなく絵文字が表示されるようになりますが、どのユーザーも同じ表情 (デフォルトの設定では、若い男性が笑っている絵文字) となるのは、取得した顔のパラメーターが絵文字に適用されていないからです。この時点で、絵文字はユーザーの動きに応じて動きます。
Uface_7.gif

顔に関して取得したデータを適用

  1. 新しいスクリプトを FaceSwitcher として作成します。JSON からの情報に基づき、Unity の顔パラメーターを切り替えます。必要なフィールド (性別、年代、感情) と 2つのオブジェクトを追加します:enabledObject はすべての条件が true の時に有効に、1つでも条件が false の場合に無効になり、disabledObject はその逆です。FaceController フィールドとブール変数 display を追加することで、顔の表示/非表示を行えます。

    using UnityEngine;
    public class FaceSwitcher :MonoBehaviour
    {
    [SerializeField] Gender gender;
    [SerializeField] AgeType ageType;
    [SerializeField] Emotions emotions;
    [SerializeField] GameObject enabledObject;
    [SerializeField] GameObject disabledObject;
    FaceController faceController;
    bool display = false;
    }

  2. Start では、親オブジェクト内の FaceController コンポーネントを探し、faceController 変数に渡します。

    public class FaceSwitcher :MonoBehaviour
    {
    ...
    bool display = false;
    void Start ()
    {
    faceController = GetComponentInParent<FaceController>();
    }
    }

  3. SwitchObjects メソッドでは、該当するオブジェクトの有効/無効にするため、値が true/false によってパラメーターを表示/非表示にすることができます。

    public class FaceSwitcher :MonoBehaviour
    {
    ...
    faceController = GetComponentInParent();
    }
    void SwitchObjects()
    {
    if (enabledObject != null)
    enabledObject.SetActive(display);
    if (disabledObject != null)
    disabledObject.SetActive(!display);
    }
    }

  4. Update では、特定の条件/状況によって、display の値が変わります。すべての条件が true (性別、年代、感情が、Unity で指定されているものと一致) の場合、enabledObject が表示されます。条件が 1つでも false の場合、displayfalse となり、enabledObject は表示されません。

    public class FaceSwitcher :MonoBehaviour
    {
    ...
    faceController = GetComponentInParent<FaceController>();
    }
    void Update()
    {
    display = (gender == Gender.any ||gender == faceController.genderType) &&
    (ageType == AgeType.any || ageType == faceController.ageType) &&
    (emotions == EmotionType.any ||emotions==faceController.emotions);
    SwitchObjects();
    }
    void SwitchObjects()

  5. Head プレハブをシーンに、再度ドラッグ アンド ドロップします。[Head] > [Face]を選択し、FaceSwitcher コンポーネントを追加し、Gender:Male、Age Type:Any、Emotions:Any (階層的に割り当てられます) を選択します。enabledObject:Male、disabledObject:Female を割り当てます。

    Uface_8.png

  6. スクリーンショットにあるように、感情や年代を該当するフィールドにアサインします (FaceSwitcher コンポーネントを何度か追加する必要があります)。

    Uface_9.png

  7. プロジェクトを実行します。それぞれのユーザーのトラッキングされたスケルトンと顔の代わりの絵文字が表示されます。異なる絵文字は、ユーザーの性別、年代、感情によって表示されます。
Face2.gif FaceGS.gif

お疲れ様でした。Nuitrack を使ってプロジェクト内での顔のトラッキングを行う方法を!この情報をゲームや他のフィールドで活用できます。他のパラメータについても、Nuitrack からの JSON レスポンスを確認いただくと、ここでは取り上げられていない他の活用法を確認できます。お楽しみください!