Categories
graphics gui programming vision work

Combining Java's BufferedImage and OpenCV's IplImage

java_opencv_imgHi
I recently did a small project combining a Java web service with a OpenCV processing. I tried to transfer the picture from Java environment (as BufferedImage) to OpenCV (IplImage) as seamlessly as possible. This proved a but tricky, especially the Java part where you need to create your own buffer for the image, but it worked out nicely.
Let me show you how I did it
First up was creating a 3-component RGB BufferedImage in Java, with a custom memory buffer that will fit nicely with IplImages:

private BufferedImage createOpenCVCompatibleBufferedImage(int w, int h)
{
ComponentColorModel cm = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
false,  //no alpha channel
false,  //not premultiplied
ColorModel.OPAQUE,
DataBuffer.TYPE_BYTE); //important - data in the buffer is saved by the byte
SampleModel sm = cm.createCompatibleSampleModel(w, h);
DataBufferByte db = new DataBufferByte(w*h*3); //3 channels buffer
WritableRaster r = WritableRaster.createWritableRaster(sm, db, new Point(0,0));
BufferedImage bm = new BufferedImage(cm,r,false,null);
return bm;
}

This took some trial and error, but I ended up with a working thing.
Now, the C++/OpenCV side of things – a JNI function to read the buffer and do some OpenCV stuff:

JNIEXPORT jint JNICALL Java_test_OpenCVShowImage
(JNIEnv *env, jobject jo, jbyteArray pic, jint w, jint h, jint bpp, jint bpr) {
IplImage* img;
jint len;
unsigned char* result;
int n1;
img = cvCreateImageHeader(cvSize(w,h),8,bpp/8); //create the "shell"
len = (*env)->GetArrayLength(env, pic);
result = (unsigned char *)malloc(len + 1);
if (result == 0) {
fatal_error("out of memory");
(*env)->DeleteLocalRef(env, pic);
return 0;
}
(*env)->GetByteArrayRegion(env, pic, 0, len,(jbyte *)result);
cvSetData(img,result,bpr);    //set the buffer
cvNamedWindow("window");
cvShowImage("window",img);
cvWaitKey(0);
cvDestroyWindow("window");
free(result);
cvReleaseImage(&img);
return 1;
}

One last thing -the Java call to the JNI function:

BufferedImage tmp = ImageIO.read(new File("bird.png"));
BufferedImage bi1 = createOpenCVCompatibleBufferedImage(tmp.getWidth(), tmp.getHeight());
//paint the image with a little transform...
Graphics2D biDestG2D = bi1.createGraphics();
biDestG2D.setColor(Color.white);
biDestG2D.fillRect(0, 0, w, h);
AffineTransform transform = AffineTransform.getShearInstance(0.2, 0.1);
transform.scale(0.5, 0.5);
biDestG2D.drawImage(tmp,transform,null);
biDestG2D.dispose();
byte[] bytes = ((DataBufferByte)bi1.getRaster().getDataBuffer()).getData();
OpenCVShowImage(bytes, w, h, 24, w*3);

That’s all folks!
java_opencv