2017-01-18 12 views
2

Предположим, я вручную созданы значения пикселей для более 4 полос, и я хочу, чтобы хранить их в Tiff файл.Как сохранить массив пикселей с более чем 4 группами в файл Tiff/GeoTiff в java?

Эти полосы могут быть для R, G, B, температуры (значения температуры не находятся в диапазоне от 0 до 255, поэтому я использую int вместо байта для pexils) и т. Д. Т.е. любую информацию, которая может берутся со спутника

Теперь я хочу сохранить эти пиксели в файл tiff. В java есть класс BufferedImage, который имеет много типов, таких как: TYPE_4BYTE_ABGR, TYPE_BYTE_GRAY и т. Д. Однако ни один из них для нескольких диапазонов более 4 диапазонов. Существует TYPE_CUSTOM, но при указании его и попытке сохранить данные в Tiff-файле он дает вам исключение, потому что он не поддерживается для операции записи (только для операции чтения, т. Е. Он может читать файл и задавать тип TYPE_CUSTOM, если он не понял тип, но он не может записать файл в непонятном типе).

Приведенный ниже код работал на 3 полосы даже не правильно (он не показывает цветное изображение, и оно выглядело как искаженное изображение с отсутствующими линиями) , но для более чем 4-х полос, как я могу это сделать?

ImageOutputStream ios = ImageIO.createImageOutputStream(os); 
    Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("tiff"); 
    ImageWriter writer = writers.next(); 
    writer.setOutput(ios); 
     int index = 0; 
     int[] pixels = new int[width*height*numberOfBands]; 
     for (int i = 0; i < width; i++) { 
      for (int j = 0; j < height; j++) { 
       for (int k = 0; k < numberOfBands; k++) { 
        pixels[index++] = //any values; 
       } 
      } 
     } 

    DataBuffer dataBuffer = new DataBufferInt(pixels, pixels.length); 

    // Create Raster 
    WritableRaster writableRaster = Raster.createBandedRaster 
     (dataBuffer, width, height, 
     width,      // scanlineStride 
     new int[numberOfBands],    // bankIndices, 
     new int[numberOfBands],    // bandOffsets, 
     null);      // location 

    // Create the image 
    BufferedImage bufferedImage = new BufferedImage 
      (width, height, BufferedImage.TYPE_BYTE_RGB); 
    bufferedImage.setData(writableRaster); 
    IIOImage iioImage = new IIOImage(bufferedImage, null, null); 
    ImageWriteParam param = writer.getDefaultWriteParam(); 
    writer.write(null, iioImage, param); 

Я использую GeoTools кстати

Отредактировано: Согласно @iant Я изменил код, но он дает только чистый прозрачный фон, даже я сохранил такое же количество полос, т.е. 3 полосы. @iant Не могли бы вы проверить код ниже.

package examples; 

    import java.awt.image.WritableRaster; 
    import java.io.File; 
    import java.io.IOException; 

    import javax.media.jai.RasterFactory; 

    import org.geotools.coverage.CoverageFactoryFinder; 
    import org.geotools.coverage.grid.GridCoordinates2D; 
    import org.geotools.coverage.grid.GridCoverage2D; 
    import org.geotools.coverage.grid.GridCoverageFactory; 
    import org.geotools.coverage.grid.GridEnvelope2D; 
    import org.geotools.coverage.grid.GridGeometry2D; 
    import org.geotools.coverage.grid.io.AbstractGridFormat; 
    import org.geotools.coverage.grid.io.OverviewPolicy; 
    import org.geotools.gce.geotiff.GeoTiffFormat; 
    import org.geotools.gce.geotiff.GeoTiffReader; 
    import org.opengis.coverage.grid.GridCoverageWriter; 
    import org.opengis.parameter.GeneralParameterValue; 
    import org.opengis.parameter.ParameterValue; 

    public class CreateTiffImageTest2 { 

    public static void main(String[] args) throws IOException { 

    File file = new File("/home/mosab/Desktop/input/tif.tif"); 

    ParameterValue<OverviewPolicy> policy = AbstractGridFormat.OVERVIEW_POLICY.createValue(); 
    policy.setValue(OverviewPolicy.IGNORE); 
    ParameterValue<String> gridsize = AbstractGridFormat.SUGGESTED_TILE_SIZE.createValue(); 
    ParameterValue<Boolean> useJaiRead = AbstractGridFormat.USE_JAI_IMAGEREAD.createValue(); 
    useJaiRead.setValue(true); 

    GeoTiffReader geoTiffReader = new GeoTiffReader(file); 
    GridCoverage2D cov = geoTiffReader.read(new GeneralParameterValue[] { policy, gridsize, useJaiRead }); 
    GridGeometry2D geometry = cov.getGridGeometry(); 
    GridEnvelope2D gridEnvelope = geometry.getGridRange2D(); 
    int w = (int) gridEnvelope.getWidth(); 
    int h = (int) gridEnvelope.getHeight(); 

    WritableRaster writableRaster = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_DOUBLE, w, h, 3, 
      null); 
    double[] data = new double[3]; 
    double[] dest = new double[3]; 
    for (int i = 0; i < w; i++) { 
     for (int j = 0; j < h; j++) { 
      GridCoordinates2D coord = new GridCoordinates2D(i, j); 
      cov.evaluate(coord, dest); 

      data[0] = dest[0]; 
      data[1] = dest[1]; 
      data[2] = dest[2]; 
      writableRaster.setPixel(i, j, data); 
     } 
     float perc = 100.0f * i/w; 
     if (i % 100 == 0) { 
      System.out.println("done " + perc); 
     } 
    } 
    // Wrap the raster as a Coverage 
    GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null); 
    GridCoverage2D gc = factory.create("name", writableRaster, cov.getEnvelope()); 
    File out = new File("/home/mosab/Desktop/input/tifgen.tif"); 
    GeoTiffFormat format = new GeoTiffFormat(); 
    GridCoverageWriter writer = format.getWriter(out); 
    try { 
     writer.write(gc, null); 
     writer.dispose(); 
    } catch (IllegalArgumentException | IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 

}

