[GIS] Reading each pixel of each band of multiband GeoTiff with GeoTools Java

geotiff-tiffgeotoolsjava

I am new to working with Raster in GeoTools-very experienced in java. My goal is to read in a geotiff that has multiple bands, then create a HashMap for each pixel, where the key is simply the lat/lon of the pixel, and the value is a sortedMap in which teh key is the band name, and the value is the real value of the pixel for that band. I am then going to do some fascinating stuff with that map. So in basic terms, I need to read in a tif, get each band, and access then pixel's lat lon in each band.
I have a rather pathetic attempt to read in a tiff below, but I can't find any straightforward way online to get each band, and get each pixel.

GridCoverage2D g;// = new GridCoverage2D(null, null);

      GeoTiffReader r = new GeoTiffReader(new File("c;\\temp\\thetiff.tif"));
      GridEnvelope originalGridRange = r.getOriginalGridRange();

UPDATE:
So I can now read in the file with the following code:

     public static void main(String[] args) {
        try {
          AbstractGridCoverage2DReader reader = new GeoTiffReader(new FileInputStream(new File("C:\\my.TIF")));//...; // Creating a reader
          String[] coverageNames = reader.getGridCoverageNames();
          // At this point, coverageNames may contain, as an instance, "pressure,temperature,humidity"

          String requestedCoverageName = coverageNames[0]; // e..g, "temperature"

          // Getting the coverage's properties
          final GeneralEnvelope envelope = reader.getOriginalEnvelope();
          final GridEnvelope gridRange = reader.getOriginalGridRange();

          // reading the coverage
//FAILS HERE
          GridCoverage2D coverage = (GridCoverage2D) reader.read(requestedCoverageName, null);
          System.out.println("test");
        } catch (Exception ex) {
          Logger.getLogger(GeoTiffvectorizer.class.getName()).log(Level.SEVERE, null, ex);
        }
      }

problem now is I know the image has 8 bands, but I only got one item in coverageNames[] and I get the following stacktrace error

Error: One factory fails for the operation "ImageRead"
Occurs in: javax.media.jai.ThreadSafeOperationRegistry
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
    at javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
    at javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
    at javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
    at javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
    at javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
    at javax.media.jai.RenderedOp.getWidth(RenderedOp.java:2179)
    at org.geotools.gce.geotiff.GeoTiffReader.read(GeoTiffReader.java:560)
    at org.geotools.coverage.grid.io.AbstractGridCoverage2DReader.read(AbstractGridCoverage2DReader.java:239)
    at dgi.vectorspaceclustering.GeoTiffvectorizer.main(GeoTiffvectorizer.java:38)
Caused by: java.lang.RuntimeException: javax.imageio.IIOException: I/O error reading header!
    at com.sun.media.jai.imageioimpl.ImageReadCRIF.create(ImageReadCRIF.java:317)
    ... 14 more
Caused by: javax.imageio.IIOException: I/O error reading header!
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.readHeader(TIFFImageReader.java:458)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.locateImage(TIFFImageReader.java:465)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.seekToImage(TIFFImageReader.java:589)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.getImageTypes(TIFFImageReader.java:1104)
    at javax.imageio.ImageReader.getRawImageType(ImageReader.java:681)
    at com.sun.media.jai.imageioimpl.ImageReadOpImage.layoutHelper(ImageReadOpImage.java:228)
    at com.sun.media.jai.imageioimpl.ImageReadOpImage.<init>(ImageReadOpImage.java:473)
    at com.sun.media.jai.imageioimpl.ImageReadCRIF.create(ImageReadCRIF.java:309)
    ... 14 more
Caused by: java.io.EOFException
    at javax.imageio.stream.ImageInputStreamImpl.readShort(ImageInputStreamImpl.java:229)
    at javax.imageio.stream.ImageInputStreamImpl.readUnsignedShort(ImageInputStreamImpl.java:242)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.readHeader(TIFFImageReader.java:404)
    ... 21 more
2014-07-14T16:30:36.845-0400  SEVERE  null
javax.media.jai.util.ImagingException: All factories fail for the operation "ImageRead"
    at javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1687)
    at javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
    at javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
    at javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
    at javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
    at javax.media.jai.RenderedOp.getWidth(RenderedOp.java:2179)
    at org.geotools.gce.geotiff.GeoTiffReader.read(GeoTiffReader.java:560)
    at org.geotools.coverage.grid.io.AbstractGridCoverage2DReader.read(AbstractGridCoverage2DReader.java:239)
    at dgi.vectorspaceclustering.GeoTiffvectorizer.main(GeoTiffvectorizer.java:38)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
    at javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
    ... 8 more
Caused by: java.lang.RuntimeException: javax.imageio.IIOException: I/O error reading header!
    at com.sun.media.jai.imageioimpl.ImageReadCRIF.create(ImageReadCRIF.java:317)
    ... 14 more
