2017-01-18 34 views
2

假設爲超過4頻段手動創建的像素值,我想將它們存儲在一個TIFF文件。如何將超過4個波段的像素陣列保存到java中的Tiff/GeoTiff文件中?

那些波段可以用於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我改變了代碼,但它是隻給空白的透明背景,甚至我保留了相同的band數,即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

你可以用任何你想要的方式來設置你的像素,我碰巧複製我的,所以我可以檢查輸出圖像是否正確。你大概知道你輸出的信封是什麼,所以你可以使用它。 –

相關問題