private void applyGeoCoding(TiffFileInfo info, TIFFImageMetadata metadata, Product product) { if (info.containsField(GeoTIFFTagSet.TAG_MODEL_TIE_POINT)) { double[] tiePoints = info.getField(GeoTIFFTagSet.TAG_MODEL_TIE_POINT).getAsDoubles(); boolean isGlobal = isGlobal(product, info); // check if we have a global geographic lat/lon with lon from 0..360 instead of -180..180 final double deltaX = Math.ceil(360. / product.getSceneRasterWidth()); if (isGlobal && tiePoints.length == 6 && Math.abs(tiePoints[3]) < deltaX) { // e.g. tiePoints[3] = -0.5, productWidth=722 --> we have a lon range of 361 which should // start // at or near -180 but not at zero isGlobalShifted180 = true; // subtract 180 from the longitudes tiePoints[3] -= 180.0; } if (canCreateTiePointGeoCoding(tiePoints)) { applyTiePointGeoCoding(info, tiePoints, product); } else if (canCreateGcpGeoCoding(tiePoints)) { applyGcpGeoCoding(info, tiePoints, product); } } if (product.getGeoCoding() == null) { try { applyGeoCodingFromGeoTiff(metadata, product); } catch (Exception ignored) { } } }
private static void applyTiePointGeoCoding( TiffFileInfo info, double[] tiePoints, Product product) { final SortedSet<Double> xSet = new TreeSet<>(); final SortedSet<Double> ySet = new TreeSet<>(); for (int i = 0; i < tiePoints.length; i += 6) { xSet.add(tiePoints[i]); ySet.add(tiePoints[i + 1]); } final double xMin = xSet.first(); final double xMax = xSet.last(); final double xDiff = (xMax - xMin) / (xSet.size() - 1); final double yMin = ySet.first(); final double yMax = ySet.last(); final double yDiff = (yMax - yMin) / (ySet.size() - 1); final int width = xSet.size(); final int height = ySet.size(); int idx = 0; final Map<Double, Integer> xIdx = new HashMap<>(); for (Double val : xSet) { xIdx.put(val, idx); idx++; } idx = 0; final Map<Double, Integer> yIdx = new HashMap<>(); for (Double val : ySet) { yIdx.put(val, idx); idx++; } final float[] lats = new float[width * height]; final float[] lons = new float[width * height]; for (int i = 0; i < tiePoints.length; i += 6) { final int idxX = xIdx.get(tiePoints[i + 0]); final int idxY = yIdx.get(tiePoints[i + 1]); final int arrayIdx = idxY * width + idxX; lons[arrayIdx] = (float) tiePoints[i + 3]; lats[arrayIdx] = (float) tiePoints[i + 4]; } String[] names = Utils.findSuitableLatLonNames(product); final TiePointGrid latGrid = new TiePointGrid(names[0], width, height, xMin, yMin, xDiff, yDiff, lats); final TiePointGrid lonGrid = new TiePointGrid(names[1], width, height, xMin, yMin, xDiff, yDiff, lons); product.addTiePointGrid(latGrid); product.addTiePointGrid(lonGrid); final SortedMap<Integer, GeoKeyEntry> geoKeyEntries = info.getGeoKeyEntries(); final Datum datum = getDatum(geoKeyEntries); product.setGeoCoding(new TiePointGeoCoding(latGrid, lonGrid, datum)); }
private static boolean isGlobal(Product product, TiffFileInfo info) { boolean isGlobal = false; final TIFFField pixelScaleField = info.getField(GeoTIFFTagSet.TAG_MODEL_PIXEL_SCALE); if (pixelScaleField != null) { double[] pixelScales = pixelScaleField.getAsDoubles(); if (isPixelScaleValid(pixelScales)) { final double widthInDegree = pixelScales[0] * product.getSceneRasterWidth(); isGlobal = Math.ceil(widthInDegree) >= 360; } } return isGlobal; }
private static void applyGcpGeoCoding( final TiffFileInfo info, final double[] tiePoints, final Product product) { int numTiePoints = tiePoints.length / 6; final GcpGeoCoding.Method method; if (numTiePoints >= GcpGeoCoding.Method.POLYNOMIAL3.getTermCountP()) { method = GcpGeoCoding.Method.POLYNOMIAL3; } else if (numTiePoints >= GcpGeoCoding.Method.POLYNOMIAL2.getTermCountP()) { method = GcpGeoCoding.Method.POLYNOMIAL2; } else if (numTiePoints >= GcpGeoCoding.Method.POLYNOMIAL1.getTermCountP()) { method = GcpGeoCoding.Method.POLYNOMIAL1; } else { return; // not able to apply GCP geo coding; not enough tie points } final int width = product.getSceneRasterWidth(); final int height = product.getSceneRasterHeight(); final GcpDescriptor gcpDescriptor = GcpDescriptor.getInstance(); final ProductNodeGroup<Placemark> gcpGroup = product.getGcpGroup(); for (int i = 0; i < numTiePoints; i++) { final int offset = i * 6; final float x = (float) tiePoints[offset + 0]; final float y = (float) tiePoints[offset + 1]; final float lon = (float) tiePoints[offset + 3]; final float lat = (float) tiePoints[offset + 4]; if (Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(lon) || Double.isNaN(lat)) { continue; } final PixelPos pixelPos = new PixelPos(x, y); final GeoPos geoPos = new GeoPos(lat, lon); final Placemark gcp = Placemark.createPointPlacemark( gcpDescriptor, "gcp_" + i, "GCP_" + i, "", pixelPos, geoPos, product.getGeoCoding()); gcpGroup.add(gcp); } final Placemark[] gcps = gcpGroup.toArray(new Placemark[gcpGroup.getNodeCount()]); final SortedMap<Integer, GeoKeyEntry> geoKeyEntries = info.getGeoKeyEntries(); final Datum datum = getDatum(geoKeyEntries); product.setGeoCoding(new GcpGeoCoding(method, gcps, width, height, datum)); }
private void addBandsToProduct(TiffFileInfo tiffInfo, Product product) throws IOException { final ImageReadParam readParam = imageReader.getDefaultReadParam(); TIFFRenderedImage baseImage = (TIFFRenderedImage) imageReader.readAsRenderedImage(FIRST_IMAGE, readParam); SampleModel sampleModel = baseImage.getSampleModel(); final int numBands = sampleModel.getNumBands(); final int productDataType = ImageManager.getProductDataType(sampleModel.getDataType()); bandMap = new HashMap<>(numBands); for (int i = 0; i < numBands; i++) { final String bandName = String.format("band_%d", i + 1); final Band band = product.addBand(bandName, productDataType); if (tiffInfo.containsField(BaselineTIFFTagSet.TAG_COLOR_MAP) && baseImage.getColorModel() instanceof IndexColorModel) { band.setImageInfo(createIndexedImageInfo(product, baseImage, band)); } bandMap.put(band, i); } }
Product readGeoTIFFProduct(final ImageInputStream stream, final File inputFile) throws IOException { Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(stream); while (imageReaders.hasNext()) { final ImageReader reader = imageReaders.next(); if (reader instanceof TIFFImageReader) { imageReader = (TIFFImageReader) reader; break; } } if (imageReader == null) { throw new IOException("GeoTiff imageReader not found"); } imageReader.setInput(stream); Product product = null; final TIFFImageMetadata imageMetadata = (TIFFImageMetadata) imageReader.getImageMetadata(FIRST_IMAGE); final TiffFileInfo tiffInfo = new TiffFileInfo(imageMetadata.getRootIFD()); final TIFFField field = tiffInfo.getField(Utils.PRIVATE_BEAM_TIFF_TAG_NUMBER); if (field != null && field.getType() == TIFFTag.TIFF_ASCII) { final String s = field.getAsString(0).trim(); if (s.contains("<Dimap_Document")) { // with DIMAP header InputStream is = null; try { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); final DocumentBuilder builder = factory.newDocumentBuilder(); is = new ByteArrayInputStream(s.getBytes()); final Document document = new DOMBuilder().build(builder.parse(is)); product = DimapProductHelpers.createProduct(document); removeGeoCodingAndTiePointGrids(product); initBandsMap(product); } catch (ParserConfigurationException | SAXException ignore) { // ignore if it can not be read } finally { if (is != null) { is.close(); } } } } if (product == null) { // without DIMAP header final String productName; if (tiffInfo.containsField(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION)) { final TIFFField field1 = tiffInfo.getField(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION); productName = field1.getAsString(0); } else if (inputFile != null) { productName = FileUtils.getFilenameWithoutExtension(inputFile); } else { productName = "geotiff"; } final String productType = getReaderPlugIn().getFormatNames()[0]; final int width = imageReader.getWidth(FIRST_IMAGE); final int height = imageReader.getHeight(FIRST_IMAGE); product = new Product(productName, productType, width, height, this); addBandsToProduct(tiffInfo, product); } if (tiffInfo.isGeotiff()) { applyGeoCoding(tiffInfo, imageMetadata, product); } TiffTagToMetadataConverter.addTiffTagsToMetadata( imageMetadata, tiffInfo, product.getMetadataRoot()); if (inputFile != null) { product.setFileLocation(inputFile); } setPreferredTiling(product); return product; }