The java wrapper for OpenNI that is included in version v1.3.2.3 comes with one significant drawback: It provides only a quite memory consuming way to access image data.

Images are stored in objects of type org.OpenNI.Map, which provide a createByteBuffer() method defined as follows:

protected ByteBuffer createByteBuffer()
{
int size = this.xRes * this.yRes * this.bytesPerPixel;
ByteBuffer buffer = ByteBuffer.allocateDirect(size);
buffer.order(ByteOrder.LITTLE_ENDIAN);
NativeMethods.copyToBuffer(buffer, this.ptr, size);
return buffer;
}


Each time an image frame is accessed, a new buffer is allocated and the image content is copied into that buffer. If you process a VGA org.OpenNI.ImageMap, a org.OpenNI.DepthMap and a org.OpenNI.SceneMap as provided by the Kinect sensor each frame, you will end up with about 62 Megabyte of newly allocated memory each second. Of course this keeps the garbage collector busy all the time, which slows down your program every few seconds.

A preferred way would be to allocate the buffer just once, and fill it each frame. A quick hack to do this is to add the following class to your project (also using that namespace), which exposes the private native copyToBuffer function to your code.

package  org.OpenNI ;

import  java.nio.ByteBuffer ;

public  class NativeAccess {
static public void copyToBuffer (ByteBuffer buffer, long ptr, int size)  {
NativeMethods.copyToBuffer(buffer, ptr, size) ;
}
} ;


If you are using JavaCV, you probably want to have the image written into an IplImage, which can be done the following way.

// Create image
IplImage iplRgbImage = IplImage.Create(640, 480, IPL_DEPTH_8U, 3);

// Fill image
ImageMap imageMap = imageGenerator.getImageMap();
ByteBuffer ptr, 640 * 480 * 3) ;
byteBuffer.Rewind();

Without this optimization, the code would be the following.

// Create image
IplImage iplRgbImage = IplImage.Create(640, 480, IPL_DEPTH_8U, 3);

// Fill image
ImageMap imageMap = imageGenerator.getImageMap() ;
ByteBuffer iplByteBuffer = iplRgbImage.getByteBuffer() ;
ByteBuffer niByteBuffer = imageGenerator.getImageMap().createByteBuffer();
iplByteBuffer.put(niByteBuffer);

Besides discharging the GC, the optimized code also runs a little bit faster, as the image only needs to be copied once and not twice. On my machine the optimized version runs in 0.79 ms, while the unoptimized version runs in 1.73 ms.