space-drawing

Dessiner dans l’espace

Pour la par­tie “Des­si­ner dans l’espace”, nous allons abor­der un nou­veau type de cap­teur, la Kinect.

Nous allons nous réfé­rer à un article détaillé du blog : article sur la Kinect

Exer­cice d’exemple de la biblio­thèque sim­pleO­penNI (Hands 3D) commenté

// on importe la bibliothèque SimpleOpenNI
import SimpleOpenNI.*;

// création d'un contexte de captation pour la kinect
//on créée donc un objet SimpleOpenNI appelé 'conetxt'
SimpleOpenNI context;

float        zoomF =0.5f;
float        rotX = radians(180);  // by default rotate the hole scene 180deg around the x-axis, 
// the data from openni comes upside down
float        rotY = radians(0);
boolean      handsTrackFlag = false;
// variable vectorielle qui va nous permettre de
// dessiner le tracé et le point
// quand une main est détectée
PVector      handVec = new PVector();
// déclaration d'une variable de type tableau
//pour stocker les coordonnées des positions
// de la min
ArrayList    handVecList = new ArrayList();
int          handVecListSize = 30;
// declaration d'une varibale de chaine de caractere
// pour afficher le type de mouvement de la main
// détecté par la kinect
String       lastGesture = "";

void setup()
{
  //taille de la scene + activation de l'affichage en 3D (P3D)
  size(1024, 768, P3D);

  // activation et paramètres de l'objet 'context'
  context = new SimpleOpenNI(this);

  // activer : context.setMirror(true); / désactiver :context.setMirror(false);
  // l'affichage en miroir
  context.setMirror(false);

  // si aucune profondeur n'est détectée 
  if (context.enableDepth() == false)
  {
    // on affiche le message suivant :
    println("Profondeur non activée, la kinect n'est peut être pas connectée !");
    exit();
    return;
  }

  // activation de la détection des mouvements
  context.enableGesture();
  // activation de la détection des mains
  context.enableHands();

  // activation de la détection de certains mouvement de la main
  // activation de la détection de mouvement type 'vague'
  context.addGesture("Wave");
  // activation de la détection de mouvement type 'clic' 
  context.addGesture("Click");
  // activation de la détection de mouvement type 'on lève la main'
  context.addGesture("RaiseHand");

  // réglage de la sensibilité de la detection de la main
  //context.setSmoothingHands(.5);

  smooth();

  perspective(radians(45),
  float(width)/float(height),
  10.0f, 150000.0f);
}

void draw()
{
  // rafraichissement de l'image 
  //capturée par la camera de la kinect
  context.update();

  //arriere plan noir
  background(0);

  // dans la representation générée par processing
  // on place notre point de vue
  translate(width/2, height/2, 0);
  rotateX(rotX);
  rotateY(rotY);
  scale(zoomF);

  // dessin des points blancs de la 'carte 3D'
  int[]   depthMap = context.depthMap();
  // pour accélerer l'affichage, on ne représente 
  // qu'un point blanc sur 3 
  int     steps   = 3;
  int     index;
  PVector realWorldPoint;

  // quand on deplace notre point de vue à l'aide des fleches du clavier
  // on le fait à partir d'un point qui est placé à 1000 de la camera
  translate(0, 0, -1000);

  // couleur des points de profondeur
  stroke(200);

  // visualisation points 3D
  // a chaque point de profondeur sur la largeur détecté par la kinect
  for (int y=0;y < context.depthHeight();y+=steps)
  {
    // a chaque point de profondeur sur la hauteur détecté par la kinect
    for (int x=0;x < context.depthWidth();x+=steps)
    {
      // 
      index = x + y * context.depthWidth();
      // si 
      if (depthMap[index] &rt; 0)
      {
        realWorldPoint = context.depthMapRealWorld()[index];
        // on dessine le point en recuperant les positions X, Y, Z
        // délivrés par la kinect
        point(realWorldPoint.x, realWorldPoint.y, realWorldPoint.z);
      }
    }
  }

  // dessin de la main reconnue
  if (handsTrackFlag)
  {
    pushStyle();

    // couleur du tracé du mouvement de la main (jaune)
    stroke(255, 255, 0, 200);
    // on désactive la couleur de remplissage
    noFill();
    // on active un objet Iterator de la bibliothèque simpleOpenNI
    // qui permet de détecter le mouvement de la main dans le temps
    Iterator itr = handVecList.iterator();
    // commencement du dessin du tracé de mouvement
    beginShape();
    while ( itr.hasNext () )
    {
      // création d'une variable PVector
      // pour le dessin du tracé du mouvment
      PVector p = (PVector) itr.next();
      // récupération des positions x, y, z
      // détectés par la kinect
      // et assignation aux coordonées pour le dessin du tracé
      vertex(p.x, p.y, p.z);
    }
    // fin du dessin du tracé de mouvement
    endShape();

    // couleur et epaisseur du point rouge de la main
    stroke(255, 0, 0);
    strokeWeight(4);
    // récupération des positions x, y, z
    // détectés par la kinect
    // et assignation aux coordonées pour le dessin du point rouge
    point(handVec.x, handVec.y, handVec.z);
    popStyle();
  }

  // on dessine la camera et son volume de détection
  // (boite jaune)
  //context.drawCamFrustum();
}

