How to create a BufferedImage from data recived over serial port - java

I'm working on a project in which I have to get image from camera (cmucam4) which is connected to my computer with Xbee.
The probleme is that I can get the image data over the serial port, but when I save it as a file, the file can't be openned as image.
I noticed that when I open the file with notepad++, the file does not have a header like other images (the camera send bmp image).
I tried to save the Image using ImageIO, but I dont know how to pass the data recived to the image!!
BufferedImage img = new BufferedImage(640, 480,BufferedImage.TYPE_INT_RGB);
ImageIO.write(img, "BMP", new File("img/tmp.bmp"));

If the camera truly sends BMP format, you could just write the data to disk. However, more likely (and this seems to be the case, reading the specs from your link), the cards sends a raw bitmap, which is not the same.
Using this info from the card spec PDF:
Raw image dumps over serial or to flash card
(640:320:160:80)x(480:240:120:60) image resolution
RGB565/YUV655 color space
The RGB565 pixel layout mentioned above should match perfectly with the BufferedImage.TYPE_USHORT_565_RGB, so that should be the easiest to use.
byte[] bytes = ... // read from serial port
ShortBuffer buffer = ByteBuffer.wrap(bytes)
.order(ByteOrder.BIG_ENDIAN) // Or LITTLE_ENDIAN depending on the spec of the card
.asShortBuffer(); // Our data will be 16 bit unsigned shorts
// Create an image matching the pixel layout from the card
BufferedImage img = new BufferedImage(640, 480, BufferedImage.TYPE_USHORT_565_RGB);
// Get the pixel data from the image, and copy the data from the card into it
// (the cast here is safe, as we know this will be the case for TYPE_USHORT_565_RGB)
short[] data = ((DataBufferUShort) img.getRaster().getDataBuffer()).getData();
buffer.get(data);
// Finally, write it out as a proper BMP file
ImageIO.write(img, "BMP", new File("temp.bmp"));
PS: The above code works for me, using a byte array of length 640 * 480 * 2, initialised with random data (as I obviously don't have such a card).

Related

Bytearray converted from Mat in Java to Image from Socket in Python

Im working on an Application were I get an image in Opencv Mat format from a Webcam in a Java Client and have to process this image on a python server.
Therefore I`m sending a bytearray to the python server. I´m encoding the Image in Java like this:
private VideoCapture capture = new VideoCapture();
...
this.capture.read(frame);
if (!frame.empty()) {
byte[] return_buff = new byte[(int) (frame.total() *
frame.channels())];
frame.get(0, 0, return_buff);
...
After that I send it through a Socket using a DataOutputStream. When I echo it back to the Java Client the bytedata seems to have been transferred correctly and entirely. In Python I then tried to decode it with PIL
img = Image.open(BytesIO(data))
And yes I already import PIL like suggested here: PIL: Convert Bytearray to Image
But Im still getting this Error:
img = Image.open(BytesIO(data))
File "/root/.local/lib/python2.7/site-packages/PIL/Image.py", line 2590, in
open % (filename if filename else fp))
IOError: cannot identify image file
Do I have to change the way I assembled my bytearra or do I have to encode it in a different way?
Solved it! The thing is that Image.open(BytesIO(data)) apparently expects the data to have some kind of header to describe the image type and was therefore unfitting for a mat converted to bytes because a Mat appears to have no kind of header integrated, just the plain image data. In python an Image from a Mat bytearray can be derived using the following:
img = cv2.imdecode(bytearray, flag)
with flag being a number representing the cvtype of the image.

Does ImageIO.read() take EXIF orientation metadata into account?

In JPEG images, EXIF metadata is sometimes included and tells in what orientation the image should be shown.
The question is, whether Java's ImageIO.read() takes EXIF into account while reading a JPEG image, and automatically applies the transformation.
More concretely, if I use Java's ImageIO for converting a JPEG image with EXIF into a PNG image, is the orientation of the PNG image going to be correct? Or is the below code going to produce a PNG image without taking EXIF orientation instructions into account?
private byte[] convertToPng(byte[] imageFileAsByteArray) {
ByteArrayInputStream bis = new ByteArrayInputStream(imageFileAsByteArray);
BufferedImage bi = ImageIO.read(bis);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(bi, "png", bos);
return bos.toByteArray();
}
The short answer is, unfortunately, no; ImageIO.read(..) (by default) does not take the Exif Orientation tag into account. Your PNG will be not be rotated accordingly.
However, all ImageIO.read(..) does internally, is to look up an appropriate ImageReader plug-in for the input, and delegate reading to it. And while the JRE-bundled plug-in does not take Exif into account, it is possible to add support for it, in a third-party ImageReader. Unfortunately, I don't know of any that do, but I am considering adding Exif orientation support to the TwelveMonkeys ImageIO JPEGImageReader in the future.
In the mean time, you have to apply the rotation yourself, by reading the metadata and rotating. The value of the orientation tag can be acquired either using the ImageIO JPEG metadata or some third-party library. I think both the mentioned metadata-extractor or TwelveMonkeys ImageIO can be used for this purpose. JAI ImageIO (using the TIFF metadata) can probably also do this.
If using the ImageIO JPEG metadata, be aware:
Note that an application wishing to interpret Exif metadata given a metadata tree structure in the javax_imageio_jpeg_image_1.0 format must check for an unknown marker segment with a tag indicating an APP1 marker and containing data identifying it as an Exif marker segment.
I have struggled with jpeg exif orientation for awhile, and now that I set out to fix my problems, I find that they are gone. To make sure for myself, I simplified OP.s example so as to read
public static void main (String [] args) throws Exception {
java.io.File in = new java.io.File ("in.jpg");
java.io.File out = new java.io.File ("out.png");
BufferedImage image = ImageIO.read (new FileInputStream(in));
ImageIO.write (image, "png", out);
}
in.jpg is a picture with exif orientation tag 8, tilted to the left. When I run the example, out.png is created as a properly oriented png picture. So it seems that ImageIo has learned something recently.

Writing JPEG image in java as uncompressed still destroys data

I was making an application that hides data in LSBs of a JPEG image. Knowing that JPEG is a lossy compression and has a default compression of 70%, I changed it's parameters to 100% thus assuming that it wont destroy any data in the image. Here is the code.
File output = new File(gui.getOutput()+".jpg");
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(1f);
FileImageOutputStream outputStream = new FileImageOutputStream(output);
jpgWriter.setOutput(outputStream);
IIOImage outputImage = new IIOImage(image, null, null);
jpgWriter.write(null, outputImage, jpgWriteParam);
jpgWriter.dispose();
The image that was created was indeed loss less, but the data I stored within the pixels were destroyed. (I checked it by reading the inserted data in the LSB and it wasn't the data I stored in the image).
What should I do to avoid the data being destroyed?
A must read api, and it only applies to quantization step

Inserting 1 MB image in neo4j returns a different size (536 KB) when retrieved

I am trying to insert a 1 MB image inside neo4j using the following code:
File fnew = new File("C:\\Users\\myimage.jpg");
BufferedImage originalImage = ImageIO.read(fnew);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.flus();
ImageIO.write(originalImage, "jpg", baos);
return baos.toByteArray();
Then I insert this byte array using:
user.setProperty("photo", photo);
This all goes fine. When I try to select the photo, using the following method, it writes it on my hard drive disk as 536KB instead of the 1 MB original size.
byte[] imageInByte = (byte[]) user.getProperty("photo");
InputStream in = new ByteArrayInputStream(imageInByte);
BufferedImage bImageFromConvert = ImageIO.read(in);
ImageIO.write(bImageFromConvert, "jpg", new File("C:\\newimage.jpg"));
Now the weird part: I can see the image, open it, same resolution, I don't see any difference in terms of quality though. Looks like it is compressed.
Why is this happening?
Saving a jpg image through ImageIO results in lossy compression of the jpg (I believe the quality defaults to 70%). You can a) Change the the quality of the image when you write to file (see Setting jpg compression level with ImageIO in Java ) or b) if you don't actually need the BufferedImage, just read/write the bytes from file to database.

How to read Bytes of an Image in Java?

I am currently working with Image processing in Java. Initially I used ImageIO class to write images
ImageIO.write(image,"jpg",os);
the problem with this method is am lossing the actual image size and quality. Then I preferred ByteStream
Files.readAllBytes(fi.toPath());
to read and
fos.write(fileContent);
to write Images. This works perfectly. The issue I am facing here is I can read only files but not Images(ie, BuffreredImage image). Is it possible to read a Image rather than files here or should I move to someother IO?
Code Snippet is here,
try {
File fnew=new File("d:\\3\\IMG1.jpg");
java.io.FileOutputStream fos = new java.io.FileOutputStream(new File("d:\\3\\Test1\\4.jpg"));
File fi = new File("d:\\3\\7.jpg");
byte[] fileContent = Files.readAllBytes(fi.toPath());
fos.write(fileContent);
} catch (Exception e) {
System.out.println("Exception");
}
Any Kind of suggestions or help will be appreciated. Thanks in Advance.
the problem with this method is am lossing the actual image size and quality. Then I preferred ByteStream
When you read a JPEG with with ImageIO, it is converting the JPEG to a Bitmap automatically. Then when you write it, it is encoding to a JPEG again (which loses quality).
Just replace ImageIO.write(image,"jpg",os) with ImageIO.write(image,"png",os) and you are done. A lossless format such as PNG will not lose any data when you write the image.
BufferedImage getRGB() will get you all the actual pixel data for the image. There will be no compression or anything like JPEG. It will be the raw image.
Edited to add an example based on my comments...
BufferedImage image = ImageIO.read(new File("google.jpg"));
ImageWriter w = ImageIO.getImageWritersBySuffix("jpg").next();
ImageOutputStream out = ImageIO.createImageOutputStream(new File("output.jpg"));
w.setOutput(out);
ImageWriteParam param = new JPEGImageWriteParam(Locale.getDefault());
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(1);
w.write(null, new IIOImage(image, null, null), param);
out.close();

Categories