Write GeoTIFF metadata from one file to other - java

My task is to take one GeoTIFF, make some image segmentation on in, and save it to new GeoTIFF(with existing coordinates). If I understand correctly, the coordinates are preserved in GeoTIFF metadata.
So I grab metadata from the original file:
File file = new File(inputFilePath);
ImageInputStream iis = ImageIO.createImageInputStream(file);
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
IIOMetadata metadata=null;
ImageReader reader=null;
if (readers.hasNext()) {
// pick the first available ImageReader
reader = readers.next();
// attach source to the reader
reader.setInput(iis, true);
// read metadata of first image
metadata = reader.getImageMetadata(0);
}
And when I do
System.out.println("Metadata: "+metadata);, I see the correct XML tree of metatags.
So I'm do some magic with image
System.out.println("Starting segmentation");
BufferedImage image = UtilImageIO.loadImage(inputImage);
// Select input image type. Some algorithms behave different depending on image type
ImageType<MultiSpectral<ImageFloat32>> imageType = ImageType.ms(3, ImageFloat32.class);
ImageSuperpixels alg = FactoryImageSegmentation.fh04(new ConfigFh04(500, 30), imageType);
// Convert image into BoofCV format
ImageBase color = imageType.createImage(image.getWidth(), image.getHeight());
ConvertBufferedImage.convertFrom(image, color, true);
// Segment and display results
performSegmentation(alg, color);
System.out.println("Segmentation finished");
In result I obtain a BufferedImage(resultBufferedImage) with successfully image segmentation.
And here starts my problems, I'm trying to save this BufferedImage with old metadata:
BufferedOutputStream out;
ImageWriter writer = ImageIO.getImageWriter(reader);
ImageOutputStream imgout = null;
FileOutputStream fos =null;
fos = new FileOutputStream(outputImage);
out = new BufferedOutputStream(fos);
imgout = ImageIO.createImageOutputStream(out);
writer.setOutput(imgout);
ImageWriteParam param = writer.getDefaultWriteParam();
IIOImage destIIOImage = new IIOImage(resultBufferedImage, null, metadata);
System.out.println("Before write");
writer.write(null, destIIOImage, null);
System.out.println("After write");
I get printed "After write". But program is still running, I tried to wait, but no results. So when I kill process the file is created successfully, even with geodata. How can I determine the finish of writing and stop program?
p.s. Image in default Ubuntu viewer seems to be nice, but when I opened it in QGIS I have transparent fields, and how can I make gray background transparent?

Not a real answer, but here's two answers on how to make a TIFF transparent:
QGis problem with raster transparent
How to make transparent the background of a topographic map in QGis 1.8.0?

Related

Issue with converting an ArrayList of BufferedImages to a GIF using GifSequenceWriter - Java

I'm trying to hide a message inside a .gif for a steganography project.
I've converted the input gif to an ArrayList of BufferedImages ana applied my steganography algorithm.
But, i came across an issue with converting the ArrayList of BufferedImages back to a .gif.
I used this GifSequenceWriter class to convert the BufferedImages array to a new .gif after getting the original delay between frames from the original gif image metadata.
File encoded_img = new File("output.gif");
ImageOutputStream output = new FileImageOutputStream(encoded_img);
GifSequenceWriter writer = new GifSequenceWriter(output, frames.get(0).getType(), delayTimeMS, true);
writer.writeToSequence(frames.get(0));
for(int k=1; k<frames.size()-1; k++) {
writer.writeToSequence(frames.get(k));
}
writer.close();
output.close();
But, the resulting .gif looks really bad, and i've saved the individual frames with and without the steganography algorithm and they look fine. You can check out an example of the original image, the 10 saved frames and the resulting .gif here.
Is there a better way to create .gifs in java?
Thanks in advance.
There's a problem with the the GifSequenceWriter when using palette images (BufferedImage.TYPE_BYTE_INDEXED with IndexColorModel). This will create metadata based on a default 216 color palette (the web safe palette), which is clearly different from the colors in your image.
The problematic lines in GifSequenceWriter:
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType);
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
Instead, the metadata should be based on the color palette in the index color model of your image. But the good news is, it works fine without it.
You can simply use:
GifSequenceWriter writer = new GifSequenceWriter(output, BufferedImage.TYPE_INT_ARGB, delayTimeMS, true);
...and the writer will automatically create the palette as needed, from your actual image data.
It's also possible to fix the GifSequenceWriter, to accept an ImageTypeSpecifier instead of the int imageType, however, this will only work if all frames use the same palette, I think:
public GifSequenceWriter(
ImageOutputStream outputStream,
ImageTypeSpecifier imageTypeSpecifier,
int timeBetweenFramesMS,
boolean loopContinuously) throws IIOException, IOException {
// my method to create a writer
gifWriter = getWriter();
imageWriteParam = gifWriter.getDefaultWriteParam();
imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);
// ... rest of the method unchanged.
Usage:
ColorModel cm = firstImage.getColorModel();
ImageTypeSpecifier imageType = new ImageTypeSpecifier(cm, cm.createCompatibleSampleModel(1, 1));
GifSequenceWriter writer = new GifSequenceWriter(output, imageType, delayTimeMS, true);

