Created
February 19, 2012 07:12
-
-
Save tatsuro-ueda/1862385 to your computer and use it in GitHub Desktop.
_120219_FallingAndUser.pde
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static final int SLOWNESS = 4; | |
static final int FALLING_RECTANGLE_WIDTH = 150; | |
static final int FALLING_RECTANGLE_WEIGHT = 20; | |
static final int FALLING_RECTANGLE_DEPTH = 40; | |
import SimpleOpenNI.*; | |
SimpleOpenNI context; | |
PImage maskImg; | |
PImage maskedImg; | |
FallingRectangle[] fall = new FallingRectangle[50]; | |
HumanRectangle hRct = new HumanRectangle(); | |
int num; | |
// ----- | |
// FallingRectangle | |
// ----- | |
class FallingRectangle { | |
int x; | |
int y; | |
int width = FALLING_RECTANGLE_WIDTH; | |
int weight = FALLING_RECTANGLE_WEIGHT; | |
color clr; | |
String clrName; | |
int hitCounter = 0; | |
boolean isFlyingRight; | |
boolean isFallingAroundYou = false; | |
int getCounter = 0; | |
FallingRectangle(int oldX) { | |
y = 0; | |
// xを決める | |
int newX; | |
do { | |
newX = oldX + (int)random(200) - 100; | |
// println("newX: " + newX); // for debug | |
} while ( newX < 0 | 440 < newX | abs(newX - oldX) < 50); | |
x = newX; | |
switch((int)random(3)) { | |
case 0: | |
clr = color(255, 0, 0); | |
clrName = "red"; | |
break; | |
case 1: | |
clr = color(0, 255, 0); | |
clrName = "green"; | |
break; | |
case 2: | |
clr = color(0, 0, 255); | |
clrName = "blue"; | |
break; | |
case 3: | |
clr = color(0, 0, 255); | |
clrName = "blue"; | |
break; | |
} | |
} | |
void update(HumanRectangle hRct) { | |
//println("hitCounter= " + hitCounter + ",x= " + x + ",y= " + y); | |
if (hitCounter > SLOWNESS * 2) | |
{ // delete fall | |
y = height + 100; | |
if (isFlyingRight) x -= SLOWNESS * 10 * SLOWNESS * 2; // xを戻す | |
else x += SLOWNESS * 10 * SLOWNESS * 2; // xを戻す | |
} | |
else if (hitCounter > 0) | |
{ // fall flies away | |
if (isFlyingRight) x += SLOWNESS * 10; | |
else x -= SLOWNESS * 10; | |
hitCounter ++; | |
} | |
else if (hRct.y <= y & y <= height) | |
{ // y軸は範囲内で、かつ | |
if ( | |
// fallがhRctの右側に引っかかっている | |
hRct.x <= x & x <= hRct.x + hRct.width | |
) | |
{ | |
if (isFallingAroundYou) { // 内側から体が押した場合 | |
isFlyingRight = false; | |
isFallingAroundYou = false; | |
} | |
else {isFlyingRight = true;} // 外側から体が押した場合 | |
hitCounter = 1; // 横へ飛び始める | |
} else if ( | |
// fallがhRctの左側に引っかかっている | |
hRct.x <= x + this.width & x + this.width <= hRct.x + hRct.width | |
) | |
{ | |
if (isFallingAroundYou) { // 内側から体が押した場合 | |
isFlyingRight = true; | |
isFallingAroundYou = false; | |
} | |
else {isFlyingRight = false;} // 外側から体が押した場合 | |
hitCounter = 1; // 横へ飛び始める | |
} else if ( | |
// 輪の中にうまく入った場合 | |
x <= hRct.x & hRct.x + hRct.width <= x + this.width | |
) | |
{ | |
isFallingAroundYou = true; | |
y += SLOWNESS * 4; // x is OK | |
} | |
} | |
else | |
{ | |
y += SLOWNESS * 4; // x is OK | |
} | |
} | |
void drawBack() { | |
// 後ろ側の線分を描く | |
stroke(clr); | |
strokeWeight(weight); | |
line(x, y, x + FALLING_RECTANGLE_DEPTH, y - FALLING_RECTANGLE_DEPTH); // 「/」 | |
line(x + FALLING_RECTANGLE_DEPTH, y - FALLING_RECTANGLE_DEPTH, | |
x + width - FALLING_RECTANGLE_DEPTH, y - FALLING_RECTANGLE_DEPTH); // 「―」 | |
line(x + width - FALLING_RECTANGLE_DEPTH, y - FALLING_RECTANGLE_DEPTH, | |
x + width, y); // 「\」 | |
} | |
void drawForward() { | |
stroke(clr); | |
strokeWeight(weight); | |
line(x, y, x + width, y); | |
} | |
void drawScoringVE() { | |
if ( getCounter < SLOWNESS * 2 ) { | |
weight += SLOWNESS * 50; | |
getCounter++; | |
y = height; | |
} else { | |
isFallingAroundYou = false; | |
getCounter = 0; | |
y = height + 1; | |
println("You get " + clrName + " !"); | |
} | |
} | |
} | |
class HumanRectangle { | |
int x; | |
int y; | |
int width; | |
void update() { | |
PVector jointLS = new PVector(); | |
context.getJointPositionSkeleton(1, SimpleOpenNI.SKEL_LEFT_SHOULDER,jointLS); | |
PVector convertedJointLS = new PVector(); | |
context.convertRealWorldToProjective(jointLS, convertedJointLS); | |
x = (int)convertedJointLS.x; | |
y = (int)convertedJointLS.y; | |
PVector jointRS = new PVector(); | |
context.getJointPositionSkeleton(1, SimpleOpenNI.SKEL_RIGHT_SHOULDER,jointRS); | |
PVector convertedJointRS = new PVector(); | |
context.convertRealWorldToProjective(jointRS, convertedJointRS); | |
width = (int)convertedJointRS.x - x; | |
//println("x= " + x + ", y= " + y + ", width= " + this.width); | |
} | |
} | |
void setup() | |
{ | |
context = new SimpleOpenNI(this); | |
context.setMirror(true); | |
// enable depthMap generation | |
if(context.enableDepth() == false) | |
{ | |
println("Can't open the depthMap, maybe the camera is not connected!"); | |
exit(); | |
return; | |
} | |
// 人物検出を有効にする | |
context.enableScene(); | |
// enable skeleton generation for all joints | |
context.enableUser(SimpleOpenNI.SKEL_PROFILE_ALL); | |
// RGBカメラを有効にする | |
if(context.enableRGB() == false) | |
{ | |
println("Can't open the rgbMap, maybe the camera is not connected or there is no rgbSensor!"); | |
exit(); | |
return; | |
} | |
// 画像データと深度データの位置合わせをする | |
context.alternativeViewPointDepthToImage(); | |
background(0); | |
stroke(0,0,255); | |
strokeWeight(3); | |
smooth(); | |
size(context.depthWidth(), context.depthHeight()); | |
num = 0; | |
fall[num] = new FallingRectangle(width/2 - FALLING_RECTANGLE_WIDTH/2); | |
hRct.x = width/2 - hRct.width/2; | |
} | |
void draw() | |
{ | |
// 一番下まで来たら上に戻す | |
if (fall[num].y > height) { | |
if ( fall[num].isFallingAroundYou ) { | |
fall[num].drawScoringVE(); | |
return; | |
} | |
int oldX = fall[num].x; | |
num++; | |
if (num < 50) { | |
fall[num] = new FallingRectangle(oldX); | |
} | |
} | |
fall[num].update(hRct); | |
// update the cam | |
context.update(); | |
maskImg = makeImgForMask(context.sceneImage()); | |
maskedImg = context.rgbImage(); // RGBカメラの映像がマスク対象 | |
maskedImg.mask(maskImg); // 人物の形で繰り抜いて | |
// 矩形を更新する | |
hRct.update(); | |
// ----- | |
// 描画 | |
// ----- | |
//background(0); | |
// draw depthImageMap | |
image(context.depthImage(),0,0); | |
//image(context.rgbImage(),0,0); | |
//background(0); | |
// 後ろ側の線分を描く | |
fall[num].drawBack(); | |
// とりあえずスケルトンを描画する | |
// 最終的には背景をグレースケール、 | |
// 人物をフルカラーで描画したい | |
// draw the skeleton if it's available | |
// stroke(128); | |
// strokeWeight(20); | |
if(context.isTrackingSkeleton(1)) | |
// drawSkeleton(1); | |
image(maskedImg, 0, 0); // 表示する | |
// 前側の線分を描く | |
fall[num].drawForward(); | |
} | |
// draw the skeleton with the selected joints | |
void drawSkeleton(int userId) | |
{ | |
// to get the 3d joint data | |
/* | |
PVector jointPos = new PVector(); | |
context.getJointPositionSkeleton(userId,SimpleOpenNI.SKEL_NECK,jointPos); | |
println(jointPos); | |
*/ | |
context.drawLimb(userId, SimpleOpenNI.SKEL_HEAD, SimpleOpenNI.SKEL_NECK); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_LEFT_SHOULDER); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_LEFT_ELBOW); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_ELBOW, SimpleOpenNI.SKEL_LEFT_HAND); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_RIGHT_SHOULDER); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_RIGHT_ELBOW); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_ELBOW, SimpleOpenNI.SKEL_RIGHT_HAND); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_TORSO); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_TORSO); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_LEFT_HIP); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_HIP, SimpleOpenNI.SKEL_LEFT_KNEE); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_LEFT_KNEE, SimpleOpenNI.SKEL_LEFT_FOOT); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_RIGHT_HIP); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_HIP, SimpleOpenNI.SKEL_RIGHT_KNEE); | |
context.drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_KNEE, SimpleOpenNI.SKEL_RIGHT_FOOT); | |
} | |
// ----------------------------------------------------------------- | |
// SimpleOpenNI events | |
void onNewUser(int userId) | |
{ | |
println("onNewUser - userId: " + userId); | |
println(" start pose detection"); | |
context.startPoseDetection("Psi",userId); | |
} | |
void onLostUser(int userId) | |
{ | |
println("onLostUser - userId: " + userId); | |
} | |
void onStartCalibration(int userId) | |
{ | |
println("onStartCalibration - userId: " + userId); | |
} | |
void onEndCalibration(int userId, boolean successfull) | |
{ | |
println("onEndCalibration - userId: " + userId + ", successfull: " + successfull); | |
if (successfull) | |
{ | |
println(" User calibrated !!!"); | |
context.startTrackingSkeleton(userId); | |
} | |
else | |
{ | |
println(" Failed to calibrate user !!!"); | |
println(" Start pose detection"); | |
context.startPoseDetection("Psi",userId); | |
} | |
} | |
void onStartPose(String pose,int userId) | |
{ | |
println("onStartPose - userId: " + userId + ", pose: " + pose); | |
println(" stop pose detection"); | |
context.stopPoseDetection(userId); | |
context.requestCalibrationSkeleton(userId, true); | |
} | |
void onEndPose(String pose,int userId) | |
{ | |
println("onEndPose - userId: " + userId + ", pose: " + pose); | |
} | |
// 深度映像から人物だけを抜き出すようなマスク用画像を返す | |
PImage makeImgForMask(PImage img) | |
{ | |
color cBlack = color(0, 0, 0); | |
color cWhite = color(255, 255, 255); | |
for (int x = 0; x < img.width; x++) | |
{ | |
for (int y = 0; y < img.height; y++) | |
{ | |
color c = img.get(x, y); | |
// 人が写っていない白、灰色、黒はRGB値が同じ | |
if (red(c) == green(c) & green(c) == blue(c)) | |
{ | |
img.set(x, y, cBlack); // 黒でマスクする | |
} | |
// 何らかの色が付いている部分は人が写っている | |
else | |
{ | |
img.set(x, y, cWhite); // 白で人の部分を残す | |
} | |
} | |
} | |
return img; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment