✌️

【XREAL Light】ピースで写真が撮れるアプリを作る【ハンドジェスチャー編】

2023/12/20に公開

この記事は Panda株式会社 Advent Calendar 2023 14日目の記事です。
Panda株式会社は東京大学松尾研究室・香川高専発のスタートアップで、AR技術とAI技術を駆使したシステム開発と研究に取り組んでいます。
このアドベントカレンダーでは、スタートアップとしての知見、AI・AR技術、バックエンドなど、さまざまな領域の記事を公開していきます。

自己紹介
Panda株式会社代表取締役の田貝奈央です。ARグラスの普及に夢を見ている人です。高専の卒業研究ではXREAL Lightを使って目の前の人の顔を認証しプロフィール情報を提示する研究を行っていました。たくさんの人にXREAL Lightでのアプリ開発に取り組んでほしいと思っており、この記事を執筆しました。

概要

XREAL Lightを装着しピースのジェスチャーを行うと、XREAL Lightについているカメラの映像を撮影し、ローカルに保存するシステムを作成します。ハンドジェスチャーを認識してイベントを呼び出す方法と、カメラの映像を撮影しローカルに保存する方法の二回に分けて説明を行います。アドベントカレンダーで公開される記事になっているため、投稿日現在(2023/12/20)、アクセスできない記事が含まれています。

  1. (本記事)【XREAL Light】ピースで写真が撮れるアプリを作る【ハンドジェスチャー編】
  2. 【XREAL Light】ピースで写真が撮れるアプリを作る【写真撮影編】

環境

  • Unity 2022.3.6f1
  • NRSDK v2.1.0

準備

こちらの記事を参考にNRSDKをプロジェクトにインポートし、NRSDKを使うための設定を行います。

そしてこの記事を参考に、ハンドトラッキングができるように設定します。新しいシーンを作成し、MainCameraを消去しNRInputNRCameraRigをヒエラルキーから追加し、ハンドトラッキングによる入力ができる設定を行います。

ハンドジェスチャー認識時にイベントを呼び出す

まず、ピースのジェスチャーを認識した時にイベントを呼び出す仕組みを作成します。

ハンドジェスチャーに関してはこの記事で言及されています。今回は「Victory」であるピースを使って写真を撮る関数を呼び出します。

ハンドジェスチャー一覧

以下にコードを示します。

ハンドジェスチャーでイベントを呼び出すコード HandGesturePhotoCapture.cs 全体

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using NRKernal;

namespace NRKernal.NRExamples{
	public class HandGesturePhotoCapture : MonoBehaviour
	{
	    private float victory_count;
	    private bool takeflag;
	    // Start is called before the first frame update
	    void Start()
	    {
		victory_count = 0f;
		takeflag = false;
	    }

	    // Update is called once per frame
	    void Update()
	    {
		// 手のトラッキングが実行中かどうかを確認
		if (NRInput.Hands.IsRunning)
		{
		    // 右手の状態を取得
		    HandState handState = NRInput.Hands.GetHandState(HandEnum.RightHand);

		    // 右手がトラッキングされているかどうか、ピースジェスチャーが行われているかをチェック
		    if (handState.isTracked && handState.isVictory)
		    {
			if (takeflag == false){
			    if (victory_count <= 50)
			    {
				victory_count++;
			    }
			    else{
				CapturePhoto();
			    }
			}
		    }
		    else
		    {
			takeflag = false;
			victory_count = 0;
		    }
		}
	    }
	    private void CapturePhoto()
	    {
		takeflag = true;
		Debug.Log("写真をとります");
	    }
	}
}

NRInput.Hands.IsRunning を使うことでハンドトラッキングが実行されているかどうかを認識します。ハンドトラッキング実行中であればNRInput.Hands.GetHandState(HandEnum.RightHand) を呼び出し、右手の状態HandState を取得します。

次に、右手がトラッキング中でピースジェスチャーが行われている場合は、撮影処理に進みます。この時、連続して撮影されることを防ぐためtakeflag 変数を用意します。フラグがfalseの場合、まだ撮影されていないため、50のカウントを行い、CaputrePhoto 関数を実行します。

CapturePhoto 関数には撮影のための詳細な処理が必要ですが、今回はDebug.Log() を用いてこの関数が実行されていることを確認します。この関数を実行するときにtakeflag 変数をtrue にすることで、今回のジェスチャーではすでに写真が撮られていることを示します。

