こんにちは!B4の大山です。

 

 

先週は、RTコンポーネントを使ってkinectを動かしました!!

具体的には、kinectで「バンザイ」と「変身」のポーズを認識し、データポートから文字列で”banzai”,”henshin”と出力するコンポーネントです。

 

kinectでは、3D深度センサのデータ,カラーカメラ,アレイマイクのデータが得られます。

 

そのひとつとして、今回利用するのが、3D深度センサから得られるスケルトンデータです。スケルトンデータとは、20ケ所の関節部分を三次元座標値として返してくれたものです。

whole+skeleton+01

それを利用することでジェスチャーを認識するプログラムが作れるのですね。

 

 

 

 

 

KinectMotionRecognizerコンポーネントの作成

 

【概要】

Kinectで、「バンザイ」と「変身」のポーズを判定し、データポートから文字列で”banzai”,”henshin”と出力するコンポーネント。

「バンザイ」= 両手が頭より上にある

「変身」= 右手が頭より右にある

 

 

 

 

【step 1】RTCBuilderで、スケルトンコードを作る

基本は同じです。

データポートは、

インポート:(ポート名)skelton ,(データ型)Kinect::NuiSkeltonFrame

アウトポート:(ポート名) motion , (データ型)RTC::TimedString

point

ここで、問題発生!

Kinect::~というデータ型は、最初は選択肢にありません。

→データ型は「idlファイル」で定義している。

新しいデータ型を設定したい場合は、

eclipsで、「ウィンドウ>設定>RTCBuilder>新規>idlを追加」

※idlを自分で定義する場合は、最後の4行をコメントアウトする必要があるから注意!

 

今回は、kinectのidlファイルを設定します。

 

詳しくは、ここを見る→ http://ysuga.net/?p=213

 

 

【step 2】CMakeで、ソリューションを生成

(いつもどおりです。)

【step 3】VisualStadioで中身の編集

 

 

 

idlファイルを見ると、このように、データ型が定義されています。

module KINECT {
enum NUI_SKELETON_TRACKING_STATE {
NUI_SKELETON_NOT_TRACKED,
NUI_SKELETON_POSITION_ONLY,
NUI_SKELETON_TRACKED
};

enum NUI_SKELETON_POSITION_TRACKING_STATE {
NUI_SKELETON_POSITION_NOT_TRACKED,
NUI_SKELETON_POSITION_INFERRED,
NUI_SKELETON_POSITION_TRACKED
};

enum NUI_SKELETON_POSITION_INDEX { NUI_SKELETON_POSITION_HIP_CENTER, NUI_SKELETON_POSITION_SPINE, NUI_SKELETON_POSITION_SHOULDER_CENTER, NUI_SKELETON_POSITION_HEAD, NUI_SKELETON_POSITION_SHOULDER_LEFT,

NUI_SKELETON_POSITION_ELBOW_LEFT, NUI_SKELETON_POSITION_WRIST_LEFT, NUI_SKELETON_POSITION_HAND_LEFT, NUI_SKELETON_POSITION_SHOULDER_RIGHT, NUI_SKELETON_POSITION_ELBOW_RIGHT,

NUI_SKELETON_POSITION_WRIST_RIGHT, NUI_SKELETON_POSITION_HAND_RIGHT, NUI_SKELETON_POSITION_HIP_LEFT, NUI_SKELETON_POSITION_KNEE_LEFT, NUI_SKELETON_POSITION_ANKLE_LEFT,

NUI_SKELETON_POSITION_FOOT_LEFT, NUI_SKELETON_POSITION_HIP_RIGHT, NUI_SKELETON_POSITION_KNEE_RIGHT, NUI_SKELETON_POSITION_ANKLE_RIGHT, NUI_SKELETON_POSITION_FOOT_RIGHT,

NUI_SKELETON_POSITION_COUNT };

struct Vector4 { float v[4]; };

struct NuiSkeletonData { NUI_SKELETON_TRACKING_STATE trackingState; long trackingID; long enrollmentIndex; long userIndex; Vector4 position; Vector4 skeletonPositions[20]; NUI_SKELETON_POSITION_TRACKING_STATE eSkeletonPositionTrackingState[20]; long qualityFlags; };

struct NuiSkeletonFrame { long long liTimeStamp; long dwFrameNumber; long dwFlags; Vector4 vFloorClipPlane; Vector4 vNormalToGravity; NuiSkeletonData SkeletonData[ 6 ]; };

struct DepthImage { long long timestamp; long width; long height; sequence<unsigned short> bits; double horizontalFieldOfView; double verticalFieldOfView; };

struct SoundSourceLocation { double angle; double confidence; };

};