// -----------------------------------------------------------------
// evenements et fonctions liés aux mains
// -----------------------------------------------------------------
// création de la detection d'une main par la kinect
void onCreateHands(int handId, PVector pos, float time)
{
  //println("onCreateHands - handId: " + handId + ", pos: " + pos + ", time:" + time);

  handsTrackFlag = true;
  handVec = pos;

  handVecList.clear();
  handVecList.add(pos);
}

// mise à jour de la detection d'une main par la kinect
void onUpdateHands(int handId, PVector pos, float time)
{
  //println("onUpdateHandsCb - handId: " + handId + ", pos: " + pos + ", time:" + time);
  handVec = pos;

  handVecList.add(0, pos);
  if (handVecList.size() &rt;= handVecListSize)
  { // remove the last point 
    handVecList.remove(handVecList.size()-1);
  }
}

// suppression de la detection d'une main par la kinect
void onDestroyHands(int handId, float time)
{
  //println("onDestroyHandsCb - handId: " + handId + ", time:" + time);

  handsTrackFlag = false;
  context.addGesture(lastGesture);
}

// -----------------------------------------------------------------
// evenement de mouvement
// -----------------------------------------------------------------
// reconnaissance de type de mouvements de la main par la kinect
void onRecognizeGesture(String strGesture, PVector idPosition, PVector endPosition)
{
  println("onRecognizeGesture - strGesture: " + strGesture + ", idPosition: " + idPosition + ", endPosition:" + endPosition);

  lastGesture = strGesture;
  context.removeGesture(strGesture);
  context.startTrackingHands(endPosition);
}

void onProgressGesture(String strGesture, PVector position, float progress)
{
  //println("onProgressGesture - strGesture: " + strGesture + ", position: " + position + ", progress:" + progress);
}

// -----------------------------------------------------------------
// Evenement du clavier
// -----------------------------------------------------------------
void keyPressed()
{
  switch(key)
  {
    // si j'appuie sur la barre espace
    // j'active / je desactive l'affichage en miroir
  case ' ':
    context.setMirror(!context.mirror());
    break;
  }

  switch(keyCode)
  {
    // si j'appuie sur la fleche gauche
    // je deplace mon point de vue vers la gauche
  case LEFT:
    rotY += 0.1f;
    break;
    // si j'appuie sur la fleche droite
    // je deplace mon point de vue vers la droite
  case RIGHT:
    rotY -= 0.1f;
    break;
    // si j'appuie sur la fleche haut
    // je deplace mon point de vue vers le haut
  case UP:
    if (keyEvent.isShiftDown())
      zoomF += 0.01f;
    else
      rotX += 0.1f;
    break;
    // si j'appuie sur la fleche bas
    // je deplace mon point de vue vers le bas
  case DOWN:
    if (keyEvent.isShiftDown())
    {
      zoomF -= 0.01f;
      if (zoomF < 0.01)
        zoomF = 0.01;
    }
    else
      rotX -= 0.1f;
    break;
  }
}

