はじめに
かなりニッチな需要の記事かもしれません!
「Kinect1台で区別された2つの手のひらの位置を追う方法」というのは、
例えば、参加者二人で何かを競わせるような体験を作り出したい場合とかに便利です。
Kinectについての記事ですが、公式の提供が終了してるOpenNIで処理しています。
まず、私が今回載せるコードが必要になった状況説明からします。
- Kinect1台で2人の参加者の手のひらを検出したい
- 二つ分の手のひらの検出はできるものの、左右の人の区別ができない!
- kinectの数は増やせない。
ということが起きました。
1つ目の状況「Kinect1台で2人の参加者の手のひらを検出したい」は、
Kinectからの映像の左半分に参加者一人、右半分に参加者もう一人がいて、
場所は定位置で足は動かさず腕だけを動かすような参加方法でした。
2つ目の状況「二つ分の手のひらの検出はできるものの、左右の人の区別ができない!」は、
手のひらだけでトラッキングしていた(openNIDevice.getTrackedHandを利用)ので、
映像の左端に近い手を左の人、映像の右端に近い人を右の人と処理しどちらの参加者かを特定していたので、
手のひらが交差したりすると逆になっちゃってました。
skeltonと呼ばれる体をトラッキングしちゃえば実装できるかもしれませんが、
無駄に処理を増やしたくなかったので、addUserGeneratorはしませんでした。
ofxOpenNIが何をトラッキングしておくかは、
openNIDeviseのstart前にトラッキングをするものを決めてるっぽい(検証してない。違ったらご指摘ください。)ので、
addUserGeneratorしない分、処理が節約できているはず・・・。
3つ目の状況「kinectの数は増やせない。」は、
増やすと処理が重くなるのと、費用の問題ですね・・・。
どう解決したか
手を挙げてトラッキングし始めた時だけ、
その場所は映像の左半分か右半分かを条件にユーザーの手のひらは左・右側どちらのものか記録するleftHandID・rightHandID変数に
ofxOpenNIHandクラスのgetIDで取得したユニークIDを代入しました。
そうすることで、手が何個かトラッキングしていたらdrawごとに行う、
if(numHands == 1)とif(numHands == 2)内の処理で、
leftHandID・rightHandIDを使い、左・右どちらの手なのかを区別できるようになっています。
これで、手が交差したりしても左の人か右の人か区別してトラッキングできます。
コードは一部抜粋ですが、openniのデフォルトのexampleにあるhandtrackingに追加する形で考えてもらえればいいと思います。
numHands = openNIDevice.getNumTrackedHands();
if(numHands-numHandsLast==1){//トラッキングした手が一つ増えたとき
ofxOpenNIHand & tmpHand = openNIDevice.getTrackedHand(numHands-1);
ofPoint & tmpHandPosition = tmpHand.getPosition();
if(tmpHandPosition.x<ofGetWidth()/2){
leftHandID = tmpHand.getID();
}else{
rightHandID = tmpHand.getID();
}
}
if(numHands-numHandsLast==2){//トラッキングした手が二つ増えたとき 起きにくいけど用意 起きにくいから正常に動いてるか試せてない。
flag1 = true;
ofxOpenNIHand & tmpHand0 = openNIDevice.getTrackedHand(0);
ofPoint & tmpHandPosition0 = tmpHand0.getPosition();
if(tmpHandPosition0.x<ofGetWidth()/2){
leftHandID = tmpHand0.getID();
}else{
rightHandID = tmpHand0.getID();
}
ofxOpenNIHand & tmpHand1 = openNIDevice.getTrackedHand(1);
if(leftHandID == tmpHand0.getID()){
rightHandID = tmpHand1.getID();
}
if(rightHandID == tmpHand0.getID()){
leftHandID = tmpHand0.getID();
}
}
if(numHands == 1){
ofxOpenNIHand & hand0 = openNIDevice.getTrackedHand(0);
handID[0] = hand0.getID();
ofPoint & handPosition0 = hand0.getPosition();
if(hand0.getID() == leftHandID){
handPos[0].x = handPosition0.x;
handPos[0].y = handPosition0.y;
}
if(hand0.getID() == rightHandID){
handPos[1].x = handPosition0.x;
handPos[1].y = handPosition0.y;
}
}
if(numHands == 2){
ofxOpenNIHand & hand0 = openNIDevice.getTrackedHand(0);
handID[0] = hand0.getID();
ofPoint & handPosition0 = hand0.getPosition();
ofxOpenNIHand & hand1 = openNIDevice.getTrackedHand(1);
handID[1] = hand1.getID();
ofPoint & handPosition1 = hand1.getPosition();
if(hand0.getID() == leftHandID){
handPos[0].x = handPosition0.x;
handPos[0].y = handPosition0.y;
}
if(hand0.getID() == rightHandID){
handPos[1].x = handPosition0.x;
handPos[1].y = handPosition0.y;
}
if(hand1.getID() == leftHandID){
handPos[0].x = handPosition1.x;
handPos[0].y = handPosition1.y;
}
if(hand1.getID() == rightHandID){
handPos[1].x = handPosition1.x;
handPos[1].y = handPosition1.y;
}
}
最後に
一例として、ご参考になれば幸いです!
なんかもっとスッキリできる方法があれば教えていただきたいです。