Есть ли справочная библиотека команд для Дэниела Шиффмана?
Я пытаюсь обновить сценарий, созданный Луисом Кальсада еще в 2010 году. Он изменил файл примера облака точек Даниэля Шиффмана, чтобы собирать данные облака точек в виде текстовых файлов. Вот учебник http://moullinex.tumblr.com/post/3180520798/catalina-music-video
Проблема в том, что все команды кажутся устаревшими, например, Kinect.enabledepth(true); после изменения на kinect2.initDepth(true) возвращается как ошибка "не применимо для аргументов (логическое значение)" или если я удаляю это, то следующая строка возвращает ошибку, говорящую "функция processDepthImage (логическое значение) не существует", и я не может найти эквивалентную команду в файлах примеров
Существует ли какая-то справочная библиотека, в которой я могу видеть все возможные команды (и даже лучше этих команд, эквивалентных предшественникам), чтобы я мог пройти через команды обновления скрипта для работы с новой библиотекой openkinect, если нет, то это даже возможная задача для меня, чтобы завершить быть новичком обработки?
1 ответ
Вот пара вещей, которые помогут:
- Прочитайте доступную документацию и руководства
- Если этого недостаточно, а javadocs / reference не доступны, посмотрите на общедоступные методы в исходном коде и прочитайте комментарии над ними.
- В Processing 3 вы можете использовать автозаполнение для просмотра доступных методов и свойств по всему коду (включая библиотеки). Вы даже можете включить Ctrl+ пробел автозаполнения (если вы установили его в настройках)
Это может показать, почему функция initDepth(true)
"не применимо для аргументов (логическое значение)". Используя функцию завершения обработки 3, вы можете увидеть, что на самом деле initDepth()
функция, но она не принимает аргументов (поэтому удалите true
).
Используя тот же метод, вы можете легко обнаружить, что некоторые функции из Kinect (v1) отсутствуют в классе Kinect2 (например, processDepthImage()
а также getDepthFPS()
) и вы должны удалить те, и другие имеют эквивалентную функциональность, но другое имя / подпись (например, quit()
в Kinect (v1), но stopDevice()
а также dispose()
в Kinect2)
Вот примерная версия кода, которая должна быть скомпилирована, но может не работать на 100%, поскольку у меня нет Kinect 2 в моем распоряжении:
import org.openkinect.freenect.*;
import org.openkinect.freenect2.*;
import org.openkinect.processing.*;
import org.openkinect.tests.*;
// Daniel Shiffman
// Kinect Point Cloud example
// http://www.shiffman.net
// https://github.com/shiffman/libfreenect/tree/master/wrappers/java/processing
import java.util.*;
import java.io.*;
// Kinect Library object
// Kinect Library object
Kinect2 kinect2;
float a = 0;
// Size of kinect image
int w = 640;
int h = 480;
// writing state indicator
boolean write = false;
// treshold filter initial value
int fltValue = 950;
// "recording" object. each vector element holds a coordinate map vector
Vector <Object> recording = new Vector<Object>();
// We'll use a lookup table so that we don't have to repeat the math over and over
float[] depthLookUp = new float[2048];
void setup() {
size(800, 600, P3D);
kinect2 = new Kinect2(this);
kinect2.init();
kinect2.initDevice();
kinect2.initDepth();
// We don't need the grayscale image in this example
// so this makes it more efficient
//kinect2.processDepthImage(false);
// Lookup table for all possible depth values (0 - 2047)
for (int i = 0; i < depthLookUp.length; i++) {
depthLookUp[i] = rawDepthToMeters(i);
}
}
void draw() {
background(0);
fill(255);
textMode(SCREEN);
text("Processing FR: " + (int)frameRate, 10, 16);
// Get the raw depth as array of integers
int[] depth = kinect2.getRawDepth();
// We're just going to calculate and draw every 4th pixel (equivalent of 160x120)
int skip = 4;
// Translate and rotate
translate(width/2, height/2, -50);
rotateY(a);
//noStroke();
//lights();
int index = 0;
PVector[] frame = new PVector[19200];
for (int x=0; x<w; x+=skip) {
for (int y=0; y<h; y+=skip) {
int offset = x+y*w;
// Convert kinect data to world xyz coordinate
int rawDepth = depth[offset];
boolean flt = true;
PVector v = depthToWorld(x, y, rawDepth);
if (flt && rawDepth > fltValue)
{
v = depthToWorld(x, y, 2047);
}
frame[index] = v;
index++;
stroke(map(rawDepth, 0, 2048, 0, 256));
pushMatrix();
// Scale up by 200
float factor = 400;
translate(v.x*factor, v.y*factor, factor-v.z*factor);
//sphere(1);
point(0, 0);
//line (0,0,1,1);
popMatrix();
}
}
if (write == true) {
recording.add(frame);
}
// Rotate
//a += 0.015f;
}
// These functions come from: http://graphics.stanford.edu/~mdfisher/Kinect.html
float rawDepthToMeters(int depthValue) {
if (depthValue < 2047) {
return (float)(1.0 / ((double)(depthValue) * -0.0030711016 + 3.3309495161));
}
return 0.0f;
}
PVector depthToWorld(int x, int y, int depthValue) {
final double fx_d = 1.0 / 5.9421434211923247e+02;
final double fy_d = 1.0 / 5.9104053696870778e+02;
final double cx_d = 3.3930780975300314e+02;
final double cy_d = 2.4273913761751615e+02;
PVector result = new PVector();
double depth = depthLookUp[depthValue];//rawDepthToMeters(depthValue);
result.x = (float)((x - cx_d) * depth * fx_d);
result.y = (float)((y - cy_d) * depth * fy_d);
result.z = (float)(depth);
return result;
}
void stop() {
kinect2.stopDevice();
kinect2.dispose();
super.stop();
}
int currentFile = 0;
void saveFile() {
}
void keyPressed() { // Press a key to save the data
if (key == '1')
{
fltValue += 50;
println("fltValue: " + fltValue);
} else if (key == '2')
{
fltValue -= 50;
println("fltValue: " + fltValue);
} else if (key=='4') {
if (write == true) {
write = false;
println( "recorded " + recording.size() + " frames.");
// saveFile();
// save
Enumeration e = recording.elements();
println("Stopped Recording " + currentFile);
int i = 0;
while (e.hasMoreElements()) {
// Create one directory
boolean success = (new File("out"+currentFile)).mkdir();
PrintWriter output = createWriter("out"+currentFile+"/frame" + i++ +".txt");
PVector [] frame = (PVector []) e.nextElement();
for (int j = 0; j < frame.length; j++) {
output.println(j + ", " + frame[j].x + ", " + frame[j].y + ", " + frame[j].z );
}
output.flush(); // Write the remaining data
output.close();
}
currentFile++;
}
} else if (key == '3') {
println("Started Recording "+currentFile);
recording.clear();
write = true;
}
}
Обновление Большая часть исходного кода действительна только для Kinect v1, особенно части вокруг данных о глубине и преобразования значений глубины в реальные значения.
Однако пример DepthPointCloud2, который поставляется с библиотекой, можно легко переназначить: ему нужно только сохранять точки в памяти, пока они не будут записаны на диск. Единственное другое дополнение - глубина фильтрации. Исходный код, включающий только дальний порог, но на практике наличие опций как ближнего, так и дальнего отсечения может оказаться полезным. Вот модифицированный пример с использованием SPACE
переключать запись, N/n
клавиши для увеличения / уменьшения возле отсечения и F/f
клавиши для увеличения / уменьшения дальнего отсечения:
// Daniel Shiffman //<>//
// Thomas Sanchez Lengeling
// Kinect Point Cloud example
// https://github.com/shiffman/OpenKinect-for-Processing
// http://shiffman.net/p5/kinect/
import org.openkinect.processing.*;
import java.nio.FloatBuffer;
// Kinect Library object
Kinect2 kinect2;
// Angle for rotation
float a = 3.1;
//depth filtering
float depthNear = 700;
float depthFar = 950;
//recording point clouds to disk
boolean isRecording;
ArrayList<ArrayList<PVector>> frames = new ArrayList<ArrayList<PVector>>();
void setup() {
// Rendering in P3D
size(800, 600, P3D);
kinect2 = new Kinect2(this);
kinect2.initDepth();
kinect2.initDevice();
}
void draw() {
background(0);
// Translate and rotate
pushMatrix();
translate(width/2, height/2, 50);
rotateY(a);
// We're just going to calculate and draw every 2nd pixel
int skip = 2;
// Get the raw depth as array of integers
int[] depth = kinect2.getRawDepth();
//create a new point cloud frame - a list of points
ArrayList<PVector> frame = new ArrayList<PVector>();
stroke(255);
beginShape(POINTS);
for (int x = 0; x < kinect2.depthWidth; x+=skip) {
for (int y = 0; y < kinect2.depthHeight; y+=skip) {
int offset = x + y * kinect2.depthWidth;
float depthValue = depth[offset];
//filter based on depth
if(depthValue >= depthNear && depthValue <= depthFar){
//calculte the x, y, z camera position based on the depth information
PVector point = depthToPointCloudPos(x, y, depthValue);
//add the point to the current frame if it's recording
if(isRecording) frame.add(point);
// Draw a point
vertex(point.x, point.y, point.z);
}
}
}
endShape();
popMatrix();
//add the frame to the recording (list of frames) if recording
if(isRecording) frames.add(frame);
fill(255, 0, 0);
text((int)frameRate+"fps\nrecording: " + isRecording + "\ndepthFar: " + depthFar + " depthNear: " + depthNear
+"\nkeys:\nSPACE - toggle recording\nN/n - increase/decrease near clipping\nF/f - increase/decrease far clipping", 50, 50);
// Rotate
//a += 0.0015f;
}
void keyReleased(){
//toggle recording using space
if(key == ' ') {
isRecording = !isRecording;
//if it was recording, but now it's not, there should be some frames there to save
if(!isRecording) saveFramesToDisk();
else frames.clear();//otherwise, there might have been a recording already, so clear any previous frames
}
//modify near/far filters
int depthFilterAmount = 10;//depth filter increment
if(key == 'n') depthNear -= depthFilterAmount;
if(key == 'N') depthNear += depthFilterAmount;
if(key == 'f') depthFar -= depthFilterAmount;
if(key == 'F') depthFar += depthFilterAmount;
}
void saveFramesToDisk(){
//create a timestamp string
String folderName = "rec_"+day()+"-"+month()+"-"+year()+" "+hour()+":"+minute()+":"+second()+":"+millis();
//make a folder with that name
new File(folderName).mkdir();
//count the number of frames
int numFrames = frames.size();
//for each frame
for(int i = 0 ; i < numFrames; i++){
//access the list of points
ArrayList<PVector> frame = frames.get(i);
//make a new text file for each frame - checkout nf() - really handy for naming files sequentially
PrintWriter output = createWriter(folderName+"/frame" + nf(i,4) +".txt");
//for each point in a frame
for (int j = 0; j < frame.size(); j++) {
//retrieve the point
PVector p = frame.get(j);
//write to file: index, x, y,z + new line character
output.println(j + ", " + p.x + ", " + p.y + ", " + p.z );
}
output.flush(); // Write the remaining data
output.close();
}
println("Wrote " + numFrames + " frames in " + folderName);
}
//calculte the xyz camera position based on the depth data
PVector depthToPointCloudPos(int x, int y, float depthValue) {
PVector point = new PVector();
point.z = (depthValue);// / (1.0f); // Convert from mm to meters
point.x = (x - CameraParams.cx) * point.z / CameraParams.fx;
point.y = (y - CameraParams.cy) * point.z / CameraParams.fy;
return point;
}
//camera information based on the Kinect v2 hardware
static class CameraParams {
static float cx = 254.878f;
static float cy = 205.395f;
static float fx = 365.456f;
static float fy = 365.456f;
static float k1 = 0.0905474;
static float k2 = -0.26819;
static float k3 = 0.0950862;
static float p1 = 0.0;
static float p2 = 0.0;
}