Télé­char­ger le sketch com­menté Exer­cice technique

Diri­ger un objet 3D (sphere) généré par Pro­ces­sing avec la main détec­tée par la kinect

import processing.opengl.*;

// on importe la bibliothèque SimpleOpenNI
import SimpleOpenNI.*;

// création d'un contexte de captation pour la kinect
//on créée donc un objet SimpleOpenNI appelé 'conetxt'
SimpleOpenNI context;

float        zoomF =0.5f;
float        rotX = radians(180);  // by default rotate the hole scene 180deg around the x-axis, 
// the data from openni comes upside down
float        rotY = radians(0);
boolean      handsTrackFlag = false;
// variable vectorielle qui va nous permettre de
// dessiner le tracé et le point
// quand une main est détectée
PVector      handVec = new PVector();
// déclaration d'une variable de type tableau
//pour stocker les coordonnées des positions
// de la min
ArrayList    handVecList = new ArrayList();
int          handVecListSize = 30;
// declaration d'une varibale de chaine de caractere
// pour afficher le type de mouvement de la main
// détecté par la kinect
String       lastGesture = "";

void setup()
{
  //taille de la scene + activation de l'affichage en 3D (P3D)
  size(1024, 768, OPENGL);

  // activation et paramètres de l'objet 'context'
  context = new SimpleOpenNI(this);

  // activer : context.setMirror(true); / désactiver :context.setMirror(false);
  // l'affichage en miroir
  context.setMirror(false);

  // si aucune profondeur n'est détectée 
  if (context.enableDepth() == false)
  {
    // on affiche le message suivant :
    println("Profondeur non activée, la kinect n'est peut être pas connectée !");
    exit();
    return;
  }

  // activation de la détection des mouvements
  context.enableGesture();
  // activation de la détection des mains
  context.enableHands();

  // activation de la détection de certains mouvement de la main
  // activation de la détection de mouvement type 'vague'
  context.addGesture("Wave");
  // activation de la détection de mouvement type 'clic' 
  context.addGesture("Click");
  // activation de la détection de mouvement type 'on lève la main'
  context.addGesture("RaiseHand");

  // réglage de la sensibilité de la detection de la main
  //context.setSmoothingHands(.5);

  smooth();

  perspective(radians(45),
  float(width)/float(height),
  10.0f, 150000.0f);

}

void draw()
{
  lights();
  // rafraichissement de l'image 
  //capturée par la camera de la kinect
  context.update();

  //arriere plan noir
  background(0);

  // dans la representation générée par processing
  // on place notre point de vue
  translate(width/2, height/2, 0);
  rotateX(rotX);
  rotateY(rotY);
  scale(zoomF);

  // dessin des points blancs de la 'carte 3D'
  int[]   depthMap = context.depthMap();
  // pour accélerer l'affichage, on ne représente 
  // qu'un point blanc sur 3 
  int     steps   = 3;
  int     index;
  PVector realWorldPoint;

  // quand on deplace notre point de vue à l'aide des fleches du clavier
  // on le fait à partir d'un point qui est placé à 1000 de la camera
  translate(0, 0, -1000);

  // couleur des points de profondeur
  stroke(200);

  // visualisation points 3D
  // a chaque point de profondeur sur la largeur détecté par la kinect
  for (int y=0;y < context.depthHeight();y+=steps)
  {
    // a chaque point de profondeur sur la hauteur détecté par la kinect
    for (int x=0;x < context.depthWidth();x+=steps)
    {
      // 
      index = x + y * context.depthWidth();
      // si 
      if (depthMap[index] > 0)
      {
        realWorldPoint = context.depthMapRealWorld()[index];
        // on dessine le point en recuperant les positions X, Y, Z
        // délivrés par la kinect
        point(realWorldPoint.x, realWorldPoint.y, realWorldPoint.z);
      }
    }
  }

  // dessin de la main reconnue
  if (handsTrackFlag)
  {
    pushStyle();

    // couleur et epaisseur de la sphère qui suit la main
    noStroke();
    fill(255, 0, 255);
    // récupération des positions x, y, z
    // détectés par la kinect
    // et assignation aux coordonées pour le dessin dela sphère
    //point(handVec.x, handVec.y, handVec.z);
    translate(handVec.x-20, handVec.y-20, handVec.z-20);
    //ellipse(x[i], y[i], i, i);
    sphere(20);

    popStyle();
  }

  // on dessine la camera et son volume de détection
  // (boite jaune)
  //context.drawCamFrustum();
}

