Как эффективно хранить данные о глубине в прошлом с помощью метода deepMapRealWorld ()? - PullRequest
1 голос
/ 26 марта 2012

Я не могу обойти специфическую проблему с SimpleOpenNI для обработки, я прошу вашей помощи.

Я бы хотел сохранить снимки данных глубины пикселя (возвращаемых методом .depthMapRealWorld () в виде массивов PVector) в дискретные интервалы времени, а затем обработать их для презентации. Я попытался добавить их в ArrayList, но похоже, что метод deepMapRealWorld () возвращает только ссылку на текущие данные глубины, а не реальный массив. Я попытался в этой последовательности:

  1. Просто получить данные и добавить их в массив. При каждом вызове метода update () весь массив массивов содержал один и тот же массив PVector, даже если массив в нулевой позиции был добавлен за много итераций!

  2. Затем я сделал массив PVector вместе с временем его создания частью класса. Немного переписал эскиз, но это не помогло. Все массивы в arraylist были одинаковыми.

  3. Наконец, в конструкторе класса я «вручную» скопировал координаты xyz каждого вектора из массива PVector в массив int. Похоже, это решило проблему - массивы int в массиве теперь отличаются друг от друга. Но это решение создало серьезные проблемы с производительностью.

Вопрос в том, существует ли более эффективный способ хранения этих массивов PVector и сохранения их стоимости?

код:

import processing.opengl.*;
import SimpleOpenNI.*;

SimpleOpenNI kinect;


float rotation = 0;
int time = 0;
ArrayList dissolver;
ArrayList<Integer> timer;
int pSize = 10;
Past past;

void setup()  {
  dissolver = new ArrayList();
  timer = new ArrayList();
  size(1024, 768, OPENGL);
  kinect = new SimpleOpenNI(this);
  kinect.enableDepth();
  translate(width/2, height/2, -100);
  rotateX(radians(180));
  stroke(255);
}

void draw() {
  background(0);
  translate(width/2, height/2, 500);
  rotateX(radians(180));
  kinect.update();
  stroke (255, 255, 255);

  past = new Past (kinect.depthMapRealWorld(), time);
  if (dissolver.size() == pSize) {  //remove the oldest arraylist element if when list gets full
    dissolver.remove(0); //
  }  

  if (time % 20 == 0) {
    dissolver.add (past);
    Past p1 = (Past) dissolver.get (0);
    float [][] o2 = p1.getVector(); 
    println ("x coord of a random point at arraylist position 0: " + o2[50000][0]); //for testing
  }
  if (dissolver.size() == pSize-1) {
    //dissolve ();  
  }
  time ++;
}

void dissolve () { //from the previous nonworking version; ignore
  for (int offset = 0; offset < pSize-1; offset ++) {
    PVector[] offPoints = (PVector[]) dissolver.get (offset);
    int offTime =  timer.get(offset);
    for (int i = 0; i < offPoints.length; i+=10) {
      int col = (time-offTime)*2; //why??
      stroke (255, 0, col);
      PVector currentPoint = offPoints[i];
      if (currentPoint.z <1500) {
        point(currentPoint.x, currentPoint.y, currentPoint.z); // - 2*(time-offTime) + random(0, 100)
      }
    }
  }
}

class Past {
  private PVector [] depth; //should contain this, not int 
  private float [][] depth1;
  private  int time;

  Past (PVector [] now, int t) {
    //should be like this: depth = now;
    //clumsy and performancewise catastrophic solution below
    depth1 = new float [now.length][3];
    for (int i = 0; i< now.length; i+=10) {
      PVector temp = now[i];
      depth1 [i][0] = temp.x;
      depth1 [i][1] = temp.y;
      depth1 [i][2] = temp.z;

    }
    //arrayCopy(now, depth); this didn't work either
    time = t;
  }

  float [][] getVector () {
    return depth1;
  }

  int getTime () {
    return time;
  }
}

1 Ответ

3 голосов
/ 26 марта 2012

Если я правильно понял, вы хотите сохранить 3D-позиции (ArrayList of PVectors) для каждого кадра, верно? Если это так, вы сможете просто хранить PVectors и ссылаться на них позже. Вот простой эскиз, чтобы проиллюстрировать это:

import processing.opengl.*;
import SimpleOpenNI.*;

SimpleOpenNI kinect;
ArrayList<ArrayList<PVector>> frames = new ArrayList<ArrayList<PVector>>();
ArrayList<PVector> frame;
boolean isRecording = true;
boolean isRecFrame;

void setup()  {
  size(1024, 768, OPENGL);
  kinect = new SimpleOpenNI(this);
  kinect.enableDepth();
  stroke(255);
}

void draw() {
  background(0);
  translate(width/2, height/2, 500);
  rotateX(PI);
  translate(0,0,-1000); 

  kinect.update();

  if(isRecording){

    isRecFrame = (frameCount % 20 == 0);//record every 20 frames
    int[]   depthMap = kinect.depthMap();
    int     steps   = 5;  // to speed up the drawing, draw every N point
    int     index;
    PVector realWorldPoint;
    if(isRecFrame) frame = new ArrayList<PVector>();

    for(int y=0;y < kinect.depthHeight();y+=steps)
    {
      for(int x=0;x < kinect.depthWidth();x+=steps)
      {
        index = x + y * kinect.depthWidth();
        if(depthMap[index] > 0)
        { 
          realWorldPoint = kinect.depthMapRealWorld()[index];
          point(realWorldPoint.x,realWorldPoint.y,realWorldPoint.z);
          if(isRecFrame) frame.add(realWorldPoint.get());
        }
      } 
    }
    if(isRecFrame) frames.add(frame); 

  }else{//playback
    ArrayList<PVector> currentFrame = frames.get(frameCount%frames.size());//playback is faster than recording now for testing purposes - add a decent frame counter here at some point
    for(PVector p : currentFrame) point(p.x,p.y,p.z);
  }

}

void keyPressed(){
  if(key == ' ') isRecording = !isRecording;
}

Используйте клавишу SPACE для переключения между записью и воспроизведением. Главное, что нужно отметить, это то, что я храню копию реальной позиции для каждого пикселя глубины (frame.add(realWorldPoint.get());). Еще одна вещь, которую нужно иметь в виду, это то, что в настоящее время вы храните эти координаты в памяти, которая в какой-то момент заполнится. Если вы храните только ограниченное количество кадров, это должно быть хорошо, если нет, вы можете сохранить в точках на диске. Таким образом, вы можете повторно использовать записи с другими набросками. Основным способом было бы хранить их в файле CSV:

void saveCSV(ArrayList<PVector> pts){
  String csv = "x,y,z\n";
  for(PVector p : pts) csv += p.x + "," + p.y + "," + p.z + "\n";
  saveStrings("frame_"+frameCount+".csv",csv.split("\n"));
}

Другой вариант - использовать более подходящий формат для облаков точек, например PLY . Сохранение ASCII PLY довольно просто:

void savePLY(ArrayList<PVector> pts){
  String ply = "ply\n";
  ply += "format ascii 1.0\n";
  ply += "element vertex " + pts.size() + "\n";
  ply += "property float x\n";
  ply += "property float y\n";
  ply += "property float z\n";
  ply += "end_header\n";
  for(PVector p : pts)ply += p.x + " " + p.y + " " + p.z + "\n";
  saveStrings("frame_"+frameCount+".ply",ply.split("\n"));
}

Позже вы можете открывать / исследовать / обрабатывать эти файлы с помощью таких инструментов, как MeshLab .

...