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

5 replies on “Combining Java's BufferedImage and OpenCV's IplImage”

Hello, nice work. Can you send instructions how to compile it. (Preferably Mac os)
I’m struggling to do so, but no success. Any help is appreciated..

Hi,
tnx, for that solution. with playing a little bit around I got it also working with that code:
Java Code:
final BufferedImage img = ImageIO.read(new File(“test.jpeg”));
openCv.showImage(img.getWidth(), img.getHeight(), img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth()));
C++ Code:
JNIEXPORT void JNICALL Java_at_test_opencv2java_OpenCV2Java_showImage
(JNIEnv* env, jobject, jint width, jint height, jintArray rgbArray)
{
jint *carr;
carr = env->GetIntArrayElements(rgbArray, NULL);
if (carr == NULL) {
return; /* TODO: exception occurred */
}
Mat img(height, width, CV_8UC4, carr);
cv::imshow( “result”, img);
env->ReleaseIntArrayElements(rgbArray, carr, 0);
cv::waitKey(1);
}
br,
Horst

Leave a Reply

Your email address will not be published. Required fields are marked *