C#
Unity
LeapMotion

LeapMotion+Unityでグー・チョキ・パーを認識する


はじめに

VRMの流行の兆しが見えたので推しの子とじゃんけんが出来るソフトでも作っておこうかな、と思ったのでLeapMotionでじゃんけんの手を検知する仕組みを作りました。知見共有。



制作

新しい方のLeapMotionSDKとUnityの知見は少な目な気がします…もしかしてもうLeapMotion界隈下火だったりします…?


LeapMotionSDKの準備

まずLeapMotion公式からUnity向けSDKをダウンロードしておきます。中にあったUnityPackageをProjectにインポートします。


Unity側の準備

Assets/LeapMotion/Core/Examples/Capsule Hands(Desktop)からLeapMotionControllerとHandModelsをコピペして自分のシーンに貼り付けます。コレさえあればとりあえず動くはずなので、試しに実行してみて手がトラッキングできればとりあえず成功です。


手の形を認識する


HandRSP.cs

using System;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Leap;
using System.Linq;
public class HandRSP : MonoBehaviour {
private Controller controller;
private Finger[] fingers;
private bool[] isGripFingers;
public enum RSP
{
Rock, Scissors, Paper
};
public RSP rsp;
// Use this for initialization
void Start () {
controller = new Controller();
fingers = new Finger[5];
isGripFingers = new bool[5];
}

// Update is called once per frame
void Update () {
Frame frame = controller.Frame();
if(frame.Hands.Count != 0)
{
List<Hand> hand = frame.Hands;
fingers = hand[0].Fingers.ToArray();
isGripFingers = Array.ConvertAll(fingers, new Converter<Finger, bool>(i => i.IsExtended));
Debug.Log(isGripFingers[0]+","+ isGripFingers[1] + "," + isGripFingers[2] + "," + isGripFingers[3] + "," + isGripFingers[4]);
int extendedFingerCount = isGripFingers.Count(n => n == true);
if(extendedFingerCount == 0)
{
rsp = RSP.Rock;
}
else if(extendedFingerCount < 4)
{
rsp = RSP.Scissors;

}
else
{
rsp = RSP.Paper;

}

}
}
}


コレをシーン内の好きなオブジェクトにアタッチすればrspにグーチョキパーの認識結果が表示されます。


解説


usingステートメント

LeapMotionの機能を利用するにはusing Leap;のステートメントを利用します。


Controller

LeapMotionの制御はControllerで行い、これがメインのインターフェースとなります。


Frame

Controller.Frameには手の挙動の情報が含まれています。


Hand

Hand型には手の位置、角度や各指の情報が存在しています。Controller.Handsで認識されている全ての手についてのHandを返します。認識範囲内に一つも手がなければ当然要素数0になるので例外処理をしっかりしましょう。


Finger

各手についている指の情報を保有する型です。位置、指し示す向き、握っているか否かなどの情報を取得することができます。Hand.Fingersですべての指のFingerを取得することができます。また、各Fingerに対してFinger.IsExtendで指の開きを検知することができます。指が開いているときTrue、指が曲がっているときがFalseです。上記の実装例ではisGripFingers = Array.ConvertAll(fingers, new Converter<Finger, bool>(i => i.IsExtended));で全ての指の曲がり方のブール値を取得したのち、int extendedFingerCount = isGripFingers.Count(n => n == true);(LinQを利用しています)で曲がっている指の本数を取得しています。


RSP

曲がった指の本数を基準にグーチョキパーのいずれの手が出されているか判断します。RSPは手の種類をまとめたEnumで、今回は曲がった指の本数が5本でグー、4~2本でチョキ、1本以下でパーとしています。

キャプチャ164.PNG

キャプチャ165.PNG

キャプチャ163.PNG


問題点

取り敢えず雑に認識させることができましたが、チョキとグーの認識が結構厳しく、ちゃんと手を下に向けないとうまく認識してくれなかったりします。これについては部屋が明るいのとか僕の手がオタク特有のまっしろハンドなのとかいろいろ原因がありそうです。


解決のアイデア

まぁ別にガチじゃんけんするわけでもないしコンピュータ側の出す手に合わせてユーザーを勝たせる側に強めの認識補正をかけてあげればいいんじゃないでしょうか。勝てる手を出したのに認識ミスで負けるってのはプレイフィール最悪なのでそれだけは避ける方向で行くといいと思います。


最後に

ちょうどVroidHubSDKも頂けたのでこれを利用して好みのモデルとじゃんけんが出来るシステムを組んでいきたいです。やるぞ~~