Обновление 2:

import java.awt.image.BufferedImage; 
import java.awt.image.WritableRaster; 
import java.io.File; 
import java.io.IOException; 

import javax.imageio.ImageIO; 
import javax.media.jai.RasterFactory; 

import org.geotools.coverage.CoverageFactoryFinder; 
import org.geotools.coverage.grid.GridCoverage2D; 
import org.geotools.coverage.grid.GridCoverageFactory; 
import org.geotools.coverage.grid.io.AbstractGridFormat; 
import org.geotools.coverage.grid.io.GridFormatFinder; 
import org.geotools.factory.Hints; 
import org.geotools.gce.geotiff.GeoTiffFormat; 
import org.geotools.geometry.jts.ReferencedEnvelope; 
import org.geotools.referencing.CRS; 
import org.opengis.coverage.grid.GridCoverageWriter; 
import org.opengis.geometry.MismatchedDimensionException; 
import org.opengis.referencing.FactoryException; 
import org.opengis.referencing.NoSuchAuthorityCodeException; 
import org.opengis.referencing.crs.CoordinateReferenceSystem; 

public class Test2 { 

public static void print(Object o) { 
    System.out.println(o); 
} 

public static void main(String[] args) 
     throws MismatchedDimensionException, NoSuchAuthorityCodeException, FactoryException, IOException { 
    File out = new File("/home/mosab/Desktop/input/1.tif"); 
    BufferedImage img = ImageIO.read(out); 

    // ColorModel colorModel = img.getColorModel(
    WritableRaster raster = img.getRaster(); 

    int w = img.getWidth(); 
    int h = img.getHeight(); 
    print("width = " + w); 
    print("heigh = " + h); 
    int numBands = raster.getNumBands(); 

    WritableRaster writableRaster = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_INT, w, h, 3, 
      null); 
    //as I said pixels are created manually but I used here pixels from an image to check the approach 
    int[] data = new int[3]; 
    for (int i = 0; i < w; i++) { 
     for (int j = 0; j < h; j++) { 
      for (int k = 0; k < numBands; k++) { 
       data[k] = raster.getSample(i, j, k); 
      } 
      writableRaster.setPixel(i, j, data); 
     } 
    } 

    GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null); 
    CoordinateReferenceSystem crs = CRS.decode("EPSG:27700"); 
    int llx = 500000; 
    int lly = 105000; 
    ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(llx, llx + (w * 10), lly, lly + (h * 10), crs); 
    GridCoverage2D gc = factory.create("name", writableRaster, referencedEnvelope); 

    AbstractGridFormat format = GridFormatFinder.findFormat(out); 
    Hints hints = null; 
    if (format instanceof GeoTiffFormat) { 
     hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); 
    } 

    File out1 = new File("/home/mosab/Desktop/input/tifgen.tif"); 
    GridCoverageWriter writer = format.getWriter(out1); 
    try { 
     writer.write(gc, null); 
     writer.dispose(); 
    } catch (IllegalArgumentException | IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 

}

Примечание: Я использовал тип Int и массив размером 3, поскольку исходное изображение имеет RGB полосы ,

+0