Java BufferedImage JPG compression without writing to file

I've seen several examples of making compressed JPG images from Java BufferedImage objects by writing to file, but is it possible to perform JPG compression without writing to file? Perhaps by writing to a ByteArrayOutputStream like this?
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(0.7f);
ImageOutputStream outputStream = createOutputStream();
jpgWriter.setOutput(outputStream);
IIOImage outputImage = new IIOImage(image, null, null);
// in this example, the JPG is written to file...
// jpgWriter.write(null, outputImage, jpgWriteParam);
// jpgWriter.dispose();
// ...but I want to compress without saving, such as
ByteArrayOutputStream compressed = ???
Just pass your ByteArrayOutputStream to ImageIO.createImageOutputStream(...) like this:
// The important part: Create in-memory stream
ByteArrayOutputStream compressed = new ByteArrayOutputStream();
try (ImageOutputStream outputStream = ImageIO.createImageOutputStream(compressed)) {
// NOTE: The rest of the code is just a cleaned up version of your code
// Obtain writer for JPEG format
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("JPEG").next();
// Configure JPEG compression: 70% quality
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(0.7f);
// Set your in-memory stream as the output
jpgWriter.setOutput(outputStream);
// Write image as JPEG w/configured settings to the in-memory stream
// (the IIOImage is just an aggregator object, allowing you to associate
// thumbnails and metadata to the image, it "does" nothing)
jpgWriter.write(null, new IIOImage(image, null, null), jpgWriteParam);
// Dispose the writer to free resources
jpgWriter.dispose();
}
// Get data for further processing...
byte[] jpegData = compressed.toByteArray();
PS: By default, ImageIO will use disk caching when creating your ImageOutputStream. This may slow down your in-memory stream writing. To disable it, use ImageIO.setCache(false) (disables disk caching globally) or explicitly create an MemoryCacheImageOutputStream (local), like this:
ImageOutputStream outputStream = new MemoryCacheImageOutputStream(compressed);

Read pixel from a big jp2 image without loading the whole image into memory