// -----------------------------------------------------------------
// evenements et fonctions liés aux mains
// -----------------------------------------------------------------
// création de la detection d'une main par la kinect
void onCreateHands(int handId, PVector pos, float time)
{
  //println("onCreateHands - handId: " + handId + ", pos: " + pos + ", time:" + time);

  handsTrackFlag = true;
  handVec = pos;

  handVecList.clear();
  handVecList.add(pos);
}

// mise à jour de la detection d'une main par la kinect
void onUpdateHands(int handId, PVector pos, float time)
{
  //println("onUpdateHandsCb - handId: " + handId + ", pos: " + pos + ", time:" + time);
  handVec = pos;

  handVecList.add(0, pos);
  if (handVecList.size() >= handVecListSize)
  { // remove the last point 
    handVecList.remove(handVecList.size()-1);
  }
}

// suppression de la detection d'une main par la kinect
void onDestroyHands(int handId, float time)
{
  //println("onDestroyHandsCb - handId: " + handId + ", time:" + time);

  handsTrackFlag = false;
  context.addGesture(lastGesture);
}

// -----------------------------------------------------------------
// evenement de mouvement
// -----------------------------------------------------------------
// reconnaissance de type de mouvements de la main par la kinect
void onRecognizeGesture(String strGesture, PVector idPosition, PVector endPosition)
{
  println("onRecognizeGesture - strGesture: " + strGesture + ", idPosition: " + idPosition + ", endPosition:" + endPosition);

  lastGesture = strGesture;
  context.removeGesture(strGesture);
  context.startTrackingHands(endPosition);
}

void onProgressGesture(String strGesture, PVector position, float progress)
{
  //println("onProgressGesture - strGesture: " + strGesture + ", position: " + position + ", progress:" + progress);
}

// -----------------------------------------------------------------
// Evenement du clavier
// -----------------------------------------------------------------
void keyPressed()
{
  switch(key)
  {
    // si j'appuie sur la barre espace
    // j'active / je desactive l'affichage en miroir
  case ' ':
    context.setMirror(!context.mirror());
    break;
  }

  switch(keyCode)
  {
    // si j'appuie sur la fleche gauche
    // je deplace mon point de vue vers la gauche
  case LEFT:
    rotY += 0.1f;
    break;
    // si j'appuie sur la fleche droite
    // je deplace mon point de vue vers la droite
  case RIGHT:
    rotY -= 0.1f;
    break;
    // si j'appuie sur la fleche haut
    // je deplace mon point de vue vers le haut
  case UP:
    if (keyEvent.isShiftDown())
      zoomF += 0.01f;
    else
      rotX += 0.1f;
    break;
    // si j'appuie sur la fleche bas
    // je deplace mon point de vue vers le bas
  case DOWN:
    if (keyEvent.isShiftDown())
    {
      zoomF -= 0.01f;
      if (zoomF < 0.01)
        zoomF = 0.01;
    }
    else
      rotX -= 0.1f;
    break;
  }
}

Télé­char­ger le sketch

Impor­ter un modele 3D et inter­agir avec lui par la Kinect

Pré requis : avoir un modèle 3D enre­gis­tré sous un fichier .obj

Isn­tal­la­tion de le biblio­thèque objLoader

import processing.opengl.*;
// on importe la bibliothèque obj loader qui nous permet 
// d'importer le fichier .obj
import saito.objloader.*;

// on importe la bibliothèque SimpleOpenNI
import SimpleOpenNI.*;

