はじめての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 ); } }