Willkommen auf unserem Seminar-Blog

Immer auf dem aktuellen Stand bleiben

Dieser Seminar-Blog befindet sich noch im Aufbau und wird in den kommenden Tagen entsprechend verfeinert.

Member Login

Lost your password?

Registration is closed

Sorry, you are not allowed to register by yourself on this site!

You must either be invited by one of our team member or request an invitation by email at viad.info {at} zhdk {dot} ch.

09 Kinect Limb Pong

März 4, 2012

 

Processing

Main

import SimpleOpenNI.*;
Hashtable users = new Hashtable();

SimpleOpenNI context;
float        zoomF =0.3f;
float        rotX = radians(160);  // by default rotate the hole scene 180deg around the x-axis, 
                                   // the data from openni comes upside down
float        rotY = radians(12);
boolean      autoCalib=true;
float bgLimitDepth=3000;

Hashtable userColor = new Hashtable();
Hashtable userBalls = new Hashtable();
Hashtable userTarget = new Hashtable();
PVector boxForce = new PVector();
PVector lineDir = new PVector();
Hashtable lineForce = new Hashtable();
boolean recording=false;

void setup()
{
  size(1024,768,P3D);  // strange, get drawing error in the cameraFrustum if i use P3D, in opengl there is no problem
  context = new SimpleOpenNI(this);
  
  // play recording
  context.openFileRecording("limbpong_double.oni");
  
  // enable mirror
  context.setMirror(true);

  // enable depthMap generation 
  if(context.enableDepth() == false)
  {
     println("Can't open the depthMap, maybe the camera is not connected!"); 
     exit();
     return;
  }

  // enable skeleton generation for all joints
  context.enableUser(SimpleOpenNI.SKEL_PROFILE_UPPER);

  stroke(255,255,255);
  smooth();  
  perspective(radians(45),
              float(width)/float(height),
              10,150000);

  // setup the recording 
  if (recording==true) {
    context.enableRecorder(SimpleOpenNI.RECORD_MEDIUM_FILE, "limbpong_double.oni");

    // select the recording channels
    context.addNodeToRecording(SimpleOpenNI.NODE_DEPTH, 
    SimpleOpenNI.CODEC_16Z_EMB_TABLES);
    context.addNodeToRecording(SimpleOpenNI.NODE_IMAGE, 
    SimpleOpenNI.CODEC_JPEG);
  }
 }

void draw()
{
  // update the cam
  context.update();

  background(255);
  
  // set the scene pos
  translate(width/2, height/2, 0);
  rotateX(rotX);
  rotateY(rotY);
  scale(zoomF);
  
  PImage  rgbImage = context.rgbImage();
  int[]   depthMap = context.depthMap();
  int     steps   = 4;  // to speed up the drawing, draw every third point
  int     index;
  PVector realWorldPoint;
  color   pixelColor;
 
  translate(0,0,-1000);  // set the rotation center of the scene 1000 infront of the camera
  
  //int userCount = context.getNumberOfUsers();
  //context.alternativeViewPointDepthToImage();
  
  stroke(153); 
  strokeWeight(2);
  for(int y=0;y < context.depthHeight();y+=steps)
  {
    for(int x=0;x < context.depthWidth();x+=steps)
    {
      index = x + y * context.depthWidth();
      if(depthMap[index] > 0 && depthMap[index]<bgLimitDepth)
      { 
        // draw the projected point
        realWorldPoint = context.depthMapRealWorld()[index];
        point(realWorldPoint.x,realWorldPoint.y,realWorldPoint.z);
      }
    } 
  }
  
  // loop through users (update ball, target)
  ArrayList tmpUsers = new ArrayList();
  ArrayList tmpBalls = new ArrayList();
  for (Enumeration e = users.keys() ; e.hasMoreElements() 😉 {
    int user = (Integer) e.nextElement();
    Ball userBall = (Ball) userBalls.get(user);
    userBall.draw();
    tmpUsers.add(user);
    tmpBalls.add(userBall.boxPos);
    Target userT = (Target) userTarget.get(user);
    if (user==userT.parent) {
        userT.draw();
    }
    // draw the skeleton if it's available
    if(context.isTrackingSkeleton(user)) drawSkeleton(user);
  }
  
  // COLLISION
  for(int i=0; i<tmpUsers.size(); i++) {
    for(int i2=0; i2<tmpUsers.size(); i2++) {
      if ((Integer) tmpUsers.get(i2)!=(Integer) tmpUsers.get(i)) {
        Target userT = (Target) userTarget.get(tmpUsers.get(i2));
        for(int k=0; k<tmpBalls.size(); k++) {
            userT.checkCollision((PVector) tmpBalls.get(i),(Integer)tmpUsers.get(i)); 
        }
      }
    }
  }

  // draw the kinect cam
  context.drawCamFrustum();
  
}

// draw the skeleton with the selected joints
void drawSkeleton(int userId)
{
  strokeWeight(3);

  // to get the 3d joint data
  drawLimb(userId, SimpleOpenNI.SKEL_HEAD, SimpleOpenNI.SKEL_NECK, false);

  drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_LEFT_SHOULDER, false);
  drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_LEFT_ELBOW, false);
  drawLimb(userId, SimpleOpenNI.SKEL_LEFT_ELBOW, SimpleOpenNI.SKEL_LEFT_HAND, false);

  drawLimb(userId, SimpleOpenNI.SKEL_NECK, SimpleOpenNI.SKEL_RIGHT_SHOULDER, false);
  drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_RIGHT_ELBOW, false);
  drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_ELBOW, SimpleOpenNI.SKEL_RIGHT_HAND, true);

  drawLimb(userId, SimpleOpenNI.SKEL_LEFT_SHOULDER, SimpleOpenNI.SKEL_TORSO, false);
  drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_SHOULDER, SimpleOpenNI.SKEL_TORSO, false);

  //drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_LEFT_HIP);
  //drawLimb(userId, SimpleOpenNI.SKEL_LEFT_HIP, SimpleOpenNI.SKEL_LEFT_KNEE);
  //drawLimb(userId, SimpleOpenNI.SKEL_LEFT_KNEE, SimpleOpenNI.SKEL_LEFT_FOOT);

  //drawLimb(userId, SimpleOpenNI.SKEL_TORSO, SimpleOpenNI.SKEL_RIGHT_HIP);
  //drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_HIP, SimpleOpenNI.SKEL_RIGHT_KNEE);
  //drawLimb(userId, SimpleOpenNI.SKEL_RIGHT_KNEE, SimpleOpenNI.SKEL_RIGHT_FOOT);  

  strokeWeight(1);
 
}

