Python地学分析 — GDAL批量计算MODIS NDVI

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XBR_2014/article/details/85041757

欢迎关注博主的微信公众号:“智能遥感”。

该公众号将为您奉上Python地学分析、爬虫、数据分析、Web开发、机器学习、深度学习等热门源代码。

本人的GitHub代码资料主页(持续更新中,多给Star,多Fork):

https://github.com/xbr2017

CSDN也在同步更新:

https://blog.csdn.net/XBR_2014


 NDVI是遥感领域最常见的植被指数,本节分享的内容主要是通过GDAL批量计算MODIS数据的NDVI参数。其中,新的知识点涉及路径以及路径下文件名的截取,对于分母为0得出的NAN如何处理等。

首先,让我们来欣赏一下本节的封面图 — 冰盖消融后,奇幻北里海。不能够踏遍世界的每个角落,但可以遥感出地球的每个像元。

北里海 图像来自LandSat官网

NASA Landsat 8卫星上搭载的陆地成像仪(OLI)拍摄了这张大型自然彩色图像,该图显示了2016年4月16日Tyuleniy群岛周围的里海景观。美国海洋科学家诺曼·库灵从该图像中发现了一个令人费解的特征 — 纵横交错的北里海,就其图像本身而言,非常漂亮。Tyuleniy Archipelago周围的浅水区让您可以看到海底的深绿色植被。但问题是:导致出现这些线条的成因是什么?深绿色区域 — 可能是海草或底栖藻类 — 线条是海底的特征。

有些痕迹可能来自人类活动。由于拖网,类似的线条出现在世界的海洋中。但科学文献和1月的卫星图像表明,图像中大多数痕迹都是冰块的杰作。1月份,冰块位于许多线条的前端,最明显的是在图像的东北角。到了4月份,冰已消融,唯独留下冲刷的痕迹。

有科学家发表了关于这种现象的研究,他同意:“毫无疑问,这些痕迹大部分都是冰凿的结果。”奥戈罗多夫注意到里海的这一部分非常浅 — 大约3米深。冬天形成的冰通常约0.5米厚,因此大部分都不会接触到海底。但是相对较薄的冰盖,很容易受风和水流的影响导致变形。当冰块被推到一起时,一些冰被迫向上和向下进入所谓的“小丘”。冰原中小丘的脊梁可以深入海底并在冰块移动时冲刷海床(文字描述译自LandSat官网)。


使用多光谱图像的一个常见任务就是计算各种目标指数,例如区分燃烧和未燃烧的土地或测量植被中含有的氮。让我们看一下用于衡量“绿度”的指数,即归一化植被指数(NDVI)。NDVI是一个简单的指数,使用红色和近红外波长产生-1到1之间的数字。生长的植物使用红色波长进行光合作用,但反射近红外辐射,因此这两个测量的高比率可以表明光合作用和健康的植被。

对于图中的体育场内的场地,左边的自然彩色图中看起来像草,右边的假彩色图像看起来是灰色的,这表明它是人造的。另外,练习场在左侧的自然彩色图像中看起来像草,但在右侧的图像中看起来是红色,表示它们确实是草。

红色,近红外和NDVI图像是单一波段,较亮区域的值较高。请注意,红色波段图像中的植被是暗的,而近红外波段中的植被是明亮的。植被吸收红光并反射近红外线,这些像元值测量的是反射回传感器的信号,就像我们的眼睛看到反射回来的东西一样。彩色红外复合材料仅是视觉图像。我们的眼睛可以看到植被看起来是红色的,这就是NDVI的用武之地。NDVI图像中的练习场很明亮,这意味着它们具有很高的值并且代表了不断生长的植被。体育场很暗,很容易确定它是人造场地。

下面,我们就通过Python GDAL来批量计算MODIS NDVI,本数据由中国农业大学的一位热心小伙伴提供,她已经通过MRT对MODIS原始数据进行了几何校正与图像拼接、裁剪,所以本节直接用的是处理好后的ENVI标准格式的数据,而非hdf数据,该示例数据已上传到我的CSDN(https://download.csdn.net/download/xbr_2014/10854454),可以免费下载。具体代码如下(已给出关键解释):

# _*_ coding: utf-8 _*_
__author__ = 'xbr'
__date__ = '2018/12/16 16:57'

import os
import numpy as np
from osgeo import gdal
import glob


list_tif = glob.glob('D:\data\*.tif')
out_path = 'D:/'

for tif in list_tif:
    in_ds = gdal.Open(tif)
    # 获取文件所在路径以及不带后缀的文件名
    (filepath, fullname) = os.path.split(tif)
    (prename, suffix) = os.path.splitext(fullname)
    if in_ds is None:
        print('Could not open the file ' + tif)
    else:
        # 将MODIS原始数据类型转化为反射率
        red = in_ds.GetRasterBand(1).ReadAsArray() * 0.0001
        nir = in_ds.GetRasterBand(2).ReadAsArray() * 0.0001
        ndvi = (nir - red) / (nir + red)
        # 将NAN转化为0值
        nan_index = np.isnan(ndvi)
        ndvi[nan_index] = 0
        ndvi = ndvi.astype(np.float32)
        # 将计算好的NDVI保存为GeoTiff文件
        gtiff_driver = gdal.GetDriverByName('GTiff')
        # 批量处理需要注意文件名是变量,这里截取对应原始文件的不带后缀的文件名
        out_ds = gtiff_driver.Create(out_path + prename + '_ndvi.tif',
                         ndvi.shape[1], ndvi.shape[0], 1, gdal.GDT_Float32)
        # 将NDVI数据坐标投影设置为原始坐标投影
        out_ds.SetProjection(in_ds.GetProjection())
        out_ds.SetGeoTransform(in_ds.GetGeoTransform())
        out_band = out_ds.GetRasterBand(1)
        out_band.WriteArray(ndvi)
        out_band.FlushCache()

对于处理长时间序列的遥感影像,批量处理是遥感数据处理家常便饭的事。需要注意的是,批量输出文件名是通过截取对应的输入文件名(去掉后缀)加上ndvi.tif来进行命名。程序中的数据是整型,需要除以10000,转化为大气表观反射率,再进行公式计算。由于图像背景值为0,所以在计算NDVI时,会有像元为0的值出现在分母上,这时候对应像元的计算结果为NAN,程序中通过Numpy的isnan()将NAN替换为0,当然你也可以替换成其他有效数值作为背景值,如-99。最后展示一下NDVI结果图:

吉林省2000年4月1日NDVI结果图,红色(负值)表示水体、冰雪、云等

吉林省2000年4月9日NDVI结果图,红色(负值)表示水体、冰雪、云等

猜你喜欢

转载自blog.csdn.net/XBR_2014/article/details/85041757