[20]というのが、20個の配列。

0がNUI_SKELETON_POSITION_HIP_CENTER、

1がNUI_SKELETON_POSITION_SPINE・・・

という感じで定義されていて、

ひとつひとつはvector4だから、四つの行列(v[0]がx軸方向, v[1]はy軸, v[2]はz軸, v[3]はw軸(実際は使われない))でできている。

 

今回は、m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HEAD].v[0]

という感じで使用します。

 

 

 

以下がonExecuten内のコード。

 

RTC::ReturnCode_t KinectMotionRecognizer::onExecute(RTC::UniqueId ec_id)

{

if(m_skeletonIn.isNew()) {

m_skeletonIn.read();

//std::cout << "Kinect Skeleton Data Arrived.\n";

if(m_Mode == RECOGNITION_MODE){

for(int i = 0;i < 6;i++) {

if(m_skeleton.SkeletonData[i].trackingState == KINECT::NUI_SKELETON_TRACKED) {

float head_x = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HEAD].v[0];

float head_y = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HEAD].v[1];

float head_z = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HEAD].v[2];

float left_x = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HAND_LEFT].v[0];

float left_y = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HAND_LEFT].v[1];

float left_z = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HAND_LEFT].v[2];

float right_x = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HAND_RIGHT].v[0];

float right_y = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HAND_RIGHT].v[1];

float right_z = m_skeleton.SkeletonData[i].skeletonPositions[KINECT::NUI_SKELETON_POSITION_HAND_RIGHT].v[2];

if(left_z>head_z && right_z>head_z){

std::cout << "BAN\(^o^)/ZAI" << std::endl;

m_motion.data= "banzai";

m_motionOut.write();

m_StartTime = coil::gettimeofday();

m_Mode = SPEACH_MODE;

}else if(right_x<head_x){

std::cout << "HEN\(\◇ ̄ )SHIN" << std::endl;

m_motion.data = "henshin";

m_motionOut.write();

m_StartTime = coil::gettimeofday();

m_Mode = SPEACH_MODE;

}else{

m_motion.data = "なし";

std::cout << "nothing" << std::endl;

m_motionOut.write();

m_StartTime = coil::gettimeofday();

m_Mode = SPEACH_MODE;

}

}

}

}else if(m_Mode == SPEACH_MODE){

double duration = coil::gettimeofday() - m_StartTime;

if(duration  > 2){

m_Mode = RECOGNITION_MODE;

}

}

}

  return RTC::RTC_OK;

}

 

Point モードを分ける

int m_Modeで条件わけ

 

※intだから、実際は変数の中身は数値だけど、わかりにくいので文字で定義したい

→HEADER FILESで定義

Header files > KinectMotionRecognizer.h 内で

「#define 代わりの文字 実際の数値」

 

 

Point 時間をとる

「何秒間、modeXをやる」という場合、時間をとる。

m_StartTime = coil::gettimeofday();

double duration = coil::gettimeofday() – m_StartTime;

 

 

 

コンポーネント完成!!

 

【step4】RTSystemEditorで、使ってみる!

kinect4win(GithubのSugarSweetRoboticsからダウンロードする)と、

今作ったKinectMotionRecognizerをつなげれば、使えます!

 

 

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です