I think the problem with the framerate is because, from reading his tweets and whatnot, Daniel started working on the processing port before the usblib was patched and is now in the midst of another professional project... so he is prioritizing... too bad for us. I spent a little time trying to update it myself, but i dont have much experience with making .JNILIBs (not to mention im not that smart!) so I reckon he will beat me to it regardless of his other commitments.
But other than the framerate and a pesky memory leak and a few other vestigial remnants from the heady hero-days of DISKinecting the Kinect from the XBOX, its totally useable and fun as hell...
if you got em, throw on ur 3D glasses and take a look:
http://www.screencast.com/users/powderly/folders/Jing/media/3b681624-3468-4c76-abe2-2e098a5b7d0c
DISKinect depthmap to old school dynamic anaglyphic 3D... red-blue and red-cyan modes.
i threw this together tonite in my copious otaku time... it works ok. especially if you tilt your screen... then it pops like Captian EO...
framerate is mud thanks to aforementioned non-patched usblib but the choppiness is really due to the screen recorder (what screen recorder doesnt suck for the mac?)
I'm using the depthmap output because the depthmap pixels and the video input pixels don't align so well... i'm still working on warping/flattening the distortion caused by (i reckon) the IR speckle's corner-stretched throw...
http://www.futurepicture.org/
atleast in my rough estimation, the mis-alignment seems to fit that skew.
maybe that is something the newer patches correct in the library (?). it could be something simpler im not considering. After that's handled, i'll draw on desaturated live video... when i get some proper diopter red-cyan glasses (i had to make my own glasses from acetate hence the red-blue mode) i can do color... multiprojector output would make it possible to do full on polarized 3D...
this is in someway a part of my larger project to waste max time? :) and make In-real-life 4D (IRL4D). 4D cinema is hella popular where i live.
my nights-worth of code, built using other projects on openprocessing, is below if you wanna play with it... but its really just something to give my students an idea what they can do with the kinect (i got my school to buy a few cameras for the students to play with...)
jp
// uses the shiffman.kinect library and a .vlw
- /*
////////////////////////////////////////
DISKinect to 3D
by Powderly, Shiffman, Birtchnell
November 23rd, 2010, 3:09 AM
Seoul, South Korea
Hwaiting!!!!!!!!!!
For Hongik University Interactive Scripting and Interactive Design Studio
Shiffman.kinect by Daniel Shiffman
http://www.shiffman.net/2010/11/14/kinect-and-processing/
OpenKinect by Hector Martin
https://github.com/OpenKinect/libfreenect
OfKinect and the perverse pleasure of kinect on the mac by Theo Watson
http://vimeo.com/16734124
Depth paint by William Birtchnell, licensed under Creative Commons Attribution-Share Alike 3.0 and GNU GPL license.
Work: http://openprocessing.org/visuals/?visualID=10838
License:
http://creativecommons.org/licenses/by-sa/3.0/
http://creativecommons.org/licenses/GPL/2.0/
This code is licensed under (c)rap-in-the-PublicDomain 0.1
http://fffff.at
make your own 3D glasses:
http://stereo.gsfc.nasa.gov/classroom/glasses.shtml
the more you know:
http://en.wikipedia.org/wiki/Anaglyph_image
////////////////////////////////////////
*/
//kinect libraries
import shiffman.kinect.*;
//PImage objects
PImage depthm;
PImage video;
PImage videoBorder; // pimage with border
int border = 60;
//2D array for depth map
int[][] dMap = new int[1000][800];// depth map
int depth;
int maxOffset;
int minOffset;
//font file path and font object
String fontFilePath= "AT.vlw";
PFont theFont;
//variables for loopinbg through pixels array and depth map
int ix,iy;
//offsets to handle image border to avoid array out of bounds exceptions
int xOff,xOff2,yOff;
//PVector variables for our video size and output screen size and windowing
PVector vidSize;
PVector smallVid;
int _red;
int currentBlue;
void setup()
{
vidSize = new PVector(640,480);
smallVid = new PVector(320, 240);
//load and initialize the font
theFont = loadFont(fontFilePath);
textFont(theFont);
//create our screen cast out floats to ints
size((int)vidSize.x,(int)vidSize.y+(int)smallVid.y,P3D);
//like it matters... this library still has a memory leak and usb transfer problems
//we wait for daniel to patch it... if only we were as smart as he we would do it ouselves...
frameRate(30);
//initialize the kinect opbject
NativeKinect.init();
// prefill our array with values... for testing purposes
for (ix=0;ix<1000;ix++){for(iy=0;iy<800;iy++){dMap[ix][iy]=-10;}}
println("init DISKinect");
//intitialize three pimage objects for our live feed, depth map and 3D depthmap
video = createImage((int)vidSize.x,(int)vidSize.y, RGB);
depthm = createImage((int)vidSize.x,(int)vidSize.y, RGB);
//put a border on this one so we dont go out of bounds
videoBorder = createImage((int)vidSize.x+border,(int)vidSize.y+border,RGB);
//initialize out colors
_red = 0xff0000;
currentBlue = 0x00ffff ;
//initialize our 3D offset
depth = 20;
//a value to help us understand the maximum and minimum offsets we get using the dynamicdepth3D function for diagnostics
maxOffset = 0;
minOffset = 24;
println("setup done...");
}
void draw()
{
//updates the kinect objects with data from usblib
NativeKinect.update();
//grab the pixels, update out pimage
video.pixels = NativeKinect.getPixels();
video.updatePixels();
//grab the depthmap from the usblib, update out depthm pimage
depthm.pixels = NativeKinect.getDepthMap();
depthm.updatePixels();
//copy the depthm over to the videoborder image object
videoBorder.copy(depthm, 0, 0, video.width, video.height, border/2, border/2, (int)vidSize.x, (int)vidSize.y);
//load the videoborder image into the system pixelarray pixels[]
loadPixels();
//draw our 3D onto the pimage based on a threshhold value
//depthThresh23D();
//create 3D offset based on depth information
dynamicDepth23D();
//place our images onto the screen
//live video from usblib
image(video,0,(int)vidSize.y,(int)smallVid.x,(int)smallVid.y);
//convert the live video to chunky FFFFFAT colors
depthThresh2Colors();
// draw our depth map on the screen
//image(depthm,(int)smallVid.x,(int)vidSize.y,(int)smallVid.x,(int)smallVid.y);
//draw our FFFFFAT-ified live video on the screen
image(video,(int)smallVid.x,(int)vidSize.y,(int)smallVid.x,(int)smallVid.y);
//write some diagnostic text to the screen
cPanelText();
}
// funtion to desaturate the image
// we dont use this anymore but its there
// yea it could be faster but bitshifting and hex
// tends to cause my students to space out and
// start checking their email in class
void desaturate(PImage pImg){
for(int x=0; x<pImg.width; x++)
{
for(int y=0; y<pImg.height; y++)
{
color c = pImg.get(x,y);
float red = red(c);
float green = green(c);
float blue = blue(c);
int grey = (int)(red+green+blue)/3;
color Color =color(grey,grey,grey);
pImg.set(x,y,Color);
}
}
}
// function to draw out red-cyan 3D onto the image
void depthThresh23D(){
int thresh = 75;
// draw our 3D onto the image thank to Birtchnell
for (iy=0;iy<(int)vidSize.y;iy++){
int xOff = iy*(int)vidSize.x;
int xOff2 = (iy+border/2)*videoBorder.width;
for (ix=0;ix<(int)vidSize.x;ix++){
//revers the logic and raise the min thresh to get a surface level forground image
//if(green(videoBorder.pixels[xOff2+ix+border/2])>20 && green(videoBorder.pixels[xOff2+ix+border/2])<thresh ){
if(green(videoBorder.pixels[xOff2+ix+border/2])>thresh){
pixels[xOff+ix]= (videoBorder.pixels[xOff2+ix+border/2+depth] & _red) | (videoBorder.pixels[xOff2+ix+border/2-depth] & currentBlue);
}else {
pixels[xOff+ix]= videoBorder.pixels[xOff2+ix+border/2] ;
}
}
}
}
// function to draw out red-cyan 3D onto the image
void dynamicDepth23D(){
// draw our 3D onto the image thank to Birtchnell
for (iy=0;iy<(int)vidSize.y;iy++){
int xOff = iy*(int)vidSize.x;
int xOff2 = (iy+border/2)*videoBorder.width;
for (ix=0;ix<(int)vidSize.x;ix++){
//test for min depth requirement to become 3D
if(green(videoBorder.pixels[xOff2+ix+border/2])>20){
//create depth from depthmap field
int tempinput = (int)green(videoBorder.pixels[xOff2+ix+border/2]);
//adjust range for a reasonable offset
depth = (int)map(tempinput, 30, 255, 0, 25);
//constrain to positive numbers within our offset range
depth = constrain(depth, 0, 25);
pixels[xOff+ix]= (videoBorder.pixels[xOff2+ix+border/2+depth] & _red) | (videoBorder.pixels[xOff2+ix+border/2-depth] & currentBlue);
}else{
pixels[xOff+ix]= videoBorder.pixels[xOff2+ix+border/2] ;
}
//calculate max and min for diagnostics
maxOffset= calculateMax(depth, maxOffset);
minOffset= calculateMin(depth, minOffset);
}
}
}
//fucntion to set the 3D mode to red-blue 3D glasses or red-cyan 3D glasses
void keyPressed(){
if(key=='c'){
currentBlue = 0x00ffff;
}else if(key=='b'){
currentBlue = 0x0000ff;
} else if (keyCode == LEFT){
depth--;
} else if (keyCode == RIGHT){
depth++;
}
}
// function to pimp out (ie, slow down frame rate of) the live video with 0xff00ff and 0xfff000 and 0x000fff (FFFFFAT) colors
//not fast, not smart, just understandable to 20 year old design students
//also useful in understanding the distortion between the live video signal and the depth map
//due to the way the laser scanner speckle has a skewed throw
// http://www.futurepicture.org/
void depthThresh2Colors(){
int index=0;
color front = 0xff00ff;
color middle = 0x00ffff;
color back = 0xfff000;
int fthresh = 75;
int mthresh = 20;
int bthresh = 0;
for(int y=0;y<(int)vidSize.y;y++){
for(int x=0;x<(int)vidSize.x;x++){
if(green(depthm.pixels[index])>=fthresh){
video.pixels[index]= front;
}
if((green(depthm.pixels[index])>=mthresh) && (green(depthm.pixels[index])<fthresh)){
video.pixels[index]= middle;
}
if((green(depthm.pixels[index])>=bthresh) && (green(depthm.pixels[index])<mthresh)){
video.pixels[index]= back;
}
index++;
}
}
}
int calculateMax(int inVal, int inMax){
inMax = max(inVal, inMax);
return inMax;
}
int calculateMin(int inVal, int inMin){
inMin = min(inVal, inMin);
return inMin;
}
void cPanelText(){
pushMatrix();
fill(150);
textSize(15);
text("fps = " + frameRate, 20, height- 35);
text("depth = " + depth, 20, height-20);
text("min = " + minOffset + " " + "max = " + maxOffset, 20, height-5);
popMatrix();
}