@uents blog

Code wins arguments.

ProcessingでKinect - スケルトンをトラッキングしてジョイント位置を描画する

前回の続き
ケルトントラッキングを試してみる。

ソースコード

ちょっと汚いコードだけど…

import processing.core.*;
import SimpleOpenNI.*;
import java.util.ArrayList;

@SuppressWarnings("serial")
public class SkeltonTracker extends PApplet {
	private class Joint {
		int type;
		String name;
		Joint(int type, String name) {
			this.type = type;
			this.name = name;
		}
	}
	private ArrayList<Joint> joints;
	private SimpleOpenNI context;
	
	public void setup() {
		// initialize openni properties
		context = new SimpleOpenNI(this);
		context.setMirror(false);
		
		if (context.enableRGB() == false) {
			println("cannot enable rgb map!!");
			exit();
		}
		if (context.enableDepth() == false) {
			println("cannot enable depth map!!");
			exit();
		}
		if (context.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL) == false) {
			println("cannot enable user skelton!!");
			exit();
		}
		
		// align depth data to image data
		context.alternativeViewPointDepthToImage();
		
		size(context.depthWidth() + 10 + context.rgbWidth(), context.depthHeight());
		background(200, 0, 0);
		
		// initialize joint list
		initJointList();
	}
	
	public void draw() {
		// カメラ情報を更新
		context.update();
		
		// Depth映像を描画
		image(context.depthImage(), 0, 0);
		
		// Depth映像にジョイント位置を重畳
		int[] users = context.getUsers();
		for (int user: users) {
			if (context.isTrackingSkeleton(user)) {
				for (Joint joint: joints) {
					drawJointPoint(user, joint.type, joint.name);
				}
			}
		}
		
		// Camera映像を描画
		image(context.rgbImage(),context.depthWidth() + 10,0);
	}
	
	// ジョイント位置を描画
	private void drawJointPoint(int userId, int jointType, String name) {
		PVector worldPosition = new PVector();
		PVector projPosition = new PVector();
		context.getJointPositionSkeleton(userId, jointType, worldPosition);
		context.convertRealWorldToProjective(worldPosition, projPosition);
		
		if (userId == 1) fill(255, 0, 0);
		else if (userId == 2) fill(0, 255, 0);
		else fill(0, 0, 255);
		ellipse(projPosition.x, projPosition.y, 10, 10);
		text(name, projPosition.x+10, projPosition.y+10);
	}

	// ジョイントリストを初期化
	private void initJointList() {
		joints = new ArrayList<Joint>();
		joints.add(new Joint(SimpleOpenNI.SKEL_HEAD, "HEAD"));
		joints.add(new Joint(SimpleOpenNI.SKEL_NECK, "NECK"));	
		joints.add(new Joint(SimpleOpenNI.SKEL_TORSO, "TORSO"));
		joints.add(new Joint(SimpleOpenNI.SKEL_LEFT_ELBOW, "LEFT ELBOW"));					
		joints.add(new Joint(SimpleOpenNI.SKEL_RIGHT_ELBOW, "RIGHT ELBOW"));
		joints.add(new Joint(SimpleOpenNI.SKEL_LEFT_HIP, "LEFT HIP"));
		joints.add(new Joint(SimpleOpenNI.SKEL_RIGHT_HIP, "RIGHT HIP"));
		joints.add(new Joint(SimpleOpenNI.SKEL_LEFT_KNEE, "LEFT KNEE"));
		joints.add(new Joint(SimpleOpenNI.SKEL_RIGHT_KNEE, "RIGHT KNEE"));
		joints.add(new Joint(SimpleOpenNI.SKEL_LEFT_HAND, "LEFT HAND"));
		joints.add(new Joint(SimpleOpenNI.SKEL_RIGHT_HAND, "RIGHT HAND"));
		joints.add(new Joint(SimpleOpenNI.SKEL_LEFT_SHOULDER, "LEFT SHOULDER"));
		joints.add(new Joint(SimpleOpenNI.SKEL_RIGHT_SHOULDER, "RIGHT SHOULDER"));
		joints.add(new Joint(SimpleOpenNI.SKEL_LEFT_FOOT, "LEFT FOOT"));
		joints.add(new Joint(SimpleOpenNI.SKEL_RIGHT_FOOT, "RIGHT FOOT"));
	}
	
	// 新たにユーザーを検出した時のコールバック 
	public void onNewUser(int userId) {
		println("onNewUser - userId:" + userId);
		
		// キャリブレーションを開始する
		// (NITE 1.5からキャリブレーションポーズは不要)
		context.requestCalibrationSkeleton(userId, true);
		//context.startPoseDetection("Psi", userId);
	}
	// ユーザーの消失を検出した時のコールバック
	public void onLostUser(int userId) {
		println("onLostUser - userId:" + userId);
	}
	// キャリブレーションを開始した時のコールバック
	public void onStartCalibration(int userId) {
		println("onStartCalibration - userId:" + userId);
	}
	// キャリブレーションが終了した時のコールバック
	public void onEndCalibration(int userId, boolean bSuccess) {
		println("onEndCalibration - userId:" + userId);
		
		if (bSuccess) {
			// トラッキングを開始する
			println(" => success to calibrate");
			context.startTrackingSkeleton(userId);
		} else {
			// 失敗。ポーズ検出からやり直す
			println(" => faied to calibrate");
			context.startPoseDetection("Psi", userId);
		}
	}
	
	/*
	// ポーズを検出した時のコールバック
	public void onStartPose(String pose, int userId) {
		println("onStartPose - userId:" + userId);

		// ポーズ検出を中止してキャリブレーションを開始
		context.stopPoseDetection(userId);
		context.requestCalibrationSkeleton(userId, true);
	}
	// ポーズを消失した時のコールバック
	public void onEndPose(String pose, int userId) {
		println("onEndPose - userId:" + userId);
	}
	*/
}

実行結果

ハマりポイント

  • context.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL)を呼んだ状態でcontext.rgbImage()を取得するには、context.enableRGB()だけでなくcontext.enableDepth()も必要?
    • よくわからないけど、そうしないと動かなかった
  • onNewUser()からcontext.startPoseDetection()しなくても、context.requestCalibrationSkeleton(userId, true)を呼べばよい