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!