Если у вас есть особые требования, вы можете подумать о наличии собственного формата файла. – Piglet

+0

Я бы поработал над тем, чтобы он работал с 3 полосами, прежде чем попробовать 4 –

+0

@Piglet это можно сделать с использованием формата TIff/Geotiff, потому что он предназначен для этого. И, кстати, я упомянул ранее более 4-х полос, потому что в случае 4-го программного обеспечения это будет считать ARGB, т. Е. + Aplha. –

ответ

2

Вам необходимо создать WritableRaster, используя другой заводской метод, который позволяет вам установить необходимый тип данных и количество диапазонов.

WritableRaster writableRaster = RasterFactory.createBandedRaster 
     (java.awt.image.DataBuffer.TYPE_DOUBLE,width,height,4,null); 
    double[] data = new double[4]; 
    double[] dest = new double[3]; 
    for(int i=0;i<width;i++) { 
     for(int j=0;j<height;j++) { 
//basically anything you like to create the bands 
     GridCoordinates2D coord = new GridCoordinates2D(i, j); 

//here I just grab the values of my base image and add them together 
     cov.evaluate(coord, dest); 

     data[0]=dest[0]; 
     data[1] = dest[1]; 
     data[2] = dest[2]; 
     data[3] = (dest[0]+dest[1]+dest[2]); 
     // write them to the new raster 
     writableRaster.setPixel(i, j, data); 
     } 
     float perc = 100.0f*i/width; 
     if(i%100==0) { 
     System.out.println("done "+perc); 
     } 
    } 
    //Wrap the raster as a Coverage 
    GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null); 
    GridCoverage2D gc = factory.create("name", writableRaster, cov.getEnvelope()); 
    //write it out 
    File out = new File(outFile); 
    GridCoverageWriter writer = format.getWriter(out); 
    try { 
     writer.write(gc , null); 
     writer.dispose(); 
    } catch (IllegalArgumentException | IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

UPDATE

Если взять следующий код:

public void makeTestRaster() throws MismatchedDimensionException, NoSuchAuthorityCodeException, FactoryException { 
    int width = 1000; 
    int height = 1000; 

    WritableRaster writableRaster = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_DOUBLE, width, 
     height, 4, null); 
    double[] data = new double[4]; 

    for (int i = 0; i < width; i++) { 
     for (int j = 0; j < height; j++) { 
     data[0] = i * 100.0; 
     data[1] = j * 100.0; 
     data[2] = (width - i) * 100.0; 
     data[3] = (height - j) * 100.0; 
     System.out.println(i + "," + j + ":" + data[0] + " " + data[1] + " " + data[2] + " " + data[3] + " "); 
     writableRaster.setPixel(i, j, data); 
     } 
     float perc = 100.0f * i/width; 
     if (i % 100 == 0) { 
     System.out.println("done " + perc); 
     } 
    } 
    File out = new File("test.tif"); 
    GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null); 
    CoordinateReferenceSystem crs = CRS.decode("EPSG:27700"); 
    int llx = 500000; 
    int lly = 105000; 
    ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(llx, llx + (width * 10), lly, lly + (height * 10), 
     crs); 
    GridCoverage2D gc = factory.create("name", writableRaster, referencedEnvelope); 
    AbstractGridFormat format = GridFormatFinder.findFormat(out); 
    Hints hints = null; 
    if (format instanceof GeoTiffFormat) { 
     hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE); 
    } 

    GridCoverageWriter writer = format.getWriter(out); 
    try { 
     writer.write(gc, null); 
     writer.dispose(); 
    } catch (IllegalArgumentException | IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    } 

Он создает 10 квадратных километров растр (возле моего дома). Он имеет 4 полосы, которые могли бы представлять что угодно, бег gdalinfo на нем дает следующую информацию:

gdalinfo test.tif 
Driver: GTiff/GeoTIFF 
Files: test.tif 
     test.tif.aux.xml 
Size is 1000, 1000 
Coordinate System is: 
PROJCS["OSGB 1936/British National Grid", 
    GEOGCS["OSGB 1936", 
     DATUM["OSGB_1936", 
      SPHEROID["Airy 1830",6377563.396,299.3249646, 
       AUTHORITY["EPSG","7001"]], 
      TOWGS84[446.448,-125.157,542.06,0.15,0.247,0.842,-20.489], 
      AUTHORITY["EPSG","6277"]], 
     PRIMEM["Greenwich",0, 
      AUTHORITY["EPSG","8901"]], 
     UNIT["degree",0.0174532925199433, 
      AUTHORITY["EPSG","9122"]], 
     AUTHORITY["EPSG","4277"]], 
    PROJECTION["Transverse_Mercator"], 
    PARAMETER["latitude_of_origin",49], 
    PARAMETER["central_meridian",-2], 
    PARAMETER["scale_factor",0.9996012717], 
    PARAMETER["false_easting",400000], 
    PARAMETER["false_northing",-100000], 
    UNIT["metre",1, 
     AUTHORITY["EPSG","9001"]], 
    AXIS["Easting",EAST], 
    AXIS["Northing",NORTH], 
    AUTHORITY["EPSG","27700"]] 