Caused by: javax.imageio.IIOException: I/O error reading header!
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.readHeader(TIFFImageReader.java:458)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.locateImage(TIFFImageReader.java:465)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.seekToImage(TIFFImageReader.java:589)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.getImageTypes(TIFFImageReader.java:1104)
    at javax.imageio.ImageReader.getRawImageType(ImageReader.java:681)
    at com.sun.media.jai.imageioimpl.ImageReadOpImage.layoutHelper(ImageReadOpImage.java:228)
    at com.sun.media.jai.imageioimpl.ImageReadOpImage.<init>(ImageReadOpImage.java:473)
    at com.sun.media.jai.imageioimpl.ImageReadCRIF.create(ImageReadCRIF.java:309)
    ... 14 more
Caused by: java.io.EOFException
    at javax.imageio.stream.ImageInputStreamImpl.readShort(ImageInputStreamImpl.java:229)
    at javax.imageio.stream.ImageInputStreamImpl.readUnsignedShort(ImageInputStreamImpl.java:242)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.readHeader(TIFFImageReader.java:404)
    ... 21 more
Caused by:
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
    at javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
    at javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
    at javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
    at javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
    at javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
    at javax.media.jai.RenderedOp.getWidth(RenderedOp.java:2179)
    at org.geotools.gce.geotiff.GeoTiffReader.read(GeoTiffReader.java:560)
    at org.geotools.coverage.grid.io.AbstractGridCoverage2DReader.read(AbstractGridCoverage2DReader.java:239)
    at dgi.vectorspaceclustering.GeoTiffvectorizer.main(GeoTiffvectorizer.java:38)
Caused by: java.lang.RuntimeException: javax.imageio.IIOException: I/O error reading header!
    at com.sun.media.jai.imageioimpl.ImageReadCRIF.create(ImageReadCRIF.java:317)
    ... 14 more
Caused by: javax.imageio.IIOException: I/O error reading header!
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.readHeader(TIFFImageReader.java:458)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.locateImage(TIFFImageReader.java:465)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.seekToImage(TIFFImageReader.java:589)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.getImageTypes(TIFFImageReader.java:1104)
    at javax.imageio.ImageReader.getRawImageType(ImageReader.java:681)
    at com.sun.media.jai.imageioimpl.ImageReadOpImage.layoutHelper(ImageReadOpImage.java:228)
    at com.sun.media.jai.imageioimpl.ImageReadOpImage.<init>(ImageReadOpImage.java:473)
    at com.sun.media.jai.imageioimpl.ImageReadCRIF.create(ImageReadCRIF.java:309)
    ... 14 more
Caused by: java.io.EOFException
    at javax.imageio.stream.ImageInputStreamImpl.readShort(ImageInputStreamImpl.java:229)
    at javax.imageio.stream.ImageInputStreamImpl.readUnsignedShort(ImageInputStreamImpl.java:242)
    at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.readHeader(TIFFImageReader.java:404)
    ... 21 more

Best Answer

Mark's answer is great! It really helped me out.

Here's a slightly modified version of Mark's code. The major difference is that this code does not rely on the java.awt.image package to compute the image size, number of bands, or pixel values. Instead, it uses the GeoTools Coverage API.

import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.geotools.coverage.grid.*;
import org.opengis.coverage.grid.*;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValue;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.OverviewPolicy;


public class Test {
    public static void test(java.io.File file) throws Exception {

        ParameterValue<OverviewPolicy> policy = AbstractGridFormat.OVERVIEW_POLICY.createValue();
        policy.setValue(OverviewPolicy.IGNORE);

        //this will basically read 4 tiles worth of data at once from the disk...
        ParameterValue<String> gridsize = AbstractGridFormat.SUGGESTED_TILE_SIZE.createValue();

        //Setting read type: use JAI ImageRead (true) or ImageReaders read methods (false)
        ParameterValue<Boolean> useJaiRead = AbstractGridFormat.USE_JAI_IMAGEREAD.createValue();
        useJaiRead.setValue(true);


        GridCoverage2DReader reader = new GeoTiffReader(file);
        GridEnvelope dimensions = reader.getOriginalGridRange();
        GridCoordinates maxDimensions = dimensions.getHigh();
        int w = maxDimensions.getCoordinateValue(0)+1;
        int h = maxDimensions.getCoordinateValue(1)+1;
        int numBands = reader.getGridCoverageCount();

        GridCoverage2D coverage = reader.read(
            new GeneralParameterValue[]{policy, gridsize, useJaiRead}
        );
        GridGeometry2D geometry = coverage.getGridGeometry();


        for (int i=0; i<w; i++) {
            for (int j=0; j<h; j++) {

                org.geotools.geometry.Envelope2D pixelEnvelop =
                geometry.gridToWorld(new GridEnvelope2D(i, j, 1, 1));

                double lat = pixelEnvelop.getCenterY();
                double lon = pixelEnvelop.getCenterX();

                double[] vals = new double[numBands];
                coverage.evaluate(new GridCoordinates2D(i, j), vals);

                //Do something!

            }
        }

    }
}
Related Question