こんにちは!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をつなげれば、使えます!