Origin = (500000.000000000000000,115000.000000000000000) 
Pixel Size = (10.000000000000000,-10.000000000000000) 
Metadata: 
    AREA_OR_POINT=Area 
    TIFFTAG_RESOLUTIONUNIT=1 (unitless) 
    TIFFTAG_XRESOLUTION=1 
    TIFFTAG_YRESOLUTION=1 
Image Structure Metadata: 
    INTERLEAVE=PIXEL 
Corner Coordinates: 
Upper Left ( 500000.000, 115000.000) ( 0d34'37.20"W, 50d55'30.82"N) 
Lower Left ( 500000.000, 105000.000) ( 0d34'47.05"W, 50d50' 7.16"N) 
Upper Right ( 510000.000, 115000.000) ( 0d26' 5.12"W, 50d55'24.27"N) 
Lower Right ( 510000.000, 105000.000) ( 0d26'15.95"W, 50d50' 0.62"N) 
Center  ( 505000.000, 110000.000) ( 0d30'26.33"W, 50d52'45.79"N) 
Band 1 Block=1000x8 Type=Float64, ColorInterp=Gray 
    Min=0.000 Max=99900.000 
    Minimum=0.000, Maximum=99900.000, Mean=49950.000, StdDev=28867.499 
    Metadata: 
    STATISTICS_MAXIMUM=99900 
    STATISTICS_MEAN=49950 
    STATISTICS_MINIMUM=0 
    STATISTICS_STDDEV=28867.499025721 
Band 2 Block=1000x8 Type=Float64, ColorInterp=Undefined 
    Min=0.000 Max=97500.000 
    Minimum=0.000, Maximum=97500.000, Mean=48750.000, StdDev=30378.926 
    Metadata: 
    STATISTICS_MAXIMUM=97500 
    STATISTICS_MEAN=48750 
    STATISTICS_MINIMUM=0 
    STATISTICS_STDDEV=30378.926358031 
Band 3 Block=1000x8 Type=Float64, ColorInterp=Undefined 
    Min=0.000 Max=97402500.000 
    Minimum=0.000, Maximum=97402500.000, Mean=24350625.000, StdDev=22476916.605 
    Metadata: 
    STATISTICS_MAXIMUM=97402500 
    STATISTICS_MEAN=24350625 
    STATISTICS_MINIMUM=0 
    STATISTICS_STDDEV=22476916.605084 
Band 4 Block=1000x8 Type=Float64, ColorInterp=Undefined 
    Min=2500.000 Max=100000.000 
    Minimum=2500.000, Maximum=100000.000, Mean=51250.000, StdDev=30378.926 
    Metadata: 
    STATISTICS_MAXIMUM=100000 
    STATISTICS_MEAN=51249.999999999 
    STATISTICS_MINIMUM=2500 
    STATISTICS_STDDEV=30378.926358031 

Это ясно показывает 4 полосы.Наконец, если вы импортируете его в QGIS для просмотра, вам предлагается присвоить любой из 4 диапазонов красным, зеленым & синим полосам.

enter image description here

Это производит множество изображений, которые обычно называют ложный цвет или вы можете выбрать оттенки серого из одной полосы, если вы смотрите на физические измерения, которые не происходят, имеет смысл в сочетании.

+0

Уважаемый, в код выше есть переменная «cov», и вы использовали ее два раза, первый раз в исходном изображении вы взяли пиксели от: cov.evaluate (coord, dest); и второй раз в сгенерированном изображении: GridCoverage2D gc = factory.create ("name", writableRaster, cov.getEnvelope()); –

+0

, но, как я уже говорил, я не хочу зависеть от исходного изображения. Я хочу установить пиксели «вручную», как если бы не было оригинального изображения раньше. Поэтому мне нужен код, чтобы либо создать отдельную переменную «cov», не зависящую от исходной, либо пробовать другой подход. Так что вы могли бы переписать код, чтобы это отразить. –

+0

вы можете установить свои пиксели так, как хотите, мне удалось скопировать мой, чтобы я мог проверить, что выходное изображение было правильным. Вы, вероятно, знаете, что такое конверт вашего вывода, чтобы вы могли его использовать. –