Convert OpenCV Mat object to BufferedImage - java

I am trying to create a helper function using OpenCV Java API that would process an input image and return the output byte array. The input image is a jpg file saved in the computer. The input and output image are displayed in the Java UI using Swing.
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// Load image from file
Mat rgba = Highgui.imread(filePath);
Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGB2GRAY, 0);
// Convert back to byte[] and return
byte[] return_buff = new byte[(int) (rgba.total() * rgba.channels())];
rgba.get(0, 0, return_buff);
return return_buff;
When the return_buff is returned and converted to BufferedImage I get NULL back. When I comment out the Imgproc.cvtColor function, the return_buff is properly converted to a BufferedImage that I can display. It seems like the Imgproc.cvtColor is returning a Mat object that I couldn't display in Java.
Here's my code to convert from byte[] to BufferedImage:
InputStream in = new ByteArrayInputStream(inputByteArray);
BufferedImage outputImage = ImageIO.read(in);
In above code, outputImage is NULL
Does anybody have any suggestions or ideas?

ImageIO.read(...) (and the javax.imageio package in general) is for reading/writing images from/to file formats. What you have is an array containing "raw" pixels. It's impossible for ImageIO to determine file format from this byte array. Because of this, it will return null.
Instead, you should create a BufferedImage from the bytes directly. I don't know OpenCV that well, but I'm assuming that the result of Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGB2GRAY, 0) will be an image in grayscale (8 bits/sample, 1 sample/pixel). This is the same format as BufferedImage.TYPE_BYTE_GRAY. If this assumption is correct, you should be able to do:
// Read image to Mat as before
Mat rgba = ...;
Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGB2GRAY, 0);
// Create an empty image in matching format
BufferedImage gray = new BufferedImage(rgba.width(), rgba.height(), BufferedImage.TYPE_BYTE_GRAY);
// Get the BufferedImage's backing array and copy the pixels directly into it
byte[] data = ((DataBufferByte) gray.getRaster().getDataBuffer()).getData();
rgba.get(0, 0, data);
Doing it this way, saves you one large byte array allocation and one byte array copy as a bonus. :-)

I used this kind of code to convert Mat object to Buffered Image.
static BufferedImage Mat2BufferedImage(Mat matrix)throws Exception {
MatOfByte mob=new MatOfByte();
Imgcodecs.imencode(".jpg", matrix, mob);
byte ba[]=mob.toArray();
BufferedImage bi=ImageIO.read(new ByteArrayInputStream(ba));
return bi;
}

Related

Image generation failure through modified byte array using both java and opencv?

In my program I am reading an image using java, taking its byte array and applying modifications to it by applying random functions. Now during the entire process the size of array is maintained but when I am trying to construct an image using the byte array an empty image is obtained. I have tried using both java and opencv to reconstruct the image (the image is grayscale image of 440*442 size .png type).
opencv code:
byte[] bytesArrayForImage=new byte[array.length];
for (int i=0; i<array.length; i++) {
bytesArrayForImage[i] = (byte) Integer.parseInt(array[i]);
}
Mat mat = new Mat(440,442, CvType.CV_8UC1);
mat.put(0,0, bytesArrayForImage);
String filename111 = Path;
Highgui.imwrite(filename111, mat);
java code:
BufferedImage image=ImageIO.read(new ByteArrayInputStream(bytearray));
ImageIO.write(image, "png", new File(C:\\Users\\domin\\Desktop\\Sop\\,"modified.png"));

Compressing a multi-page tiff image with lossy jpeg

