Hi
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!
5 replies on “Combining Java's BufferedImage and OpenCV's IplImage”
[…] the brilliant picture is from here. […]
I do use use opencv-java-processin.org library ( http://ubaa.net/shared/processing/opencv/ + processing.org libraries ) that can create Processing Image (PImage) and convert this into opencv image …
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..
Exactly what I was looking for! Thanks a lot!!! 🙂
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