こんにちは!B4の大山です。
先週は、RTコンポーネントを使ってkinectを動かしました!!
具体的には、kinectで「バンザイ」と「変身」のポーズを認識し、データポートから文字列で”banzai”,”henshin”と出力するコンポーネントです。
kinectでは、3D深度センサのデータ,カラーカメラ,アレイマイクのデータが得られます。
そのひとつとして、今回利用するのが、3D深度センサから得られるスケルトンデータです。スケルトンデータとは、20ケ所の関節部分を三次元座標値として返してくれたものです。
それを利用することでジェスチャーを認識するプログラムが作れるのですね。
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をつなげれば、使えます!