2011-06-22 1 views
1

J'ai travaillé avec Processing et Cinder pour modifier l'entrée Kinect à la volée. Cependant, je voudrais également enregistrer le flux complet (profondeur + couleur + accéléromètre, et tout ce qui s'y trouve). J'enregistre pour pouvoir essayer différents effets/traitements sur le même matériel. Parce que je ne fais que l'apprentissage de Cinder and Processing est assez lent/laggy, j'ai eu du mal à trouver des conseils sur une stratégie pour capturer le flux - n'importe quoi (de préférence dans Cinder, oF ou Processing) serait vraiment utile.Quelle est la méthode la plus fiable pour enregistrer un flux Kinect en vue d'une lecture ultérieure?

+1

Utilisez-vous ou OpenNI Le SDK de Microsoft? – Artium

+0

que voulez-vous dire par valeur d'accéléromètre? –

+0

Merci pour les questions, désolé je n'étais pas plus précis! Je n'utilise pas Microsoft SDK, et j'ai le plus d'expérience en utilisant la bibliothèque Processing (par Shiffman, je crois) et le bloc Cinder (par R Hodgin) ... Je comprends que la Kinect a un accéléromètre dedans (I ' Je ne suis pas tout à fait sûr pourquoi il est là - peut-être pour détecter quand il est sur une surface non plane?), et ce serait génial de pouvoir enregistrer la sortie complète, y compris tous les autres capteurs. Mais ce n'est pas essentiel, si cela rend la question plus facile à répondre ... Merci encore, AKA – AKA

Répondre

3

J'ai déjà essayé Processing et OpenFrameworks. Le traitement est plus lent lors de l'affichage des deux images (profondeur et couleur). OpenFrameworks ralentit un peu en écrivant les données sur le disque, mais voici l'approche de base:

  1. Setup Openframeworks (ouvert et compiler un échantillon pour vous assurer que vous êtes opérationnel)
  2. Télécharger le ofxKinect addon et copier l'exemple projet comme décrit sur github.
  3. Une fois que vous avez l'exemple et DE ofxKinect en cours d'exécution, il est juste une question d'ajouter quelques variables pour enregistrer vos données:

Dans cette configuration de base, j'ai créé quelques cas ofImage et un booléen pour basculer l'épargne. Dans l'exemple, les buffers profondeur et RGB sont sauvegardés dans des instances ofxCvGrayscaleImage, mais je n'ai pas utilisé OF et OpenCV assez pour savoir comment faire quelque chose d'aussi simple que d'enregistrer une image sur le disque, c'est pourquoi j'ai utilisé deux instances. Je ne sais pas à quel point vous êtes à l'aise avec Processing, OF, Cinder, donc, pour les arguments, je suppose que vous savez que vous êtes loin du traitement, mais vous êtes encore en train de vous attaquer au C++.

DE est assez similaire à la transformation, mais il y a quelques différences:

  1. Dans le traitement que vous avez déclaration des variables et ils sont l'utilisation dans le même fichier. Dans OF vous avez un fichier .h où vous déclarez que vous êtes des variables et le fichier .cpp où vous initialisez et utilisez vos variables. Dans Processing, vous avez les méthodes setup() (initialize variables) et draw() (mise à jour des variables et draw to screen), alors que dans OF vous avez setup() (comme dans Processing), update() (update seulement, rien de visuel) et draw() (dessiner à l'écran en utilisant les valeurs mises à jour)
  2. Lorsque vous travaillez avec des images, puisque vous codez en C++, vous devez d'abord allouer de la mémoire, par opposition à Processing/Java où vous avez gestion de la mémoire.

Il ya plus de différences que je ne vais pas détailler ici. Ne consultez OF for Processing Users sur le wiki

Retour à l'exemple exampleKinect, voici ma configuration de base:

.h:

#pragma once 

#include "ofMain.h" 
#include "ofxOpenCv.h" 
#include "ofxKinect.h" 

class testApp : public ofBaseApp { 
    public: 

     void setup(); 
     void update(); 
     void draw(); 
     void exit(); 

     void drawPointCloud(); 

     void keyPressed (int key); 
     void mouseMoved(int x, int y); 
     void mouseDragged(int x, int y, int button); 
     void mousePressed(int x, int y, int button); 
     void mouseReleased(int x, int y, int button); 
     void windowResized(int w, int h); 

     ofxKinect kinect; 

     ofxCvColorImage  colorImg; 

     ofxCvGrayscaleImage  grayImage; 
     ofxCvGrayscaleImage  grayThresh; 
     ofxCvGrayscaleImage  grayThreshFar; 

     ofxCvContourFinder contourFinder; 

     ofImage    colorData;//to save RGB data to disk 
     ofImage    grayData;//to save depth data to disk 

     bool    bThreshWithOpenCV; 
     bool    drawPC; 
     bool    saveData;//save to disk toggle 

     int     nearThreshold; 
     int     farThreshold; 

     int     angle; 

     int     pointCloudRotationY; 
     int     saveCount;//counter used for naming 'frames' 
}; 

et le fichier .cpp:

#include "testApp.h" 


//-------------------------------------------------------------- 
void testApp::setup() { 
    //kinect.init(true); //shows infrared image 
    kinect.init(); 
    kinect.setVerbose(true); 
    kinect.open(); 

    colorImg.allocate(kinect.width, kinect.height); 
    grayImage.allocate(kinect.width, kinect.height); 
    grayThresh.allocate(kinect.width, kinect.height); 
    grayThreshFar.allocate(kinect.width, kinect.height); 
    //allocate memory for these ofImages which will be saved to disk 
    colorData.allocate(kinect.width, kinect.height, OF_IMAGE_COLOR); 
    grayData.allocate(kinect.width, kinect.height, OF_IMAGE_GRAYSCALE); 

    nearThreshold = 230; 
    farThreshold = 70; 
    bThreshWithOpenCV = true; 

    ofSetFrameRate(60); 

    // zero the tilt on startup 
    angle = 0; 
    kinect.setCameraTiltAngle(angle); 

    // start from the front 
    pointCloudRotationY = 180; 

    drawPC = false; 

    saveCount = 0;//init frame counter 
} 

//-------------------------------------------------------------- 
void testApp::update() { 
    ofBackground(100, 100, 100); 

    kinect.update(); 
    if(kinect.isFrameNew()) // there is a new frame and we are connected 
    { 

     grayImage.setFromPixels(kinect.getDepthPixels(), kinect.width, kinect.height); 

     if(saveData){ 
      //if toggled, set depth and rgb pixels to respective ofImage, save to disk and update the 'frame' counter 
      grayData.setFromPixels(kinect.getDepthPixels(), kinect.width, kinect.height,true); 
      colorData.setFromPixels(kinect.getCalibratedRGBPixels(), kinect.width, kinect.height,true); 
      grayData.saveImage("depth"+ofToString(saveCount)+".png"); 
      colorData.saveImage("color"+ofToString(saveCount)+".png"); 
      saveCount++; 
     } 

     //we do two thresholds - one for the far plane and one for the near plane 
     //we then do a cvAnd to get the pixels which are a union of the two thresholds. 
     if(bThreshWithOpenCV){ 
      grayThreshFar = grayImage; 
      grayThresh = grayImage; 
      grayThresh.threshold(nearThreshold, true); 
      grayThreshFar.threshold(farThreshold); 
      cvAnd(grayThresh.getCvImage(), grayThreshFar.getCvImage(), grayImage.getCvImage(), NULL); 
     }else{ 

      //or we do it ourselves - show people how they can work with the pixels 

      unsigned char * pix = grayImage.getPixels(); 
      int numPixels = grayImage.getWidth() * grayImage.getHeight(); 

      for(int i = 0; i < numPixels; i++){ 
       if(pix[i] < nearThreshold && pix[i] > farThreshold){ 
        pix[i] = 255; 
       }else{ 
        pix[i] = 0; 
       } 
      } 
     } 

     //update the cv image 
     grayImage.flagImageChanged(); 

     // find contours which are between the size of 20 pixels and 1/3 the w*h pixels. 
     // also, find holes is set to true so we will get interior contours as well.... 
     contourFinder.findContours(grayImage, 10, (kinect.width*kinect.height)/2, 20, false); 
    } 
} 

//-------------------------------------------------------------- 
void testApp::draw() { 
    ofSetColor(255, 255, 255); 
    if(drawPC){ 
     ofPushMatrix(); 
     ofTranslate(420, 320); 
     // we need a proper camera class 
     drawPointCloud(); 
     ofPopMatrix(); 
    }else{ 
     kinect.drawDepth(10, 10, 400, 300); 
     kinect.draw(420, 10, 400, 300); 

     grayImage.draw(10, 320, 400, 300); 
     contourFinder.draw(10, 320, 400, 300); 
    } 


    ofSetColor(255, 255, 255); 
    stringstream reportStream; 
    reportStream << "accel is: " << ofToString(kinect.getMksAccel().x, 2) << "/" 
           << ofToString(kinect.getMksAccel().y, 2) << "/" 
           << ofToString(kinect.getMksAccel().z, 2) << endl 
       << "press p to switch between images and point cloud, rotate the point cloud with the mouse" << endl 
       << "using opencv threshold = " << bThreshWithOpenCV <<" (press spacebar)" << endl 
       << "set near threshold " << nearThreshold << " (press: + -)" << endl 
       << "set far threshold " << farThreshold << " (press: < >) num blobs found " << contourFinder.nBlobs 
        << ", fps: " << ofGetFrameRate() << endl 
       << "press c to close the connection and o to open it again, connection is: " << kinect.isConnected() << endl 
       << "press s to toggle saving depth and color data. currently saving: " << saveData << endl 
       << "press UP and DOWN to change the tilt angle: " << angle << " degrees"; 
    ofDrawBitmapString(reportStream.str(),20,656); 
} 

void testApp::drawPointCloud() { 
    ofScale(400, 400, 400); 
    int w = 640; 
    int h = 480; 
    ofRotateY(pointCloudRotationY); 
    float* distancePixels = kinect.getDistancePixels(); 
    glBegin(GL_POINTS); 
    int step = 2; 
    for(int y = 0; y < h; y += step) { 
     for(int x = 0; x < w; x += step) { 
      ofPoint cur = kinect.getWorldCoordinateFor(x, y); 
      ofColor color = kinect.getCalibratedColorAt(x,y); 
      glColor3ub((unsigned char)color.r,(unsigned char)color.g,(unsigned char)color.b); 
      glVertex3f(cur.x, cur.y, cur.z); 
     } 
    } 
    glEnd(); 
} 

//-------------------------------------------------------------- 
void testApp::exit() { 
    kinect.setCameraTiltAngle(0); // zero the tilt on exit 
    kinect.close(); 
} 

//-------------------------------------------------------------- 
void testApp::keyPressed (int key) { 
    switch (key) { 
     case ' ': 
      bThreshWithOpenCV = !bThreshWithOpenCV; 
     break; 
     case'p': 
      drawPC = !drawPC; 
      break; 

     case '>': 
     case '.': 
      farThreshold ++; 
      if (farThreshold > 255) farThreshold = 255; 
      break; 
     case '<':  
     case ',':  
      farThreshold --; 
      if (farThreshold < 0) farThreshold = 0; 
      break; 

     case '+': 
     case '=': 
      nearThreshold ++; 
      if (nearThreshold > 255) nearThreshold = 255; 
      break; 
     case '-':  
      nearThreshold --; 
      if (nearThreshold < 0) nearThreshold = 0; 
      break; 
     case 'w': 
      kinect.enableDepthNearValueWhite(!kinect.isDepthNearValueWhite()); 
      break; 
     case 'o': 
      kinect.setCameraTiltAngle(angle); // go back to prev tilt 
      kinect.open(); 
      break; 
     case 'c': 
      kinect.setCameraTiltAngle(0);  // zero the tilt 
      kinect.close(); 
      break; 
     case 's'://s to toggle saving data 
      saveData = !saveData; 
      break; 

     case OF_KEY_UP: 
      angle++; 
      if(angle>30) angle=30; 
      kinect.setCameraTiltAngle(angle); 
      break; 

     case OF_KEY_DOWN: 
      angle--; 
      if(angle<-30) angle=-30; 
      kinect.setCameraTiltAngle(angle); 
      break; 
    } 
} 

//-------------------------------------------------------------- 
void testApp::mouseMoved(int x, int y) { 
    pointCloudRotationY = x; 
} 

//-------------------------------------------------------------- 
void testApp::mouseDragged(int x, int y, int button) 
{} 

//-------------------------------------------------------------- 
void testApp::mousePressed(int x, int y, int button) 
{} 

//-------------------------------------------------------------- 
void testApp::mouseReleased(int x, int y, int button) 
{} 

//-------------------------------------------------------------- 
void testApp::windowResized(int w, int h) 
{} 

C'est une configuration très basique. N'hésitez pas à modifier (ajouter l'angle d'inclinaison aux données sauvegardées, etc.) Je suis à peu près sûr qu'il existe des façons d'améliorer cette vitesse (par ex.ne pas mettre à jour ofxCvGrayscaleImage instances et ne pas tirer des images à l'écran lors de l'enregistrement, ou empiler quelques images et de les écrire à l'intervalle par opposition à sur chaque image, etc.)

Goodluck

Questions connexes