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

遥感影像导出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()

问题原因

  1. 写入TIFF时未显式指定NoData值,Rasterio默认用1e+20填充掩码区域,导致最大值异常。
  2. 不必要的min-max归一化:原始影像的NBR/NDVI已经是0-1范围,掩码区域的存在会干扰min/max计算,反而破坏原有数值范围。
  3. 掩码数组未正确转换为可识别的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:34:57