このコードでは、handState.isVictory という形で現在の手の状態がVictoryであるかを取得していますが、SDKに入っているHandState.cs にはisPinching という現在の手の状態がピンチであるかを返す関数しか実装されていません。そこで、同じようにVictory であるかを返す関数を実装します。

HandState.csの抜粋
     	public bool isPinching
        {
            get =>
#if UNITY_EDITOR
                Input.GetKey(KeyCode.Mouse0) ||
#endif
                currentGesture == HandGesture.Pinch;
        }

+        public bool isVictory
+        {
+            get =>
+ #if UNITY_EDITOR
+                Input.GetKey(KeyCode.V) ||
+ #endif
+                currentGesture == HandGesture.Victory;
+        }

これにより、現在のジェスチャの状態をisVictory 関数で受け取れるようになりました。Input.GetKey(KeyCode.V) を使うことで、Unity Editor上で実行している際にV キーをピースのハンドジェスチャーをやっていることを返せるようになりました。

しかし、このままでUnity Editor上から実行しても、ハンドトラッキングをシミュレーションするハンドモデルには変化がありません。これは、NREmulatorHandTracking.cs というエミュレータ上でのハンドトラッキングを管理するクラスのm_TestHandStatesDict にピースのハンドジェスチャーが登録されていないからです。以下のようにm_TestHandStatesDictKeyCode.V が押されたときにVictory の手の形になることを登録する必要があります。

NREmulatorHandTracking.csの抜粋
public NREmulatorHandTracking()
{
    m_DefaultLostHandState = CreateTestHandState_Lost_None(HandEnum.RightHand);
    m_DefaultTrackedHandState = CreateTestHandState_Found_OpenHand(HandEnum.RightHand);
    m_TestHandStatesDict = new Dictionary<KeyCode, HandState>()
    {
        {KeyCode.Mouse0, CreateTestHandState_Found_Pinch(HandEnum.RightHand)},
        {KeyCode.Mouse1, CreateTestHandState_Found_Point(HandEnum.RightHand)},
        {KeyCode.Mouse2, CreateTestHandState_Found_SystemGesture(HandEnum.RightHand)},
+        {KeyCode.V, CreateTestHandState_Found_Victory(HandEnum.RightHand)}
    };
}

CreateTestHandState_Found_Victory も存在しないため、同じクラスの下部に以下内容を書き足します。

NREmulatorHandTracking.csの抜粋
private HandState CreateTestHandState_Found_SystemGesture(HandEnum handEnum)
{
    var handState = new HandState(handEnum);
    handState.isTracked = true;
    handState.currentGesture = HandGesture.None;
    HandJointPoseDataUtility.JsonToDict(HandJointsArrayData.HandJointsArrayData_Right_SystemGesture_Json, handState.jointsPoseDict);
    return handState;
}

+private HandState CreateTestHandState_Found_Victory(HandEnum handEnum)
+{
+    var handState = new HandState(handEnum);
+    handState.isTracked = true;
+    handState.currentGesture = HandGesture.Victory;
+    HandJointPoseDataUtility.JsonToDict(HandJointsArrayData.HandJointsArrayData_Right_Victory_Json, handState.jointsPoseDict);
+    return handState;
+}

#endregion

HandGesturePhotoCapture.cs スクリプトをシーン内のオブジェクトにアタッチすることで、ピースのジェスチャーを認識するとイベントを呼び出すことができるようになりました。

シーン内のオブジェクトにスクリプトをアタッチ

https://youtu.be/XZm6WXL_c10

おわりに

今回は「【XREAL Light】ピースで写真が撮れるアプリを作る【ハンドジェスチャー編】」というテーマでPanda株式会社 Advent Calendar 2023 14日目を執筆させていただきました。
本記事では、ハンドジェスチャーを認識してイベントを呼び出す方法を紹介しました。
エミュレーター上でのハンドジェスチャーの種類を追加できるようになり、ビルドの手間を減らせることができるようになったと思います。
明日の記事も私、Panda株式会社代表取締役の田貝奈央による「【XREAL Light】ピースで写真が撮れるアプリを作る【写真撮影編】」です。お楽しみに!

Panda株式会社

Discussion