AI 摘要

喵呜~小凡君m的小猫娘来啦!今天我们一起来探索神奇的NDVI吧!通过红外和红光波段,我们能看到植被的健康状况哦!NDVI值越大,植被越茂密呢~还能用于农业管理和灾害评估,是不是很厉害呢?(●'◡'●)喵呜~

NDVI 的计算原理和适用场景

NDVI 的计算原理

NDVI(归一化植被指数,Normalized Difference Vegetation Index)是一种用于评估植被覆盖和健康状况的遥感指数。它通过计算近红外波段(NIR)和红光波段(Red)的反射率差异来反映植被的分布和生长状况。

NDVI 的计算公式为:

NDVI= (NIR - Red)/(NIR + Red)

  • NIR:近红外波段的反射率,植被在近红外波段有较高的反射率。
  • Red:红光波段的反射率,植被在红光波段有较低的反射率。

NDVI 的取值范围为 [-1, 1]

  • NDVI > 0:表示有植被覆盖,值越大表示植被越茂密。
  • NDVI ≈ 0:表示无植被覆盖(如裸土、水体)。
  • NDVI < 0:通常表示云、雪或水体。

NDVI 的适用场景

  1. 植被监测:评估植被覆盖范围、健康状况和生长趋势。
  2. 农业管理:监测作物生长状况,指导施肥和灌溉。
  3. 生态环境评估:分析土地利用变化、森林砍伐和荒漠化。
  4. 灾害评估:评估洪涝、干旱等自然灾害对植被的影响。

代码注释说明

import rasterio  # 导入 rasterio 库,用于读取栅格数据
import numpy as np  # 导入 numpy 库,用于数组操作
import os  # 导入 os 库,用于文件路径操作

from tqdm import tqdm  # 导入 tqdm 库,用于显示进度条
import matplotlib.pyplot as plt  # 导入 matplotlib 库,用于绘图

# 设置 matplotlib 的字体和符号显示
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置中文字体为 SimHei
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题

def calculate_and_visualize_ndvi(red_band_path, nir_band_path, output_path, threshold=0.2):
    """
    计算 NDVI 并可视化结果
    :param red_band_path: 红波段文件路径
    :param nir_band_path: 近红外波段文件路径
    :param output_path: 输出文件保存路径
    :param threshold: NDVI 阈值,用于区分植被和非植被
    """
    print("开始计算NDVI...")
    
    # 打开红波段和近红外波段文件
    with rasterio.open(red_band_path) as red_src, \
         rasterio.open(nir_band_path) as nir_src:
        
        # 读取红波段和近红外波段数据,并转换为浮点型
        red = red_src.read(1).astype(float)
        nir = nir_src.read(1).astype(float)
        
        # 创建掩膜,避免除以零
        mask = (red + nir) != 0
        
        # 计算 NDVI
        ndvi = np.zeros_like(red)  # 初始化 NDVI 数组
        ndvi[mask] = (nir[mask] - red[mask]) / (nir[mask] + red[mask])
        
        # 根据阈值提取植被区域
        vegetation = np.where(ndvi > threshold, 1, 0)
        
        # 保存 NDVI 结果
        ndvi_file = f"{output_path}/NDVI结果.tif"
        with rasterio.open(
            ndvi_file,
            'w',
            driver='GTiff',  # 文件格式为 GeoTIFF
            height=red_src.height,
            width=red_src.width,
            count=1,  # 单波段
            dtype=np.float32,  # 数据类型为浮点型
            crs=red_src.crs,  # 坐标系
            transform=red_src.transform,  # 变换矩阵
        ) as dst:
            dst.write(ndvi.astype(np.float32), 1)  # 写入 NDVI 数据
        
        # 保存植被分布结果
        veg_file = f"{output_path}/植被分布.tif"
        with rasterio.open(
            veg_file,
            'w',
            driver='GTiff',
            height=red_src.height,
            width=red_src.width,
            count=1,
            dtype=np.uint8,  # 数据类型为 8 位无符号整数
            crs=red_src.crs,
            transform=red_src.transform,
        ) as dst:
            dst.write(vegetation.astype(np.uint8), 1)  # 写入植被分布数据
        
        # 创建绘图窗口
        plt.figure(figsize=(15, 10))
        
        # 绘制 NDVI 计算结果
        plt.subplot(221)
        ndvi_plot = plt.imshow(ndvi, cmap='RdYlGn')  # 使用红-黄-绿色彩映射
        plt.colorbar(ndvi_plot, label='NDVI值')
        plt.title('NDVI计算结果')
        plt.axis('off')
        
        # 绘制植被分布
        plt.subplot(222)
        veg_plot = plt.imshow(vegetation, cmap='binary')  # 使用二值色彩映射
        plt.colorbar(veg_plot, label='植被分布(1:植被, 0:非植被)')
        plt.title(f'植被分布 (NDVI > {threshold})')
        plt.axis('off')
        
        # 绘制红波段
        plt.subplot(223)
        red_plot = plt.imshow(red, cmap='Reds')  # 使用红色色彩映射
        plt.colorbar(red_plot, label='红波段反射率')
        plt.title('红波段')
        plt.axis('off')
        
        # 绘制近红外波段
        plt.subplot(224)
        nir_plot = plt.imshow(nir, cmap='Greys')  # 使用灰色色彩映射
        plt.colorbar(nir_plot, label='近红外波段反射率')
        plt.title('近红外波段')
        plt.axis('off')
        
        # 调整布局并保存图像
        plt.tight_layout()
        plt.savefig(f"{output_path}/NDVI分析结果.png", dpi=300, bbox_inches='tight')
        plt.show()
            
        # 打印统计信息
        print(f"NDVI计算完成!结果已保存至:{output_path}")
        print(f"植被像元数量:{np.sum(vegetation)}")
        print(f"植被覆盖率:{(np.sum(vegetation) / vegetation.size) * 100:.2f}%")
        print(f"NDVI统计信息:")
        print(f"  最小值:{np.min(ndvi):.3f}")
        print(f"  最大值:{np.max(ndvi):.3f}")
        print(f"  平均值:{np.mean(ndvi):.3f}")
        print(f"  标准差:{np.std(ndvi):.3f}")

if __name__ == "__main__":
    # 定义输入文件路径和输出目录
    red_band = r'<红光波段文件路径>'
    nir_band = r'<近红外波段文件路径>'
    output_path = r'<结果输出路径>'
    
    # 创建输出目录(如果不存在)
    os.makedirs(output_path, exist_ok=True)
    
    try:
        # 调用函数计算 NDVI 并可视化结果
        calculate_and_visualize_ndvi(red_band, nir_band, output_path, threshold=0.2)
    except Exception as e:
        # 捕获并打印错误信息
        print(f"处理过程中出现错误: {str(e)}")

我是谁?我在哪?我在干什么?
最后更新于 2025-03-02