void drawLimb(int userId,int jointType1,int jointType2, boolean drawBox)
{
  PVector jointPos1 = new PVector();
  PVector jointPos2 = new PVector();
  float  confidence;
  
  // draw the joint position
  confidence = context.getJointPositionSkeleton(userId,jointType1,jointPos1);
  confidence = context.getJointPositionSkeleton(userId,jointType2,jointPos2);

  stroke(255,0,0,confidence * 200 + 55);
  //line(jointPos1.x,jointPos1.y,jointPos1.z,
  //     jointPos2.x,jointPos2.y,jointPos2.z);
       
  float limbLength = dist(jointPos1.x,jointPos1.y,jointPos1.z,jointPos2.x,jointPos2.y,jointPos2.z);
  
  PVector pVdir = jointPos1.cross(jointPos2); // direction of limb
  drawJointOrientation(userId,jointType1,jointPos1,jointType2,jointPos2,50,drawBox, limbLength, pVdir);
}

void drawJointOrientation(int userId,int jointType,PVector pos,int jointType2,PVector pos2,float length, boolean drawBox, float limbLength, PVector pVdir)
{
  // draw the joint orientation  
  PMatrix3D  orientation = new PMatrix3D();
  float confidence = context.getJointOrientationSkeleton(userId,jointType,orientation);
  if(confidence < 0.001f) 
    // nothing to draw, orientation data is useless
    return;
  
  Ball userBall = (Ball) userBalls.get(userId);
    
  // target
  Target userT = (Target) userTarget.get(userId);
  
  // skeleton head -> draw target
  if (jointType==SimpleOpenNI.SKEL_NECK) {
    userT.ini = false;
    userT.targetPos = pos;
    userT.orientation = orientation;
  }
    
  if (drawBox==true) { 
    
    color uColor = (Integer) userColor.get(userId);
    
    float offsetDefaultY = -700;
    strokeWeight(1);
    
    pushStyle();
    stroke(red(uColor),green(uColor),blue(uColor));
    strokeWeight(2);
    // line target to hand
    line(userBall.boxPos.x,userBall.boxPos.y,userBall.boxPos.z,
       pos2.x,pos2.y,pos2.z);
    popStyle();
    
    PVector targetPos = new PVector(userBall.boxPos.x,userBall.boxPos.y,userBall.boxPos.z);
    PVector lineDir = PVector.sub(pos2,targetPos);
  
    // default position
    //line(userBall.boxPos.x,userBall.boxPos.y,userBall.boxPos.z,pos2.x,pos2.y+offsetDefaultY,pos2.z);
    pushMatrix();
    translate(pos2.x,pos2.y+offsetDefaultY,pos2.z);
    fill(204);
    stroke(102);
    box(50,50,50);
    popMatrix();
    
    PVector defaultPos = new PVector(pos2.x,pos2.y-700,pos2.z);
    PVector defaultDir = PVector.sub(defaultPos,targetPos);
    boxForce.add(defaultDir);
    boxForce.add(lineDir);
    boxForce.normalize();
    boxForce.mult(180);
    
    userBall.boxDir.add(boxForce);
    
    // box hand
    pushMatrix();
      translate(pos2.x,pos2.y,pos2.z);
      
      // set the local coordsys
      applyMatrix(orientation);
      
      if (pVdir.z>0) {
      //translate(limbLength,0,0);
      } else {
      //  translate(-limbLength,0,0);
      }
      
      fill(red(uColor),green(uColor),blue(uColor));
      box(200,100,20);
      
      // coordsys lines are 100mm long
      // x - r
      //stroke(255,0,0,confidence * 200 + 55);
      //line(0,0,0,
      //     length,0,0);
      // y - g
      //stroke(0,255,0,confidence * 200 + 55);
      //line(0,0,0,
      //     0,length,0);
      // z - b    
      //stroke(0,0,255,confidence * 200 + 55);
      //line(0,0,0,
      //     0,0,length);
           
    popMatrix();
  }
}

