如何裁剪TIFF文件中的NoData值区域?
移除RGB TIFF的NoData边框并裁剪文件
现有一个3通道RGB TIFF文件,边缘存在25像素值为0的边框,且所有通道已设置NoData值(值为0)。原始文件尺寸为10534×7034,需要裁剪该文件以彻底移除所有NoData区域。
以下是用于设置NoData值的Python代码:
from osgeo import gdal from osgeo.gdalconst import GDT_Float32, GDT_Byte import sys import numpy as np path = r"C:\Test\file.tif" path_output = r"C:\Test\file_res.tif" def fix_dem_nodata(raster_input, raster_output, nodata=0, threshold=0): try: in_data, out_data = None, None in_data = gdal.Open(raster_input) if in_data is None: print('无法打开文件 %s' % raster_input) return None print('栅格波段数量: %s' % in_data.RasterCount) file_data = list() for i in range(1, in_data.RasterCount+1): file_data.append(in_data.GetRasterBand(i)) raster_datatype = gdal.GetDataTypeName(file_data[1].DataType) if raster_datatype == 'Byte': raster_datatype = GDT_Byte print('文件波段类型: %s' % raster_datatype) driver = in_data.GetDriver() print('文件驱动: %s' % driver) rows = in_data.RasterYSize cols = in_data.RasterXSize geo_transform = in_data.GetGeoTransform() geo_projection = in_data.GetProjection() print('文件地理变换参数: %s' % repr(geo_transform)) print('文件投影信息: %s' % repr(geo_projection)) out_data = driver.Create(raster_output, cols, rows, in_data.RasterCount, raster_datatype) if out_data is None: print ('无法创建输出文件 %s' % raster_output) return None for i in range(0, len(file_data)): dem_data = np.array(file_data[i].ReadAsArray(0, 0, cols, rows)) dem_data[dem_data < threshold] = nodata out_band = out_data.GetRasterBand(i+1) out_band.WriteArray(dem_data, 0, 0) out_band.FlushCache() out_band.SetNoDataValue(nodata) print(i) out_data.SetGeoTransform(geo_transform) out_data.SetProjection(geo_projection) return raster_output except Exception as e: print("错误: %s" % repr(e)) return None finally: del in_data del out_data fix_dem_nodata(path, path_output)
裁剪NoData区域的解决方案
要完全移除NoData边框,需先确定所有通道都为有效数据的边界范围,再基于该范围裁剪文件。以下是实现代码:
from osgeo import gdal import numpy as np def crop_nodata_borders(input_path, output_path): # 打开输入文件 ds = gdal.Open(input_path) if not ds: print("无法打开输入文件") return # 读取所有波段数据及对应NoData值 bands_data = [] for band_idx in range(ds.RasterCount): band = ds.GetRasterBand(band_idx + 1) nodata_val = band.GetNoDataValue() band_array = band.ReadAsArray() bands_data.append((band_array, nodata_val)) # 生成有效数据掩码:仅保留所有通道都不为NoData的区域 valid_mask = np.ones_like(bands_data[0][0], dtype=bool) for data, nodata in bands_data: valid_mask &= (data != nodata) # 定位有效数据的边界坐标 valid_rows = np.any(valid_mask, axis=1) valid_cols = np.any(valid_mask, axis=0) y_start, y_end = np.where(valid_rows)[0][[0, -1]] x_start, x_end = np.where(valid_cols)[0][[0, -1]] # 计算裁剪后的地理变换参数 original_gt = ds.GetGeoTransform() new_gt = ( original_gt[0] + x_start * original_gt[1], original_gt[1], original_gt[2], original_gt[3] + y_start * original_gt[5], original_gt[4], original_gt[5] ) # 创建输出文件 driver = ds.GetDriver() out_ds = driver.Create( output_path, x_end - x_start + 1, y_end - y_start + 1, ds.RasterCount, ds.GetRasterBand(1).DataType ) out_ds.SetProjection(ds.GetProjection()) out_ds.SetGeoTransform(new_gt) # 写入裁剪后的数据并保留NoData设置 for band_idx in range(ds.RasterCount): data, nodata = bands_data[band_idx] cropped_data = data[y_start:y_end+1, x_start:x_end+1] out_band = out_ds.GetRasterBand(band_idx + 1) out_band.WriteArray(cropped_data) if nodata is not None: out_band.SetNoDataValue(nodata) out_band.FlushCache() # 清理资源 del ds, out_ds print(f"裁剪完成,输出文件已保存至 {output_path}") # 调用裁剪函数(使用设置好NoData的文件作为输入) input_tif = r"C:\Test\file_res.tif" output_tif = r"C:\Test\file_cropped.tif" crop_nodata_borders(input_tif, output_tif)
操作步骤说明
- 先运行
fix_dem_nodata函数,确保所有通道的NoData值正确设置为0。 - 再运行
crop_nodata_borders函数:- 生成跨所有通道的有效数据掩码,精准定位无NoData的区域边界。
- 调整地理变换参数,保证裁剪后的文件坐标信息与原始数据匹配。
- 生成裁剪后的新TIFF文件,保留原始投影和NoData配置。
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

