【XREAL Light】ピースで写真が撮れるアプリを作る【ハンドジェスチャー編】
この記事は Panda株式会社 Advent Calendar 2023 14日目の記事です。
Panda株式会社は東京大学松尾研究室・香川高専発のスタートアップで、AR技術とAI技術を駆使したシステム開発と研究に取り組んでいます。
このアドベントカレンダーでは、スタートアップとしての知見、AI・AR技術、バックエンドなど、さまざまな領域の記事を公開していきます。
自己紹介
Panda株式会社代表取締役の田貝奈央です。ARグラスの普及に夢を見ている人です。高専の卒業研究ではXREAL Lightを使って目の前の人の顔を認証しプロフィール情報を提示する研究を行っていました。たくさんの人にXREAL Lightでのアプリ開発に取り組んでほしいと思っており、この記事を執筆しました。
概要
XREAL Lightを装着しピースのジェスチャーを行うと、XREAL Lightについているカメラの映像を撮影し、ローカルに保存するシステムを作成します。ハンドジェスチャーを認識してイベントを呼び出す方法と、カメラの映像を撮影しローカルに保存する方法の二回に分けて説明を行います。アドベントカレンダーで公開される記事になっているため、投稿日現在(2023/12/20)、アクセスできない記事が含まれています。
環境
- Unity 2022.3.6f1
- NRSDK v2.1.0
準備
こちらの記事を参考にNRSDKをプロジェクトにインポートし、NRSDKを使うための設定を行います。
そしてこの記事を参考に、ハンドトラッキングができるように設定します。新しいシーンを作成し、MainCameraを消去しNRInput
とNRCameraRig
をヒエラルキーから追加し、ハンドトラッキングによる入力ができる設定を行います。
ハンドジェスチャー認識時にイベントを呼び出す
まず、ピースのジェスチャーを認識した時にイベントを呼び出す仕組みを作成します。
ハンドジェスチャーに関してはこの記事で言及されています。今回は「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
であるかを返す関数を実装します。
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_TestHandStatesDict
にKeyCode.V
が押されたときにVictory
の手の形になることを登録する必要があります。
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
も存在しないため、同じクラスの下部に以下内容を書き足します。
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
スクリプトをシーン内のオブジェクトにアタッチすることで、ピースのジェスチャーを認識するとイベントを呼び出すことができるようになりました。
おわりに
今回は「【XREAL Light】ピースで写真が撮れるアプリを作る【ハンドジェスチャー編】」というテーマでPanda株式会社 Advent Calendar 2023 14日目を執筆させていただきました。
本記事では、ハンドジェスチャーを認識してイベントを呼び出す方法を紹介しました。
エミュレーター上でのハンドジェスチャーの種類を追加できるようになり、ビルドの手間を減らせることができるようになったと思います。
明日の記事も私、Panda株式会社代表取締役の田貝奈央による「【XREAL Light】ピースで写真が撮れるアプリを作る【写真撮影編】」です。お楽しみに!
Discussion