// -----------------------------------------------------------------
// SimpleOpenNI user events

void onNewUser(int userId)
{
  users.put(userId, userId);
  userColor.put(userId, color(random(0,204),random(0,204),random(0,204)));
  
  color tmpC = (Integer) userColor.get(userId);
  
  // BALL ini            
  Ball tmp = new Ball(tmpC);
  userBalls.put(userId, tmp);
  
  Target userT = new Target(userId);
  userT.userColor = tmpC;
  userTarget.put(userId,userT);

  println("onNewUser - userId: " + userId);
  println("  start pose detection");
  
  if(autoCalib)
    context.requestCalibrationSkeleton(userId,true);
  else    
    context.startPoseDetection("Psi",userId);
}

void onLostUser(int userId)
{
  println("onLostUser - userId: " + userId);
  users.remove(userId);
  userBalls.remove(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("onStartdPose - 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);
}

// -----------------------------------------------------------------
// Keyboard events

void keyPressed()
{
  switch(key)
  {
  case ' ':
    context.setMirror(!context.mirror());
    break;
  case 'p':
     save("screens/points_"+year()+"-"+month()+"-"+day()+"_"+hour()+"-"+minute()+"-"+second());
   break;
  }
    
  switch(keyCode)
  {
    case LEFT:
      rotY += 0.1f;
      break;
    case RIGHT:
      // zoom out
      rotY -= 0.1f;
      break;
    case UP:
      if(keyEvent.isShiftDown())
        zoomF += 0.01f;
      else
        rotX += 0.1f;
      break;
    case DOWN:
      if(keyEvent.isShiftDown())
      {
        zoomF -= 0.01f;
        if(zoomF < 0.01)
          zoomF = 0.01;
      }
      else
        rotX -= 0.1f;
      break;
  }
}

Class Ball

class Ball {
  
  PVector boxPos = new PVector();
  PVector boxDir = new PVector(0,0,0);
  float ballRotX;
  float ballRotY;
  float gravity = 0;
  float friction = 0.92;
  color ballColor;
  int ballSize = 30;
  
  Ball(color _c) {
    ballColor = _c;
  } 
  
  void draw() {  
    boxDir.x*=friction;
    boxDir.y*=friction;
    boxDir.z*=friction;
    boxPos.add(boxDir);
    
    pushMatrix();
    translate(boxPos.x,boxPos.y,boxPos.z);
    //rotateX(radians(ballRotX));
    //rotateY(radians(ballRotY));
  
    fill(red(ballColor),green(ballColor),blue(ballColor));
    stroke(red(ballColor)-24,green(ballColor)-24,blue(ballColor)-24);
    sphereDetail(8);
    sphere(ballSize);
    popMatrix();
  
    boxPos.y-=gravity;
    //boxPos.y+=1;
  } 
}

Class Target

class Target {
 
 boolean hit=false;
 color targetColor = color(204,204,153);
 PVector targetSize = new PVector(300,500,50);
 PVector targetPos = new PVector(0,0,1000);
 PVector shiftPos = new PVector(0,400,0);
 PVector ballPos = new PVector(0,0,0);
 color userColor = color(0,0,0);
 int parent;
 int xTarget,yTarget,zTarget;
 PMatrix3D  orientation = new PMatrix3D();
 boolean ini=true;
 float hitLength = 30;
 float hitLengthCounter=0;
 float hitArea=400;
 
 Target(int _parent) {
   parent = _parent;
 }

 void draw() {
   if (parent>0 && ini==false) {
     pushMatrix();
     fill(userColor);
     if ((hit==true || hitLengthCounter<hitLength) && ini==false) {
       fill(targetColor);
     }
     targetPos.add(shiftPos);
    
     translate(targetPos.x, targetPos.y, targetPos.z);
    
     // set the local coordsys
     applyMatrix(orientation);
    
     box(targetSize.x,targetSize.y,targetSize.z);
     popMatrix();
     hit=false;
     hitLengthCounter++;
   }
 } 
 
 boolean checkCollision(PVector _p,int user) {  
   ballPos = _p;
    
   if (ini==false && parent != user ) {
     //println("CHECK2"); 
   if((int(ballPos.x) >= (targetPos.x-hitArea) && int(ballPos.x) <= (targetPos.x+hitArea + targetSize.x)) 
     && (int(ballPos.y) >= (targetPos.y-hitArea) && int(ballPos.y) <= (targetPos.y+hitArea + targetSize.y))
     && (int(ballPos.z) >= (targetPos.z-hitArea) && int(ballPos.z) <= (targetPos.z+hitArea + targetSize.z))
     ){
       println("Kollision  parent " + parent + " user " + user);
       hit=true;
       hitLengthCounter=0;
     } 
   }
   return hit;
 }
}