遥感影像导出NoData值异常问题求助(基于Rasterio)
问题描述
我从事遥感相关工作,使用的卫星影像包含2个波段:波段0为NBR、波段1为NDVI,二者数值范围均为0至1。这些影像从Google Earth Engine下载,其NoData值设为-9999。为将影像用于自研深度学习算法,我需要移除这些NoData值而非替换为其他值。我已编写掩码处理-9999的代码,但导出到新文件夹后,原NoData区域被填充为1e+20,影像最大值异常,而非预期的1。使用Rasterio库,尝试多种方法均未解决,特此求助。
原始代码:
import os import numpy as np import rasterio from matplotlib import pyplot as plt # Folder paths folder_path = '/content/drive/MyDrive/2018-2022 NDVI NBR/zonauno' processed_folder = '/content/drive/MyDrive/2018-2022 NDVI NBR/zonaunonodata' # Nodata value nodata_value = -9999 # Create the "processed_folder" if it doesn't exist os.makedirs(processed_folder, exist_ok=True) # Get the list of TIFF files tiff_files = [file for file in os.listdir(folder_path) if file.endswith('.tif')] # Process each TIFF file for tiff_file in tiff_files: tiff_path = os.path.join(folder_path, tiff_file) with rasterio.open(tiff_path) as src: data = src.read(masked=True) # Read data as a numpy array # Make sure you are working with 2 channels if data.shape[0] >= 2: data = data[:2] # Exclude nodata values and normalize data_without_nodata = np.ma.masked_where(data == nodata_value, data) normalized_data = np.zeros_like(data_without_nodata) for i in range(normalized_data.shape[0]): min_val = data_without_nodata[i].min() max_val = data_without_nodata[i].max() normalized_data[i] = (data_without_nodata[i] - min_val) / (max_val - min_val) # Save normalized image save_path = os.path.join(processed_folder, f'processed_{tiff_file}') with rasterio.open( save_path, 'w', driver='GTiff', height=normalized_data.shape[1], width=normalized_data.shape[2], count=normalized_data.shape[0], dtype=str(normalized_data.dtype), crs=src.crs, transform=src.transform, ) as dst: dst.write(normalized_data) # Visualize the first processed file (optional) plt.figure(figsize=(10, 10)) plt.imshow(normalized_data[0], cmap='viridis', vmin=0, vmax=1) plt.colorbar(label='Pixel value') plt.title(f'Normalized Image - {tiff_file} - Channel 0') plt.xlabel('Columns') plt.ylabel('Rows') plt.show()
问题原因
- 写入TIFF时未显式指定NoData值,Rasterio默认用
1e+20填充掩码区域,导致最大值异常。 - 不必要的min-max归一化:原始影像的NBR/NDVI已经是0-1范围,掩码区域的存在会干扰min/max计算,反而破坏原有数值范围。
- 掩码数组未正确转换为可识别的NoData值,Rasterio无法识别哪些像素是无效的。
修正后的代码
import os import numpy as np import rasterio from matplotlib import pyplot as plt # 文件夹路径 folder_path = '/content/drive/MyDrive/2018-2022 NDVI NBR/zonauno' processed_folder = '/content/drive/MyDrive/2018-2022 NDVI NBR/zonaunonodata' # 原始NoData值 nodata_value = -9999 # 导出时使用的NoData值(浮点数影像推荐用np.nan,也可保留-9999) export_nodata = np.nan # 创建输出文件夹 os.makedirs(processed_folder, exist_ok=True) # 获取所有TIFF文件 tiff_files = [file for file in os.listdir(folder_path) if file.endswith('.tif')] # 批量处理每个文件 for tiff_file in tiff_files: tiff_path = os.path.join(folder_path, tiff_file) with rasterio.open(tiff_path) as src: # 读取带掩码的数据 data = src.read(masked=True) # 保留前2个波段 if data.shape[0] >= 2: data = data[:2] # 移除原始NoData值:将掩码区域填充为指定的export_nodata # 原始数据已是0-1范围,无需额外归一化 processed_data = np.ma.filled(data, fill_value=export_nodata) # 保存处理后的影像 save_path = os.path.join(processed_folder, f'processed_{tiff_file}') with rasterio.open( save_path, 'w', driver='GTiff', height=processed_data.shape[1], width=processed_data.shape[2], count=processed_data.shape[0], dtype=processed_data.dtype, crs=src.crs, transform=src.transform, nodata=export_nodata # 关键:显式声明NoData值 ) as dst: dst.write(processed_data) # 可视化最后一个处理后的文件(可选) plt.figure(figsize=(10, 10)) # 过滤掉NoData值再显示 plt.imshow(np.ma.masked_invalid(processed_data[0]), cmap='viridis', vmin=0, vmax=1) plt.colorbar(label='Pixel value') plt.title(f'Processed Image - {tiff_file} - Channel 0 (NBR)') plt.xlabel('Columns') plt.ylabel('Rows') plt.show()
关键修改说明
- 显式指定NoData值:写入TIFF时通过
nodata=export_nodata参数告诉Rasterio哪些是无效像素,彻底避免默认填充1e+20的问题。推荐用np.nan,因为它是浮点数类型影像的标准无效值,也可以继续用-9999,但要确保影像 dtype 兼容(比如float32)。 - 移除多余归一化:原始影像的NBR/NDVI已经是0-1范围,不需要再做min-max归一化。如果后续确实需要归一化,要先提取非掩码区域计算统计值:
# 示例:针对有效像素做归一化(按需使用) for i in range(data.shape[0]): valid_pixels = data[i].compressed() min_val = valid_pixels.min() max_val = valid_pixels.max() data[i] = (data[i] - min_val) / (max_val - min_val) - 正确处理掩码:用
np.ma.filled()将掩码区域转换为指定的NoData值,确保Rasterio能识别并标记这些无效区域。
内容的提问来源于stack exchange,提问作者Kevin Galvan
相关产品推荐
相关产品推荐

