0

我对使用 Java、Kinect (OpenNI) 和 Processing 的实际项目有疑问。
如果我只使用 Processing 和 Java 一切正常,没有什么是绊脚石,我也没有例外。
但是,如果我将处理 Applet 放入 JFrame 中(以解决 Applet 处理方式的一些问题),我会遇到以下问题:

  • 每隔 3 秒,kinect 图像就会很快挂起(看起来 Java 正在使用垃圾收集器清除内存中的任何内容)
  • 20 秒后应用程序停止,我收到以下错误:

    Exception in thread "Animation Thread" java.lang.OutOfMemoryError: Java heap space
    at java.awt.image.DataBufferInt.<init>(Unknown Source)
    at java.awt.image.Raster.createPackedRaster(Unknown Source)
    at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
    at java.awt.image.BufferedImage.<init>(Unknown Source)
    

这是我关于可视化的相关代码:

public boolean drawGrayscaleImage(){    

    //init PApplet and build JFrame
    GrayscalePApplet grayscalePApplet = new  GrayscalePApplet ();
    grayscalePApplet.init();        
    this.grayscaleJFrame = this.initFrame(grayscalePApplet);

    //Set Uplink for PApplet and begin drawing
    grayscalePApplet.setGraphicP(this);     

    return false;
}

这里是处理 PApplet 类的绘图函数

public void draw(){

    if(graphicP != null){
        //creat the relevant image Buffers for java and Processing
        BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_BYTE_GRAY);           
        PImage pimage = new PImage(image.getWidth(),image.getHeight(),PConstants.ARGB);

        //fill up the databuffer using a converted Kinect Grayscale Image
        DataBufferByte dataBuffer = new DataBufferByte(graphicP.getImage(ImageType.GRAYSCALE), this.imageWidth * this.imageHeight);
        Raster raster = Raster.createPackedRaster(dataBuffer,imageWidth, imageHeight, 8, null);
        image.setData(raster);

        //draw image to Processing
        image.getRGB(0, 0, pimage.width, pimage.height, pimage.pixels, 0, pimage.width);
        pimage.updatePixels();
        image(pimage, 0, 0);

        // null everything to get Garbagecollection to work (?)
        image = null;
        pimage = null;
        dataBuffer = null;
    }
}

如何防止 OutOfMemory 异常?
什么可能导致该异常?

4

1 回答 1

0

由于我看不到完整的代码,我无法做出准确的假设,但我的猜测是问题出在这里:

BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_BYTE_GRAY);           
        PImage pimage = new PImage(image.getWidth(),image.getHeight(),PConstants.ARGB);

        //fill up the databuffer using a converted Kinect Grayscale Image
        DataBufferByte dataBuffer = new DataBufferByte(graphicP.getImage(ImageType.GRAYSCALE), this.imageWidth * this.imageHeight);
        Raster raster = Raster.createPackedRaster(dataBuffer,imageWidth, imageHeight, 8, null);
        image.setData(raster);

我不确定您使用的是什么 Kinect API(OpenNI/libfreenect),但无论如何,您可能不应该每帧多次创建新图像(就像您在 中所做的那样draw())。图像会很快填满内存,您不需要始终使用多个图像,您只需要不断更新的两个图像。例如,您初始化图像一次,setup()然后更新这些图像的像素draw()

此外,如果您使用的是 Processing,我建议您查看 Kinect 处理包装库,例如用于OpenNI的 SimpleOpenNI 或用于 libfreenect 的dLibs (Win)/ OpenKinect。使用以下任何一种显示深度图像要简单得多:

使用 SimpleOpenNI:

import SimpleOpenNI.*;

SimpleOpenNI  ni;

void setup(){
  ni = new SimpleOpenNI(this);
  ni.enableDepth()
  size(ni.depthWidth(), ni.depthHeight()); 
}

void draw(){
  ni.update();
  image(context.depthImage(),0,0);
}

使用 dLibs freenect:

import dLibs.freenect.toolbox.*;
import dLibs.freenect.constants.*;
import dLibs.freenect.interfaces.*;
import dLibs.freenect.*;

Kinect kinect;                     // main kinect-object
KinectFrameDepth kinectDepth;     // depth frame
PImage depthFrame;

void setup(){
  size(640,480);
  kinect = new Kinect(0);
  kinectDepth = new KinectFrameDepth(DEPTH_FORMAT._11BIT_);// create a depth instance
  kinectDepth.connect(kinect);  //connect the created depth instance to the main kinect
  depthFrame = createImage(DEPTH_FORMAT._11BIT_.getWidth(), DEPTH_FORMAT._11BIT_.getHeight(), RGB);
}
void draw(){
  assignPixels(depthFrame, kinectDepth);
  image(depthFrame, 0, 0);
}
void assignPixels(PImage img, Pixelable kinectDev){
  img.loadPixels();
  img.pixels = kinectDev.getPixels();  // assign pixels of the kinect device to the image
  img.updatePixels();
}
void dispose(){
  Kinect.shutDown(); 
  super.dispose();
}

使用 OpenKinect P5:

import org.openkinect.*;
import org.openkinect.processing.*;

Kinect kinect;

void setup() {
  size(640,480);
  kinect = new Kinect(this);
  kinect.start();
  kinect.enableDepth(true);
}

void draw() {
  background(0);
  image(kinect.getDepthImage(),0,0);
}

void stop() {
  kinect.quit();
  super.stop();
}

这取决于您需要什么操作系统和什么功能来为您选择正确的处理包装器。

简单的openni SimpleOpenNI 示例

diwi dlibs dLibs_freenect

OpenKinect P5 OpenKinect P5

于 2012-11-15T00:14:09.993 回答