I need to compress a tif file that has several gray 16bit images (multi-page). I have tried working with ImageIO as here: Tiff compression using Java ImageIO Initially, each image that will be in the tif file comes from another tiff file. When I want to use the compressors, I have the following options:
CCITT RLE, CCITT T.4, CCITT T.6: They give me the error: "javax.imageio.IIOException: I/O error writing TIFF file!"
LZW. I cannot use it. My images are 16bit and LZW increases the size of 16bit images
JPEG. Not possible for 16bit images.
ZLIB. It only reduces 10% even if I specify setCompressionQuality(0.0f);
PackBits. Does not compress.
Deflate. Like ZLIB.
EXIF JPEG. It gives me the error: "javax.imageio.IIOException: Old JPEG compression not supported!"
Does any know any other alternative? I saw an apache imaging library but the tif compression only support the above or less options. Does anyone know about JPEG2000 compressor? Any other kind of alternative?
PNG compresses 16-bit images losslessly. Libraries and utilities are widely available. JPEG2000 has a lossy 16-bit mode, but you'd have to find some software that supports it. Open JPEG might.
However I'd have to ask: what are your criteria for when you have acceptable image quality and when you do not? If it is visual, then you likely end up at normal JPEG anyway, with a good bit less than 8 bits per pixel effective.
Reducing the image 16 bit to 8 bit. Consider that you have a byte[] variable plane16 where you have all the pixels of your image.
Note: My byte[] plane16 gets the data from a 16bit image but byte is 8bit=1byte. Therefore, 2 elements in row of this array are 2byte = 16bit. That is why I convert it to a short[] before operating. If you start from a short[], ommit "ByteBuffer.wrap(plane16).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);"
byte[] plane16; //Fill it with your image!!!
//Do stuff with imageIO. Set writer and compresion method
ImageIO.scanForPlugins();
TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
javax.imageio.ImageWriter writerIO = tiffspi.createWriterInstance();
ImageWriteParam param = writerIO.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("ZLib");
param.setCompressionQuality(0.5f);
File fOutputFile = new File(route+".tif");
ImageOutputStream ios = ImageIO.createImageOutputStream(fOutputFile);
writerIO.setOutput(ios);
//Reducing 16bit to 8bit
short[] shorts = new short[plane16.length/2];
ByteBuffer.wrap(plane16).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
int max = 0;
int min = 999999;
for (int v = 0; v<shorts.length;v++){
if (max<shorts[v]) max = shorts[v];
if (min>shorts[v]) min = shorts[v];
}
double range = 255./(max-min);
byte[] plane8 = new byte[shorts.length];
for (int v = 0; v<plane8.length;v++){
plane8[v] = (byte) ((shorts[v]+min)*range - 128);
}
//16bit:
/*BufferedImage convertedGrayscale = new BufferedImage(width,
heigth, BufferedImage.TYPE_USHORT_GRAY);
convertedGrayscale.getRaster().setDataElements(0, 0, width,
heigth, shorts);*/
//8bit:
BufferedImage convertedGrayscale = new BufferedImage(width,
heigth, BufferedImage.TYPE_BYTE_GRAY);
convertedGrayscale.getRaster().setDataElements(0, 0, width,
heigth, plane8);
//Save image
//If you have a stack of images in tiff, do this trick. "image" is the image number you are setting inside the tiff. If you only have 1 image, remove the if and take the expression from the else.
if (image!=0){
writerIO.writeInsert(image, new IIOImage(convertedGrayscale, null, null), param);
}else{
writerIO.write(null, new IIOImage(convertedGrayscale, null, null), param);
}
//do the next only after the last image to be saved
writerIO.dispose();
ios.flush();
ios.close();

byte[] to bufferedImage conversion gives null

I am trying to convert byte[] array to buffered image so than i can resize the image..but problem is conversion always turned into null.here is my code..
ByteArrayInputStream bais = new ByteArrayInputStream(user.getUser_image());
//Here user.getUser_image() returns byte[] returned from server..
try {
BufferedImage image = ImageIO.read(bais);
System.out.println("============><================"+image);//Here it prints null
BufferedImage scaledImage = Scalr.resize(image,48);
}
.....and so on
It means that the ImageIO class is not able to select an appropriate ImageReader. The purpose of this could be corrupted byte array or unsupported image type. Try to debug it.

Write CMYK image in PDF

I need to add a CMYK Image (java.awt.BufferedImage) to a Pdf-Document with iText.
I'm trying to do it with:
com.lowagie.text.Image img = Image.getInstance(BufferedImage, bgColor);
This produces an RGB image in the resulting PDF. (and I suppose it's a bug, because it just ignores ColorModel). However I could use:
com.lowagie.text.Image img = Image.getInstance(byte[] rawData);
And it produces a correct CMYK-Image in PDF. But for the second case I need to convert java.awt.BufferedImage in ByteArray. I cannot do it with ImageIO.write(ByteArrayOutputStream). I also cannot do it with com.sun.image.codec.jpeg.JPEGImageEncoder because I must use OpenJDK.
Any ideas how can I achieve the correct behavior to write a CMYK image in PDF using iText?
So basically what you're asking is how to convert a BufferedImage to a byte[] to print to PDF?
BufferedImage img; // your image to be printed
String formatName; // name of the image format (see ImageIO docs)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write( img, formatName, baos);
byte[] rawData = baos.toByteArray();
You should be able to use that for the CMYK-image as you had in your original post:
com.lowagie.text.Image img = Image.getInstance(byte[] rawData);

How do I convert byte[] to Bitmap?

Let's say I have a byte buffer and how do I get Bitmap?
If you want to manipulate the image, use ImageIO. It creates a format-agnostic image in memory:
BufferedImage img = ImageIO.read(new ByteArrayInputStream(bytes));
If you just want to store in to disk, then simply write the byte array to a file.
Note that the byte array must be already a bitmap image, you can't take any byte array and have it as bitmap.
And you get the byte array from the byte buffer by:
byte[] bytes = new byte[buf.capacity()];
buf.get(bytes, 0, bytes.length);

Categories

Resources