有效地将BufferedImage转换为IplImage

时间:2012-01-18 02:09:36

标签: java c++ opencv

我正在尝试有效地将BufferedImage转换为IplImage ...你能否给我一些关于jni部分的提示?

现在我执行以下步骤:

我从BufferedImage获取rgbs并将它们发送到jni代码,我执行以下操作:

IplImage* getIplImageFromIntArray(JNIEnv* env, jintArray array_data,
    jint width, jint height) {
int *pixels = env->GetIntArrayElements(array_data, 0);
if (pixels == 0) {      
    return 0;
}
IplImage *image = loadPixels(pixels, width, height);
env->ReleaseIntArrayElements(array_data, pixels, 0);
if (image == 0) {   
    return 0;
}
return image;}};

IplImage* loadPixels(int* pixels, int width, int height) {
int x, y;
IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
unsigned char* base = (unsigned char*) (img->imageData);
unsigned char* ptr;
for (y = 0; y < height; y++) {
    ptr = base + y * img->widthStep;
    for (x = 0; x < width; x++) {
        // blue
        ptr[3 * x] = pixels[x + y * width] & 0xFF;
        // green
        ptr[3 * x + 1] = pixels[x + y * width] >> 8 & 0xFF;
        // blue
        ptr[3 * x + 2] = pixels[x + y * width] >> 16 & 0xFF;
    }
}
return img;}

但那真的很慢......谢谢你的帮助!

1 个答案:

答案 0 :(得分:1)

使用JavaCV

IplImage.createFrom(aBufferedImage)

编辑:您的代码速度慢的原因有很多。 BufferedImage类是在NIO缓冲区开始之前设计的,因此它使用标准Java数组作为后备缓冲区。无法(安全地)直接从JNI访问Java数组,因此默认情况下,通过调用GetIntArrayElements()的方式,临时分配内存并将数组数据复制到新分配的内存中,而ReleaseIntArrayElements()也会复制数据进入数组,并释放临时分配的内存。并且您还在每次调用时分配一个新的IplImage,并在将所有内容从该临时缓冲区复制到临时IplImage时创建另一个副本。简而言之,您的代码在堆上分配两次内存并将数据复制三次。实现所需效果的推荐方法是使用直接NIO缓冲区从Java内部复制数据一次。您可以通过查看JavaCV源代码的相关部分来检查它的外观,即IplImage.copyFrom(BufferedImage):

http://code.google.com/p/javacv/source/browse/trunk/javacv/src/com/googlecode/javacv/cpp/opencv_core.java#881

它分支到很多特殊情况,但基本上它遍历所有像素以产生副本。添加几个线程以在多个内核上并行循环也可以进一步提高性能......

从Java复制数据后,您可以根据需要直接从本机代码中使用它。