给定一个最小的 ESRI ASCII 文件,在 libtiff 或 libgeotiff 中设置的相应字段是什么?

What are the corresponding fields to set in libtiff or libgeotiff, given a minimal ESRI ASCII file?

我有一个 ESRI ASCII 文件,格式如下:

ncols         5 
nrows         4 
xllcorner     0 
yllcorner     0 
cellsize      10 
NODATA_value  -9999 
25.4 26.1 27 28.6 27.7
25 26 26.4 27.9 27.4
25.1 25.8 26.8 28.6 27.6
27.5 28 27.7 30.6 28.3

我需要使用 libtiff.net(或其 C++ 等价物、libtiff、libgeotiff、GDAL,或任何其他 C# 或 C++ 库)来转换它到 geotiff 文件。

但是我根本不知道要设置哪些字段,有很多字段我不知道TIFFTAG_IMAGEWIDTHTIFFTAG_SAMPLESPERPIXELTIFFTAG_BITSPERSAMPLE它们是否相关。

给定一个如上所述的 ESRI ASCII 文件,如何使用 libtiff.net 或 libtiff 库创建一个 geotiff 文件?

我为什么要这样做?

在我的应用程序中,我有一个网格,我必须将网格转换为光栅文件。我想直接从网格采样创建这样一个 geotiff 栅格文件,而不先创建中间 ASCII 文件,因为与最终的 geotiff 输出文件相比,中间文件的大小非常大。

我能想到的唯一方法是在获取网格上的网格点时使用 libtiff.net 直接操作 geotiff 文件。

如何做到这一点,或者有更好的方法吗?

即使您不打算在您的应用程序中使用 GDAL(稍后会详细介绍),也没有什么能阻止您从 ESRI ASCII GRID (gdal_translate -of "GTiff" in.asc out.tif) 生成 geotiff,并检查生成的文件(这些是从给定网格生成 geotiff 的必要标签)。

AsTiffTagViewer gives the following output (similar to TiffTags utility output):

TagCode (Count DataType): Value  // my comments

ImageWidth (1 Short): 5    // ncols
ImageLength (1 Short): 4   // nrows
BitsPerSample (1 Short): 32
Compression (1 Short): Uncompressed
Photometric (1 Short): MinIsBlack
StripOffsets (1 Long): 260
SamplesPerPixel (1 Short): 1
RowsPerStrip (1 Short): 4    //nrows
StripByteCounts (1 Long): 80
PlanarConfig (1 Short): Contig
SampleFormat (1 Short): 3
33550 (3 Double): 
33922 (6 Double): 
42113 (6 ASCII): -9999    // NODATA_value

如您所见,有 11 个标准 Tiff 标签和 3 个非标准标签(但我们知道数据类型,更重要的是知道最后 3 个标签的维度,366)。让我们确认我们有 2 个 GeoTiff 标签和一个非标准 GDAL-specific 标签。

Libgeotiff C 库随 listgeo 实用程序一起分发,用于转储 GeoTIFF 元数据。输出:

Geotiff_Information:
   Version: 1
   Key_Revision: 1.0
   Tagged_Information:
      ModelTiepointTag (2,3):
         0                0                0                
         0                40               0                
      ModelPixelScaleTag (1,3):
         10               10               0                
      End_Of_Tags.
   Keyed_Information:
      End_Of_Keys.
   End_Of_Geotiff.

Corner Coordinates:
Upper Left    (       0.000,      40.000)
Lower Left    (       0.000,       0.000)
Upper Right   (      50.000,      40.000)
Lower Right   (      50.000,       0.000)
Center        (      25.000,      20.000)

根据Tagged_Information的维度我们可以识别出以下2个标签。此外,由于网格是规则的(X 和 Y 间距相等,并且没有倾斜的网格线)我们可以建立以下公式:

33550 标签:

ModelPixelScaleTag = [ cellsize , cellsize , 0 ]

33922 标签:

ModelTiepointTag = [ 0 , 0 , 0 , UpperLeftCorner_X , UpperLeftCorner_Y , 0] 

    where
            UpperLeftCorner_X = xllcorner 

            UpperLeftCorner_Y = yllcorner + cellsize * nrows

剩下最后一个标签 42113。 geotiff 格式没有用于 nodata 值的标准标记。 GDAL 在非标准 TIFFTAG_GDAL_NODATA ASCII 标签(代码 42113)中存储波段无数据值。

最后,作为示例,我们可以使用 Libgeotiff C 库编写一个将网格 (ncols, nrows, cellsize, xllcorner, yllcorner) 的 header 与 Tiff 标签相关联的函数:

void SetUpTIFFDirectory(TIFF *tif)
{
    double tiepoints[6];
    double pixscale[3];

    double upperLeftCorner_X, upperLeftCorner_Y;

    upperLeftCorner_X = xllcorner;

    upperLeftCorner_Y = yllcorner + (cellsize*nrows);

    tiepoint[0] = 0.0;
    tiepoint[1] = 0.0;
    tiepoint[2] = 0.0;
    tiepoint[3] = upperLeftCorner_X;
    tiepoint[4] = upperLeftCorner_Y;
    tiepoint[5] = 0.0;

    pixscale[0] = cellsize;
    pixscale[1] = cellsize;
    pixscale[2] = 0.0;

    TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,    ncols);
    TIFFSetField(tif,TIFFTAG_IMAGELENGTH,   nrows);
    TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE, 32);
    TIFFSetField(tif,TIFFTAG_COMPRESSION,   COMPRESSION_NONE);
    TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,   PHOTOMETRIC_MINISBLACK);
    TIFFSetField(tif,TIFFTAG_STRIPOFFSETS,  260L);
    TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL, 1);
    TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP, nrows;
    TIFFSetField(tif,TIFFTAG_STRIPBYTECOUNTS, 80L);
    TIFFSetField(tif,TIFFTAG_PLANARCONFIG,  PLANARCONFIG_CONTIG);
    TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,  3;

    TIFFSetField(tif,GTIFF_TIEPOINTS, 6,tiepoints);
    TIFFSetField(tif,GTIFF_PIXELSCALE, 3,pixscale);

}

注意:当您说您不能使用 GDAL 时,有一种内存中的栅格格式,在您添加网格样本时可以用作栅格的临时占位符:

https://www.gdal.org/frmt_mem.html

实际上,使用 GDAL 库(或其 .Net 等价物,GDAL.Net)可以轻松完成此任务。 Python中甚至还有an example here

ncols         174
nrows         115
xllcorner     14.97
yllcorner     -34.54
cellsize      0.11

和 Python 脚本:

if __name__ == '__main__':
# Import libs
import numpy, os
from osgeo import osr, gdal

# Set file vars
output_file = "out.tif"

# Create gtif
driver = gdal.GetDriverByName("GTiff")
dst_ds = driver.Create(output_file, 174, 115, 1, gdal.GDT_Byte )
raster = numpy.zeros( (174, 115) )

# top left x, w-e pixel resolution, rotation, top left y, rotation, n-s pixel resolution
dst_ds.SetGeoTransform( [ 14.97, 0.11, 0, -34.54, 0, 0.11 ] )

# set the reference info 
srs = osr.SpatialReference()
srs.SetWellKnownGeogCS("WGS84")
dst_ds.SetProjection( srs.ExportToWkt() )

# write the band
dst_ds.GetRasterBand(1).WriteArray(raster)

将代码转换为 .Net 应该很简单。