// création d'un contexte de captation pour la kinect
//on créée donc un objet SimpleOpenNI appelé 'conetxt'
SimpleOpenNI context;

float        zoomF =0.5f;
float        rotX = radians(180);  // by default rotate the hole scene 180deg around the x-axis, 
// the data from openni comes upside down
float        rotY = radians(0);
boolean      handsTrackFlag = false;
// variable vectorielle qui va nous permettre de
// dessiner le tracé et le point
// quand une main est détectée
PVector      handVec = new PVector();
// déclaration d'une variable de type tableau
//pour stocker les coordonnées des positions
// de la min
ArrayList    handVecList = new ArrayList();
int          handVecListSize = 30;
// declaration d'une varibale de chaine de caractere
// pour afficher le type de mouvement de la main
// détecté par la kinect
String       lastGesture = "";

// on créée un objet dans cette bibliotheque
// on le nomme model
OBJModel model;

void setup()
{
  //taille de la scene + activation de l'affichage en 3D (P3D)
  size(1024, 768, OPENGL);

  // activation et paramètres de l'objet 'context'
  context = new SimpleOpenNI(this);

  // activer : context.setMirror(true); / désactiver :context.setMirror(false);
  // l'affichage en miroir
  context.setMirror(false);

  // si aucune profondeur n'est détectée 
  if (context.enableDepth() == false)
  {
    // on affiche le message suivant :
    println("Profondeur non activée, la kinect n'est peut être pas connectée !");
    exit();
    return;
  }

  // activation de la détection des mouvements
  context.enableGesture();
  // activation de la détection des mains
  context.enableHands();

  // activation de la détection de certains mouvement de la main
  // activation de la détection de mouvement type 'vague'
  context.addGesture("Wave");
  // activation de la détection de mouvement type 'clic' 
  context.addGesture("Click");
  // activation de la détection de mouvement type 'on lève la main'
  context.addGesture("RaiseHand");

  // réglage de la sensibilité de la detection de la main
  //context.setSmoothingHands(.5);

  smooth();

  perspective(radians(45),
  float(width)/float(height),
  10.0f, 150000.0f);

  //on appelle notre objet model
  // et on lui donne ses caracteristiques (le fichier .obj lié...)
  model = new OBJModel(this, "map_ground_path_s.obj", "relative", QUADS);
  // activation mode debug
  // model.enableDebug();

  //on indique l'echelle de notre objet
  model.scale(200);
  //on le déplace au centre de notre scène
  model.translateToCenter();
}

void draw()
{
  lights();
  // rafraichissement de l'image 
  //capturée par la camera de la kinect
  context.update();

  //arriere plan noir
  background(0);

  // dans la representation générée par processing
  // on place notre point de vue
  translate(width/2, height/2, 0);
  rotateX(rotX);
  rotateY(rotY);
  scale(zoomF);

  // dessin des points blancs de la 'carte 3D'
  int[]   depthMap = context.depthMap();
  // pour accélerer l'affichage, on ne représente 
  // qu'un point blanc sur 3 
  int     steps   = 3;
  int     index;
  PVector realWorldPoint;

  // quand on deplace notre point de vue à l'aide des fleches du clavier
  // on le fait à partir d'un point qui est placé à 1000 de la camera
  translate(0, 0, -1000);

  // couleur des points de profondeur
  stroke(200);

  // visualisation points 3D
  // a chaque point de profondeur sur la largeur détecté par la kinect
  for (int y=0;y < context.depthHeight();y+=steps)
  {
    // a chaque point de profondeur sur la hauteur détecté par la kinect
    for (int x=0;x < context.depthWidth();x+=steps)
    {
      // 
      index = x + y * context.depthWidth();
      // si 
      if (depthMap[index] > 0)
      {
        realWorldPoint = context.depthMapRealWorld()[index];
        // on dessine le point en recuperant les positions X, Y, Z
        // délivrés par la kinect
        point(realWorldPoint.x, realWorldPoint.y, realWorldPoint.z);
      }
    }
  }

  // dessin de la main reconnue
  if (handsTrackFlag)
  {
    pushStyle();

    // couleur et epaisseur de la sphère qui suit la main
    noStroke();
    fill(255, 0, 255);
    // récupération des positions x, y, z
    // détectés par la kinect
    // et assignation aux coordonées pour le dessin dela sphère
    //point(handVec.x, handVec.y, handVec.z);
    translate(handVec.x-20, handVec.y-20, handVec.z-20);
    // je fais subir une rotation
    // à mon modele 3D pour qu'il soit affiché
    // dans une position visible et intéressante
    rotateY(1.5);
    rotateZ(1.5);

    //en appliquant la fonction draw à notre objet 'model'
    // on le fait se dessiner
    model.draw();

    popStyle();
  }

  // on dessine la camera et son volume de détection
  // (boite jaune)
  //context.drawCamFrustum();
}

