はじめてのKinectプログラミング(IVRC ユース部門勉強会資料)
2013/8/21 @明治大学 総合数理学部 先端メディアサイエンス学科 橋本研究室
IVRCユース部門勉強会で使うサンプルコード達デス。
目次
各種リンク
深度画像、デプスマップの取得
Kinectの目玉、深度画像の表示です。
import SimpleOpenNI.*;
SimpleOpenNI kinect;
void setup() {
size(640, 480); // 画面サイズの設定
kinect = new SimpleOpenNI(this); // 初期化
kinect.enableDepth(); // 深度画像の有効化
}
void draw() {
background(0); // 背景の初期化
kinect.update(); // データの更新
image(kinect.depthImage(), 0, 0); // 描画
}
赤外線画像の取得
赤外線レーザプロジェクタから投影されている見えないドットパターンが見えます。
import SimpleOpenNI.*;
SimpleOpenNI kinect;
void setup() {
size(640, 480); // 画面サイズの設定
kinect = new SimpleOpenNI(this); // 初期化
kinect.enableIR(); // 赤外線画像の有効化
}
void draw() {
background(0); // 背景の初期化
kinect.update(); // データの更新
image(kinect.irImage(), 0, 0); // 描画
}
ユーザマップの取得
ユーザごとに色を割り振って塗りつぶします。
import SimpleOpenNI.*;
SimpleOpenNI kinect;
color[] userColors = { color(255,0,0), color(0,255,0), color(0,0,255),
color(255,255,0), color(255,0,255), color(0,255,255) };
void setup() {
kinect = new SimpleOpenNI(this);
kinect.setMirror(false); // ミラー反転を無効にする
kinect.enableDepth(); // デプス画像を有効にする
kinect.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL); // ユーザトラッキングを有効にする
size(kinect.depthWidth(), kinect.depthHeight());
}
void draw() {
// カメラの更新とデプス画像の描画
kinect.update();
image(kinect.depthImage(), 0, 0);
// ユーザが1人以上いるなら,ユーザマップを取得
int[] userMap = null;
int userCount = kinect.getNumberOfUsers();
if (userCount > 0) {
userMap = kinect.getUsersPixels(SimpleOpenNI.USERS_ALL);
}
// ユーザマップの情報を元に,ユーザがいるピクセルに色を塗る
loadPixels();
for (int y=0; y<kinect.depthHeight(); y++) {
for (int x=0; x<kinect.depthWidth(); x++) {
int index = x + y * kinect.depthWidth();
// ユーザマップを読み,値が0より大きければユーザが居るピクセルだと判定
if ( userMap != null && userMap[index] > 0 ) {
int colorIndex = userMap[index] % userColors.length; // ユーザ色を決定
pixels[index] = userColors[colorIndex]; // ピクセル値をユーザ色にする
}
}
}
updatePixels();
}
人物領域の抽出
ユーザマップを使って人物だけを切り出します。ユーザが検知されないとウィンドウは真っ白なままなので注意!
import SimpleOpenNI.*;
SimpleOpenNI kinect;
void setup() {
size(640, 480);
kinect = new SimpleOpenNI(this);
kinect.enableRGB();
kinect.enableDepth();
kinect.setMirror(true);
kinect.alternativeViewPointDepthToImage();
kinect.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL);
}
void draw() {
background(255);
kinect.update();
int[] userMap = null;
int userCount = kinect.getNumberOfUsers();
if (userCount > 0) {
userMap = kinect.getUsersPixels(SimpleOpenNI.USERS_ALL);
}
loadPixels();
for (int y=0; y<kinect.rgbHeight(); y++){
for (int x=0; x<kinect.rgbWidth(); x++){
int i = x + y * kinect.rgbWidth();
if (userMap != null && userMap[i] > 0)
pixels[i]=kinect.rgbImage().pixels[i];
}
}
updatePixels();
}
距離計測
画面中心の座標のKinectとの距離を表示します。
import SimpleOpenNI.*;
SimpleOpenNI kinect;
void setup() {
size(640, 480); // 画面サイズの設定
kinect = new SimpleOpenNI(this); // 初期化
kinect.enableDepth(); // 深度画像の有効化
textSize(50); // 文字サイズの設定
}
void draw() {
background(0); // 背景の初期化
kinect.update(); // データの更新
image(kinect.depthImage(), 0, 0); // 描画
// 中心の距離を表示
int[] depthMap = kinect.depthMap();
int x = width/2; // 画像中心
int y = height/2; // 画像中心
int index = x + y * width;
int distance = depthMap[index];
fill(255, 0, 0);
ellipse(x, y, 10, 10);
if(distance > 0)
text(distance +" mm", x+10, y-10);
else
text("-- mm", x+10, y-10);
}
距離計測(面)1
Kinectから1m未満のエリアを赤くします。
import SimpleOpenNI.*;
SimpleOpenNI kinect;
void setup() {
size(640, 480); // 画面サイズの設定
kinect = new SimpleOpenNI(this); // 初期化
kinect.enableDepth(); // 深度画像の有効化
}
void draw() {
background(0); // 背景の初期化
kinect.update(); // データの更新
image(kinect.depthImage(), 0, 0); // 描画
// 1000mm以下を赤くする処理
int[] depthMap = kinect.depthMap();
loadPixels();
for (int y=0; y<kinect.depthHeight(); y++){
for (int x=0; x<kinect.depthWidth(); x++){
int d = depthMap[x + y*width];
if (0 < d && d < 1000 ) {
pixels[x + y*width] = color(255, 0, 0); // ピクセル値に赤色を設定
}
}
}
updatePixels();
}
距離計測(面)2
Kinectから1m未満のエリアを、RGBカメラで取得したカラー画像にします。
import SimpleOpenNI.*;
SimpleOpenNI kinect;
void setup() {
size(640, 480); // 画面サイズの設定
kinect = new SimpleOpenNI(this); // 初期化
kinect.enableDepth(); // 深度画像の有効化
kinect.enableRGB(); // カラー画像の有効化
kinect.alternativeViewPointDepthToImage(); // 視点の位置合わせ
}
void draw() {
background(0); // 背景の初期化
kinect.update(); // データの更新
image(kinect.depthImage(), 0, 0); // 描画
// 1000mm未満にカラー画像の色を付ける
int[] depthMap = kinect.depthMap();
PImage rgbImage = kinect.rgbImage();
loadPixels();
for (int y=0; y<kinect.depthHeight(); y++){
for (int x=0; x<kinect.depthWidth(); x++){
int d = depthMap[x + y*width];
if (0 < d && d < 1000 ) {
pixels[x + y*width] = rgbImage.pixels[x + y*width]; // ピクセル値をカラー画像に
}
}
}
updatePixels();
}
距離計測(面)3
距離に応じて色をグラデーションさせます。
import SimpleOpenNI.*;
SimpleOpenNI kinect;
void setup() {
size(640, 480); // 画面サイズの設定
kinect = new SimpleOpenNI(this); // 初期化
kinect.enableDepth(); // 深度画像の有効化
colorMode(HSB, 360, 100, 100); // 色の設定をHSB色空間にする
}
void draw() {
background(0); // 背景の初期化
kinect.update(); // データの更新
// 距離に応じてグラデーション
int[] depthMap = kinect.depthMap();
loadPixels();
for (int y=0; y<kinect.depthHeight(); y++){
for (int x=0; x<kinect.depthWidth(); x++){
int d = depthMap[x + y*width];
pixels[x + y*width] = color(d/3500.0*360, 70, 100);
}
}
updatePixels();
}
骨格の認識とトラッキング
人の骨格をトラッキング!右手を上げると円が表示されます。
import SimpleOpenNI.*; // simple-openni
SimpleOpenNI kinect;
void setup() {
kinect = new SimpleOpenNI(this);
kinect.setMirror(true); // ミラー反転を有効化
kinect.enableDepth(); // 深度画像を有効化
kinect.enableRGB(); // カラー画像を有効化
kinect.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL); // ユーザトラッキングを有効化
kinect.alternativeViewPointDepthToImage(); // 視点の位置合わせ
size(kinect.rgbWidth(), kinect.rgbHeight()); // 画面サイズの設定
}
void draw() {
kinect.update(); // Kinectのデータの更新
image(kinect.rgbImage(), 0, 0); // カラー画像の描画
//ユーザごとに骨格のトラッキングができていたら骨格を描画
for (int userId = 1; userId <= kinect.getNumberOfUsers(); userId++) {
if( kinect.isTrackingSkeleton(userId) ) {
strokeWeight(10); // 線の太さの設定
stroke(255,0,0); // 線の色の設定
drawSkeleton(userId); // 骨格の描画
detectGesture(userId); // ジェスチャ認識
}
}
}
// 新しいユーザを見つけた場合の処理
void onNewUser(int userId) {
kinect.requestCalibrationSkeleton(userId, true); // 骨格キャリブレーションのリクエスト
}
// 骨格キャリブレーション終了時の処理
void onEndCalibration(int userId, boolean successfull) {
if (successfull) {
kinect.startTrackingSkeleton(userId); // 骨格トラッキングの開始
}
}
// 骨格の描画
void drawSkeleton(int userId) {
// 関節間を結ぶ直線を描画
kinect.drawLimb(userId, SimpleOpenNI.SKEL_HEAD, SimpleOpenNI.SKEL_NECK);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_LEFT_SHOULDER);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_LEFT_ELBOW);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_ELBOW, SimpleOpenNI.SKEL_LEFT_HAND);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_RIGHT_SHOULDER);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_RIGHT_ELBOW);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_ELBOW, SimpleOpenNI.SKEL_RIGHT_HAND);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_TORSO);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_TORSO);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_LEFT_HIP);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_HIP, SimpleOpenNI.SKEL_LEFT_KNEE);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_KNEE, SimpleOpenNI.SKEL_LEFT_FOOT);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_RIGHT_HIP);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_HIP, SimpleOpenNI.SKEL_RIGHT_KNEE);
kinect.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_KNEE, SimpleOpenNI.SKEL_RIGHT_FOOT);
}
// ジェスチャ認識
void detectGesture(int userId) {
// 右手の3次元位置を取得する
PVector hand3d = new PVector(); // 3次元位置
kinect.getJointPositionSkeleton(userId, SimpleOpenNI.SKEL_RIGHT_HAND, hand3d);
// 右手の2次元位置を取得する
PVector hand2d = new PVector(); // 2次元位置
kinect.convertRealWorldToProjective(hand3d, hand2d);
// 右肩の3次元位置を取得する
PVector shoulder3d = new PVector();
kinect.getJointPositionSkeleton(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, shoulder3d);
// 右手が右肩よりも高い位置にあるとき,手の2次元位置に円を表示する
if ( hand3d.y - shoulder3d.y > 0 ) {
ellipse( hand2d.x, hand2d.y, 50, 50 );
}
}