いった技術分野のお役立ち情報を紹介しています。はじめに以前、当社のWebマガジンにて、「LMCを用いて手の関節の3次元座標を標準出力する」方法をまとめました。実際は関節の3次元座標情報以外にも、SDKを用いて様々な手の情報が取得可能です。これら情報の取得方法がSDK付属のサンプルプログラムに含まれておらず、Ultraleap社のAPI仕様書を読み調べる必要がありました。今回、様々な手の情報の取得方法をWebマガジンとしてまとめましたので、ご参照下さい。5.7.2のSDK(以下SDK5.7.2と記載します)をWindowsPCにインストール済みとして説明しております。入る可能性がある旨、ご了承ください。Version5.7.2について」でまとめていますのでご参考下さい。IR170(以下SIR170と記載します)、3Di等のこと)の設置・設定に関してはDeskTopモード、つまり下記写真のようにステレオカメラを卓上に置き、NIRレンズが上を向いた状態としています。サンプルプログラムの記述例SDK5.7.2のサンプルプログラム「CallBackSample.c」の27行目~41行目に、OnFrame関数という手の認識結果を処理する関数が存在します。この箇所をいろいろと修正することで、様々な手の情報が取得可能となります。SDK5.7.2のサンプルプログラムは、初期設定のままインストールした場合、下記フォルダに含まれています。Files\Ultraleap\LeapSDK\samplesOnFrame関数の内容をサンプルプログラム中にコメントを追記して説明します。下記サンプルプログラム中の「//★」の箇所が追記したコメントです。※xyz座標の定義は後述}}上記サンプルプログラムのhand変数(LEAP_HAND構造体)の中に、様々な手の情報が含まれています。LEAP_HAND構造体の構成LEAP_HAND構造体の中に様々な手の情報が含まれていますが、LEAP_HAND構造体の構成を理解されるとプログラムが書きやすいと考えております。ここでは、LEAP_HAND構造体の構成について、説明します。LEAP_HAND構造体は手の平から手首、そして肘までの範囲の情報を取り扱っています。LEAP_HAND構造体はarmおよびpalmをメンバ変数として持っています。armはLEAP_BONE構造体、palmはLEAP_PALM構造体を用いて宣言しています。LEAP_PALM構造体は、gidits配列をメンバ変数として持っています。gidits配列はLEAP_DIGIT構造体を用いて宣言しています。digits配列は共有体として別の変数名を持っています。gidits配列と添え字の関係および別変数名の関係は以下の通りです。()内は別変数名を示しています。本Webマガジンにてdigits[0-4]と記載した場合、digits[0]からdigits[4]のいずれかであることを示しています。LEAP_DIGIT構造体は、bones配列をメンバ変数として持っています。bones配列はLEAP_HAND構造体のarm変数と同じく、LEAP_BONE構造体を用いて宣言しています。bones配列は共有体として別の変数名を持っています。bones配列と添え字の関係および別変数名の関係は以下の通りです。()内は別変数名を示しています。本Webマガジンにてboines[0-3]と記載した場合、bones[0]からbones[3]のいずれかであることを示しています。metacarpal)のデータは無効となっています。intermediate)がありませんが、データ処理の簡便さから、上記のような構成としています。後述しますが、それぞれの構造体に含まれるその他のメンバ変数を参照することにより、各種手の情報が取得可能です。ステレオカメラのxyz座標LEAP_PALM構造体やLEAP_BONE構造体にはxyz座標のデータが含まれています。このxyz座標を用いて各種手の関節がどこにあるかを知ることができます。xyz座標の原点は、Ultraleap社のステレオカメラモジュールの左右カメラ間の中心です。LMCおよびSIR170のxyz座標の原点および座標軸を以下の図に示します。三次元座標系は右手系(ワールド座標系)を使用しています。y軸に関してはプラス値のみ、マイナス値はもたない仕様になっています。xyz座標の単位はmmです。hand->type」で、左手または右手の情報を取得できます。取得した値がeLaeapHandType_Leftであれば左手、eLaeapHandType_Rightであれば右手です。Panelと記載します)の表示例を以下に示します。Panelの表示例を以下に示します。Panelは、旧VersionのSDKではVisualizerという名前でした。操作方法やレイアウトも変わっていますのでご注意下さい。プログラムの記述例を以下に示します。「hand->grab_angle」で、手の平に対する指の平均角度を取得できます。値はラジアンで、0で水平、πでGrab(グー)の状態を示します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。「hand->grab_strength」で、Grab(グー)の状態を正規化した推定値を取得できます。この値は0.0~1.0の範囲であり、0.0で「Grabではない」、1.0で「Grabである」を意味します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。「hand_->pinch_strength」で、Pinch(摘まむ)状態を正規化し推定理を取得できます。この値は0.0~1.0の範囲であり、0.0で「Pinchではない」、1.0で「Pinchである」を意味します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。「hand->pinch_distance」で、親指の先と人差し指の先の距離を取得できます。Panelの表示例を以下に示します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。以下、サンプルプログラム中のarm変数(LEAP_BONE構造体)で取得可能な情報に関してまとめます。「hand->arm.prev_join」で、肘の座標を取得できます。x座標、y座標、z座標それぞれは、以下の記述で取得できます。Panelの表示例を以下に示します。Panelの表示例を以下に示します。Panel上では肘に2つのxyz座標(黄色い丸)が表示されていますが、実際はxyz座標は1点のみ、後述する腕の幅と回転を用いて2点の表示に変換しています(視覚的に腕の向きや回転分かりやすくするため)。プログラムの記述例を以下に示します。「hand->arm.next_join」で、手首の座標を取得できます。x座標、y座標、z座標それぞれは、以下の記述で取得できます。Panelの表示例を以下に示します。Panelの表示例を以下に示します。Panel上では手首に2つのxyz座標(黄色い丸)が表示されていますが、前記した理由と同じです。プログラムの記述例を以下に示します。「hand->arm.width」で、腕の平均幅を取得できます。Panelの表示例を以下に示します。Panelの表示例を以下に示します。上記2つの図のように、腕がどのような位置・向きにあっても似た値になっています。プログラムの記述例を以下に示します。hand->arm.width);}・腕の回転(クォータニオン)「hand->arm.rotation」で、腕の回転(クォータニオン)を取得できます。xyzwで表記します。※クォータニオンについてはInternet上でいろいろと記載があるので、検索して調べて下さい。x,y,z,wそれぞれは、以下の記述で取得できます。Panelの表示例を以下に示します。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。以下、サンプルプログラム中のpalm変数(LEAP_PALM構造体)で取得可能な情報に関してまとめます。「hand->palm.position」で、手の平の中心座標を取得できます。x座標、y座標、z座標それぞれは、以下の記述で取得できます。Panelの表示例を以下に示します。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。「hand->palm.verocity」で、手の平の移動速度を取得できます。単位はmm/secで、xyz座標毎に取得可能です。x座標方向、y座標方向、z座標方向それぞれの移動速度は、以下の記述で取得できます。Panelの表示例を以下に示します。この図は手の平をz軸方向手前から奥に移動させた後なので、z座標方向の移動速度がマイナス値で大きな値になっています。Panelの表示例を以下に示します。この図は手の平をx軸方向左から右に移動後なのでx座標方向の移動速度がプラス値で大きな値になっています。プログラムの記述例を以下に示します。hand->palm.velocity.z);}・手の平のへの法線ベクトル「hand->palm.normal」で、手の平(平面)への法線ベクトルを取得できます。法線ベクトルのxyzの各成分として取得できます。xyzそれぞれの係数は、以下の記述で取得できます。Panelの表示例を以下に示します。この図は手の平を下に向けているので、y係数が-1.0に近い値になっています。Panelの表示例を以下に示します。この図は手の平を上に向けているので、y係数が+1.0に近い値になっています。各xyz係数と手の平(または手の甲)の向きの関係は、以下の通りです。x係数が-1.0に近い値:手の平が左向き(手の甲が右向き)x係数が+1.0に近い値:手の平が右向き(手の甲が左向き)y係数が-1.0に近い値:手の平が下向き(手の甲が上向き)y係数が+1.0に近い値:手の平が上向き(手の甲が下向き)z係数が-1.0に近い値:手の平が奥向き(手の甲が手前向き)z係数が+1.0に近い値:手の平が手前向き(手の甲が奥向き)プログラムの記述例を以下に示します。「hand->palm.width」で、手の平の平均幅を取得できます。Panelの表示例を以下に示します。Panelの表示例を以下に示します。上記2つの図のように、手の平がどのような位置・向きにあっても似た値になっています。プログラムの記述例を以下に示します。hand->arm.width);}・手の平→指の単位方向ベクトル「hand->palm.direction」で、手の平から指に向かう単位方向ベクトルを取得できます。単位方向ベクトルのxyzの各成分として取得できます。xyzそれぞれの成分は、以下の記述で取得できます。Panelの表示例を以下に示します。この図は手の平から指先の方向が手前から奥の方向なので、x成分が0.0に近い値、z成分が-1.0になっています。Panelの表示例を以下に示します。この図は手の平から指先の方向が右から左の方向なので、x成分が-1.0に近い値、z成分が0.0に近い値になっています。各xyz成分と手の平から指の方向の関係は、以下の通りです。x成分が-1.0に近い値:手の平から指の方向が右から左x成分が+1.0に近い値:手の平から指の方向が左から右y成分が-1.0に近い値:手の平から指の方向が上から下y成分が+1.0に近い値:手の平から指の方向が下から上z成分が-1.0に近い値:手の平から指の方向が手前から奥z成分が+1.0に近い値:手の平から指の方向が奥から手前プログラムの記述例を以下に示します。hand->palm.direction.z);}・手の平の方向(クォータニオン)「hand->palm.orientation」で、手の平の方向(クォータニオン)を取得できます。xyzwで表記します。x,y,z,wそれぞれは、以下の記述で取得できます。Panelの表示例を以下に示します。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。digitsで取得可能な情報digits配列(LEAP_DIGIT構造体)は下記のような記述を追加することで、取得できます。//★以下、指毎の処理}以下、上記プログラム中のfinger変数(LEAP_DIGITS構造体)で取得可能な情報に関してまとめます。「hand->digits[0-4].bones[0-3].next_joint」で、各指の関節の座標を取得できます。bones配列はLEAP_BONE構造体を使用しています(サンプルプログラム中のarm変数と同じ構造体)。x座標、y座標、z座標それぞれは、以下の記述で取得できます。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。「hand->digits[0-4].isExtended」で、各指の伸ばした状態の判定結果を取得できます。0で偽(縮んだ状態)、1で真(伸ばした状態)を意味します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。」で、指の平均幅を取得できます。各指のbones[3].width~bones[0].widthはすべて同じ値となっています。Panelの表示例を以下に示します。Panelの表示例を以下に示します。上記2つの図のように、指がどのような位置・向きにあっても似た値になっています。プログラムの記述例を以下に示します。bone.width);}}・指の回転(クォータニオン)「hand->digits[0-4].bones[0-3].rotation」で、腕の回転(クォータニオン)を取得できます。xyzwで表記します。x,y,z,wそれぞれは、以下の記述で取得できます。Panelの表示例を以下に示します。プログラムの記述例を以下に示します。おわりに今までに説明した各種手の情報を取得する方法を1つにまとめたプログラムを以下に記載します。SDK5.7.2のサンプルプログラム「CallBackSample.c」のOnFrame関数を下記のプログラムと入れ替えば動作します。SDKサンプルプログラムのbuild」を参照ください。SDKでの取得可能な情報についてにご紹介しました。