I’m trying to do efficiently convert a BufferedImage to an IplImage… could you give me any hint about the jni part?
Right now I do these steps:
I get the rgbs from the BufferedImage and I send them to the jni code where I do the following:
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;}};
and
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;}
But that is really slow… thank you for your help!
With JavaCV:
EDIT: There are a couple of reasons why your code is slow. The BufferedImage class was designed before NIO buffers came into fashion, so it uses standard Java arrays as backing buffer. Java arrays cannot be (safely) accessed directly from JNI, so by default, with the way you call GetIntArrayElements(), memory gets temporarily allocated and the array data gets copied into that new allocated memory, while ReleaseIntArrayElements() also copies back the data into the array, and frees the temporary allocated memory. And you also allocate a new IplImage on every call and make another copy when copying everything from that temporary buffer to the temporary IplImage. In a nutshell, your code allocates memory twice on the heap and copies the data three times. The recommended way to achieve the desired effect is instead to copy the data only once from inside Java, using direct NIO buffers. You can check what this looks like by peering into the relevant portion of the JavaCV’s source code, namely IplImage.copyFrom(BufferedImage):
http://code.google.com/p/javacv/source/browse/trunk/javacv/src/com/googlecode/javacv/cpp/opencv_core.java#881
It branches into a lot of special cases, but basically it loops over all pixels to produce the copy. Adding a couple of threads to loop in parallel on multiple cores could also improve performance further…
After copying the data from Java, you may then use it directly from your native code if desired.