// -----------------------------------------------------------------
// evenements et fonctions liés aux mains
// -----------------------------------------------------------------
// création de la detection d'une main par la kinect
void onCreateHands(int handId, PVector pos, float time)
{
  //println("onCreateHands - handId: " + handId + ", pos: " + pos + ", time:" + time);

  handsTrackFlag = true;
  handVec = pos;

  handVecList.clear();
  handVecList.add(pos);
}

// mise à jour de la detection d'une main par la kinect
void onUpdateHands(int handId, PVector pos, float time)
{
  //println("onUpdateHandsCb - handId: " + handId + ", pos: " + pos + ", time:" + time);
  handVec = pos;

  handVecList.add(0, pos);
  if (handVecList.size() >= handVecListSize)
  { // remove the last point 
    handVecList.remove(handVecList.size()-1);
  }
}

// suppression de la detection d'une main par la kinect
void onDestroyHands(int handId, float time)
{
  //println("onDestroyHandsCb - handId: " + handId + ", time:" + time);

  handsTrackFlag = false;
  context.addGesture(lastGesture);
}

// -----------------------------------------------------------------
// evenement de mouvement
// -----------------------------------------------------------------
// reconnaissance de type de mouvements de la main par la kinect
void onRecognizeGesture(String strGesture, PVector idPosition, PVector endPosition)
{
  println("onRecognizeGesture - strGesture: " + strGesture + ", idPosition: " + idPosition + ", endPosition:" + endPosition);

  lastGesture = strGesture;
  context.removeGesture(strGesture);
  context.startTrackingHands(endPosition);
}

void onProgressGesture(String strGesture, PVector position, float progress)
{
  //println("onProgressGesture - strGesture: " + strGesture + ", position: " + position + ", progress:" + progress);
}

// -----------------------------------------------------------------
// Evenement du clavier
// -----------------------------------------------------------------
void keyPressed()
{
  switch(key)
  {
    // si j'appuie sur la barre espace
    // j'active / je desactive l'affichage en miroir
  case ' ':
    context.setMirror(!context.mirror());
    break;
  }

  switch(keyCode)
  {
    // si j'appuie sur la fleche gauche
    // je deplace mon point de vue vers la gauche
  case LEFT:
    rotY += 0.1f;
    break;
    // si j'appuie sur la fleche droite
    // je deplace mon point de vue vers la droite
  case RIGHT:
    rotY -= 0.1f;
    break;
    // si j'appuie sur la fleche haut
    // je deplace mon point de vue vers le haut
  case UP:
    if (keyEvent.isShiftDown())
      zoomF += 0.01f;
    else
      rotX += 0.1f;
    break;
    // si j'appuie sur la fleche bas
    // je deplace mon point de vue vers le bas
  case DOWN:
    if (keyEvent.isShiftDown())
    {
      zoomF -= 0.01f;
      if (zoomF < 0.01)
        zoomF = 0.01;
    }
    else
      rotX -= 0.1f;
    break;
  }
}

Télé­char­ger le sketch et ses fichiers liés

Pour aller plus loin

Une appli­ca­tion la Kinect pour la détec­tion de mou­ve­ments et la géné­ra­tion de formes : TUIOKINECT

0