I'm trying to read parts from a big image in java. My image size is more than 700 MB. I have used this code which normally reads pixels without loading the whole image into memory:
Rectangle sourceRegion = new Rectangle(0, 0, 512, 512); // The region you want to extract
ImageInputStream stream = ImageIO.createImageInputStream( new File("/home/dhoha/Downloads/BreastCancer.jp2")); // File or input stream
final Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
if (readers.hasNext()) {
ImageReader reader = (ImageReader)readers.next();
reader.setInput(stream, true);
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(sourceRegion); // Set region
BufferedImage image = reader.read(0, param); // Will read only the region specified
However, I got the error:
Exception in thread "main" java.lang.IllegalArgumentException: Dimensions (width=95168 height=154832) are too large
at java.awt.image.SampleModel.<init>(SampleModel.java:130)
at java.awt.image.ComponentSampleModel.<init>(ComponentSampleModel.java:146)
at java.awt.image.PixelInterleavedSampleModel.<init>(PixelInterleavedSampleModel.java:87)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.createSampleModel(J2KRenderedImageCodecLib.java:741)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.createOriginalSampleModel(J2KRenderedImageCodecLib.java:729)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.<init>(J2KRenderedImageCodecLib.java:261)
at com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLib.read(J2KImageReaderCodecLib.java:364)
at testJai2.test3.main(test3.java:21)
Any help please to read parts from this big image?
There are different ways to load parts of image to memory and then process it afterwards. You can try out the following method to read fragments:
public static BufferedImage readFragment(InputStream stream, Rectangle rect)
throws IOException {
ImageInputStream imageStream = ImageIO.createImageInputStream(stream);
ImageReader reader = ImageIO.getImageReaders(imageStream).next();
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(rect);
reader.setInput(imageStream, true, true);
BufferedImage image = reader.read(0, param);
reader.dispose();
imageStream.close();
return image;
}
And calling it like this:
URL url = new URL("..."); // You can use your own stream instead of URL
Image chunk = readFragment(url.openStream(), new Rectangle(150, 150, 300, 250));
This is marked as a correct answer in this thread.
You can use this technique to finally read the whole image into the memory if you need by doing some simple calculations.
EDIT:
The resolution of the image you are trying to process is larger than an array can have (95168x154832). So basically you will not be able to read the image, since ImageIO.createImageInputStream() tries to load the whole image into an array AFAIK.
What you can do is use a library called ImgLib2. Here you can find some examples. ImgLib2 uses multidimensional arrays to read the (big) image data and so it's larger than ImageIO can handle.

antialiasing in java image scaling library

I am currently using http://code.google.com/p/java-image-scaling/ this library to generate scaled images for my web app.But when I scale down the image to about 100x100 size there are some leftover artifacts visible in some images. Is this an issue with antialiasing? And how do I use antialiasing with this library.The api documentation doesn't say any thing about it.
Here is the code
File f = new File("C:\\Users\\ad min\\Pictures\\30-whisky-3d-wallpaper-1152x864.jpg");
BufferedImage src = ImageIO.read(f);
//ResampleOp resampleOp = new ResampleOp(76, 76);
ResampleOp resampleOp = new ResampleOp(200,200);
resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.VerySharp);
BufferedImage rescaled = resampleOp.filter(src, null);
ImageIO.write(rescaled, "JPG", new File(
"C:\\Users\\ad min\\Pictures\\scaleddown.jpg"));
what am I doing wrong?
I finally didn't need antialiasing I simply used this code given in the foloowing link and it worked :) whewww
http://www.universalwebservices.net/web-programming-resources/java/adjust-jpeg-image-
compression-quality-when-saving-images-in-java
Iterator<ImageWriter> iter = ImageIO
.getImageWritersByFormatName("jpeg");
ImageWriter writer = (ImageWriter) iter.next();
// instantiate an ImageWriteParam object with default compression
// options
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(1); // an integer between 0 and 1
// 1 specifies minimum compression and maximum quality
File file = new File("C:\\Users\\ad min\\Pictures\\scaleddown.jpg");
FileImageOutputStream output = new FileImageOutputStream(file);
writer.setOutput(output);
IIOImage image = new IIOImage(rescaled, null, null);
writer.write(null, image, iwp);
writer.dispose();

image upload resolution problems

when i am uploading an image with image io it is converting the resolutions of the image
what i mean to say is i am uploading a image with 300 dpi it get converts into 96 dpi why?
i am not using any resizing
Guess, you don't copy image metadata, here goes simplistic example how this can be done:
ImageInputStream iis =ImageIO.createImageInputStream(new File("test.jpg"));
ImageReader reader = (ImageReader) ImageIO.getImageReaders(iis).next();
reader.setInput(iis, true);
IIOMetadata meta = reader.getImageMetadata(0);
BufferedImage image = reader.read(0);
/*
do image manipulations here
*/
ImageOutputStream ios = ImageIO.createImageOutputStream(new File("out.jpg"));
ImageWriter writer = ImageIO.getImageWriter(reader);
writer.setOutput(ios);
writer.write(meta, new IIOImage(image, null, null), null);
Since you've not provided any specific details, i've tested it on local files. However, i hope that it provides you a hint.

Categories