GDAL 是一个开源的操作栅格数据和矢量数据的库,本文记录下用 Python 中 GDAL 库操作 TIFF (GeoTIFF)的常见代码,包括读写、获取坐标系、获取指定位置像元值等。
一、TIFF 和 GeoTIFF 介绍
TIFF 简单理解就是一种图像格式,类似于 jpg、png 等。
GeoTIFF 就是在普通 TIFF 文件上增加了地理位置、投影信息、坐标信息等,常用于遥感数据。
二、GDAL 安装
Python 的 GDAL 包我们可以通用 pip 安装,之前老王也分享了安装过程中可能遇到的问题:《pip 安装 GDAL 包出现错误 ERROR: Command errored out with exit status 1 的解决方法》
三、代码分享
以下代码是基于处理 MAIAC AOD 的,所以只有一个波段,因此 Band 数默认就是 1 了,如果是需要多波段,就是 GetRasterBand(band)
的参数需要改一下。
读取 TIFF 文件:
def get_tif_info(tif_path): if tif_path.endswith('.tif') or tif_path.endswith('.TIF'): dataset = gdal.Open(tif_path) pcs = osr.SpatialReference() pcs.ImportFromWkt(dataset.GetProjection()) gcs = pcs.CloneGeogCS() extend = dataset.GetGeoTransform() # im_width = dataset.RasterXSize #栅格矩阵的列数 # im_height = dataset.RasterYSize #栅格矩阵的行数 shape = (dataset.RasterYSize, dataset.RasterXSize) else: raise "Unsupported file format" img = dataset.GetRasterBand(1).ReadAsArray() # (height, width) # img(ndarray), gdal数据集、地理空间坐标系、投影坐标系、栅格影像大小 return img, dataset, gcs, pcs, extend, shape
经纬度、行列号、投影坐标之间的转换(参考文章里 rowcol_to_xy 写错了):
def longlat_to_xy(gcs, pcs, lon, lat): ct = osr.CoordinateTransformation(gcs, pcs) coordinates = ct.TransformPoint(lon, lat) return coordinates[0], coordinates[1], coordinates[2] def xy_to_lonlat(gcs, pcs, x, y): ct = osr.CoordinateTransformation(gcs, pcs) lon, lat, _ = ct.TransformPoint(x, y) return lon, lat def xy_to_rowcol(extend, x, y): a = np.array([[extend[1], extend[2]], [extend[4], extend[5]]]) b = np.array([x - extend[0], y - extend[3]]) row_col = np.linalg.solve(a, b) row = int(np.floor(row_col[1])) col = int(np.floor(row_col[0])) return row, col def rowcol_to_xy(extend, row, col): x = extend[0] + col * extend[1] + row * extend[2] y = extend[3] + col * extend[4] + row * extend[5] return x, y
获取指定位置的值:
def get_value_by_coordinates(tif_pah, coordinates, coordinate_type='rowcol'): img, dataset, gcs, pcs, extend, shape = get_tif_info(tif_pah) if coordinate_type == 'rowcol': value = img[coordinates[0], coordinates[1]] elif coordinate_type == 'lonlat': x, y, _ = longlat_to_xy(gcs, pcs, coordinates[0], coordinates[1]) row, col = xy_to_rowcol(extend, x, y) value = img[row, col] elif coordinate_type == 'xy': row, col = xy_to_rowcol(extend, coordinates[0], coordinates[1]) value = img[row, col] else: raise 'coordinated_type error' return value
保存 TIFF 文件:
def save_tif(array, path, shape, geo_trans, projection, type_name): if 'int8' in type_name: datatype = gdal.GDT_Byte elif 'int16' in type_name: datatype = gdal.GDT_UInt16 else: datatype = gdal.GDT_Float32 driver = gdal.GetDriverByName('GTiff') dataset = driver.Create(path, shape[1], shape[0], 1, datatype) if dataset is not None: dataset.SetGeoTransform(geo_trans) dataset.SetProjection(projection) dataset.GetRasterBand(1).WriteArray(array)
例子:
1、取值
value = get_value_by_coordinates(tif_path, [115.8597501, 40.0485068], coordinate_type='lonlat') print(value)
2、保存 TIFF 文件
img_beijing, dataset, gcs, pcs, extend, shape = get_tif_info(aoi_path) out_path = 'out' # ratio 是一个 ndarray save_tif(ratio, out_path + '/ratio.tif', shape, extend, pcs.ExportToWkt(), ratio.dtype.name)
参考:
- https://cloud.tencent.com/developer/news/276097
- http://zhaoxuhui.top/blog/2019/07/17/GeoTIFFReading&WritingWithGDAL.html