C# Unity中使用LibTiff.NET获取GeoTiff经纬度范围及指定区域像素方法问询
关于LibTiff.NET能否读取所需地理参数
可以读取,你找不到对应参数是因为GeoTIFF的地理元数据没有存在标准TIFF标签中,而是存储在GeoTIFF规范定义的扩展私有标签下,LibTiff.NET支持读取这些自定义标签,步骤如下:
- 所需的X/Y分辨率存储在Tag ID为
33550的ModelPixelScaleTag中,值为double类型数组,依次对应X方向分辨率、Y方向分辨率、Z方向分辨率 - 像素坐标与地理坐标的对应关系存储在Tag ID为
33922的ModelTiepointTag中,每个控制点对应6个double值,依次为:像素X、像素Y、像素Z、地理X、地理Y、地理Z,常规无偏移的GeoTIFF第一个控制点即为左上角(0,0)像素对应的地理坐标 - 坐标系、坐标单位等参数存储在Tag ID为
34735的GeoKeyDirectoryTag中,需要读取该标签确认坐标单位是米还是度,避免后续50米范围计算出现误差 - 若GeoTIFF存在旋转、偏移,还需要读取Tag ID为
34264的ModelTransformationTag获取仿射变换矩阵,用于坐标换算
对应示例代码:
using BitMiracle.LibTiff.Classic; using (Tiff tiff = Tiff.Open("测试文件路径.tif", "r")) { // 读取像素分辨率 FieldValue[] scaleField = tiff.GetField((TiffTag)33550); double xResolution = default, yResolution = default; if (scaleField != null) { double[] scaleValues = scaleField[0].ToDoubleArray(); xResolution = scaleValues[0]; yResolution = scaleValues[1]; } // 读取控制点 FieldValue[] tiepointField = tiff.GetField((TiffTag)33922); double upperLeftLon = default, upperLeftLat = default; if (tiepointField != null) { double[] tiepointValues = tiepointField[0].ToDoubleArray(); // 取第一个控制点的地理坐标 upperLeftLon = tiepointValues[3]; upperLeftLat = tiepointValues[4]; } // 读取影像宽高 int imageWidth = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt(); int imageHeight = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt(); // 正北无旋转场景下计算四至边界 double bboxLeft = upperLeftLon; double bboxTop = upperLeftLat; double bboxRight = upperLeftLon + imageWidth * xResolution; double bboxBottom = upperLeftLat - imageHeight * yResolution; }
后续实现指定经纬度范围读取像素块时,需先完成经纬度到影像坐标系的转换,再换算出目标像素范围,若影像为分块存储格式,可直接读取对应块的内容无需加载全图。
替代方案:GDAL封装版
如果不想自行处理标签解析、坐标系转换、不同压缩格式兼容等问题,更推荐使用Unity适配的GDAL封装库:
- 直接调用
GDAL.Open打开文件后,通过Dataset.GetGeoTransform()方法即可直接获取完整的坐标变换参数,无需手动解析各个扩展标签 - 原生支持分块读取,调用
Dataset.ReadRaster()方法时直接指定目标像素的偏移量、读取宽高,即可直接读取对应范围的像素数据,自动处理分块/条带存储、压缩解压等逻辑 - 内置坐标转换工具,可直接完成WGS84经纬度到影像投影坐标系的转换,无需额外引入坐标转换库,兼容性覆盖绝大多数生产级GeoTIFF格式
内容的提问来源于stack exchange,提问作者FacePuncher7
相关产品推荐
相关产品推荐

