You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何裁剪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)

操作步骤说明

  1. 先运行fix_dem_nodata函数,确保所有通道的NoData值正确设置为0。
  2. 再运行crop_nodata_borders函数:
    • 生成跨所有通道的有效数据掩码,精准定位无NoData的区域边界。
    • 调整地理变换参数,保证裁剪后的文件坐标信息与原始数据匹配。
    • 生成裁剪后的新TIFF文件,保留原始投影和NoData配置。

内容的提问来源于stack exchange,提问作者Denis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 17:15:43