欢迎关注博主的微信公众号:“智能遥感”。
该公众号将为您奉上Python地学分析、爬虫、数据分析、Web开发、机器学习、深度学习等热门源代码。
本人的GitHub代码资料主页(持续更新中,多给Star,多Fork):
https://github.com/xbr2017
CSDN也在同步更新:
https://blog.csdn.net/XBR_2014
“ 本节通过Python + GDAL读取MODIS HDF格式的数据集。”
作为一名遥感仁,在接触Python之前,一直使用IDL语言(遥感专业的一门语言)处理遥感数据,从几何校正、辐射定标、图像拼接、矢量裁剪栅格以及几乎所有的遥感图像运算、数据读取与常见格式的存储,无一不是通过IDL来实现的。在读研期间,甚至一度迷上用IDL制作读取与展示遥感数据的小软件界面,在毕业论文里竟然专门有一小节介绍该软件,现在想想,是多么的苍白无力。
IDL是一门小众语言,冷了不能再冷的语言。墙裂推荐:不管你是否搞科研,还是做开发,对于没有计算机编程基础(C、C++、Java等)的小伙伴们,包括软妹子吆,Python是性价比最高的语言,没有之一,简单易懂,上手快。来吧,让我们一起高喊:“人生苦短,我用Python”!
顺便多说一句,既然我们使用了Python来处理遥感数据,那就准备抛弃ArcGis、MeteoInfo之类的二次开发环境,所以在今后的遥感数据处理介绍中,争取不使用arcpy包。因为要使用该模块,自己的本本上需要安装ArcGis软件,所以还是尽量不使用arcpy。
GDAL读取HDF
今天以较为经典的卫星数据MODIS为例,讲解如何使用Python+GDAL读取HDF文件,以及输出指定投影的tif文件,这里的tif是指Geotiff文件,其中包含地理信息。
HDF为分层数据格式的文件,可以使用GetSubDatasets函数获取它们的列表,然后使用该信息打开你想要的那个数据集。
例如,让我们打开MODIS文件中包含的子数据集。请注意,默认情况下,HDAL驱动程序不包含在GDAL中,因此如果你的GDAL版本不包含HDF支持,此示例将不适用于你。假设你可以使用HDF文件,第一步是将HDF文件作为数据集打开:
from osgeo import gdal
ds = gdal.Open('MYD13Q1.A2014313.h20v11.005.2014330092746.hdf')
现在,你可以获取此开放数据集中包含的子数据集列表。GetSubDatasets方法返回元组列表,每个子数据集有一个元组。每个元组按顺序包含子数据集的名称和描述。以下代码段获取此列表,然后打印出每个子数据集的名称和描述:
subdatasets = ds.GetSubDatasets()
print 'Number of subdatasets: {}'.format(len(subdatasets))
for sd in subdatasets:
print 'Name: {0}\nDescription:{1}\n'.format(*sd)
前几行输出看起来像这样,并显示第一个子数据集的信息,即NDVI(归一化差异植被指数),这里只展示第一个,剩余11个就不放在这显示了:
Number of subdatasets: 12
Name: HDF4_EOS:EOS_GRID:"D:/osgeopy-data/Modis/MYD13Q1.A2014313.h20v11.005.2014330092746.hdf":MODIS_Grid_16DAY_250m_500m_VI:250m 16 days NDVI
Description:[4800x4800] 250m 16 days NDVI MODIS_Grid_16DAY_250m_500m_VI (16-bit integer)
要打开子数据集,请将其名称传递给gdalOpen。例如,这将获取与第一个子数据集对应的元组,从元组中获取第一个项(名称),然后使用它来打开子数据集:
ndvi_ds = gdal.Open(subdatasets[0][0])
同样,使用subdatasets[4] [0]表示打开第五个子数据集。一旦打开了这样的子数据集,它就可以像任何其他数据集一样处理。例如,你可以使用ndvi_ds.GetRasterBand(1)获取NDVI子数据集中的第一个波段。
如果没有特殊说明,HDF一般指hdf4,现在很多卫星数据开始使用hdf5格式存储,对于GDAL都可以去读取操作。当然,也有专门读取hdf4与hdf5的包,感兴趣的可以pip install安装一下相关的包就可以直接使用啦。这里给大家稍微展示一下具体代码使用:
# _*_ coding: utf-8 _*_
__author__ = 'xbr'
__date__ = '2018/11/28 22:47'
import h5py
import numpy as np
# HDF5的读取:
in_ds = h5py.File('FY4A-_AGRI--_N_DISK_1047E_L1-_FDI-_MULT_NOM_20180101024500_20180101025959_4000M_V0001.HDF','r')
# 读取FY4A静止卫星第一波段数据
array = in_ds['NOMChannel01'][:]
in_ds.close()
GDAL将数据保存为tif格式
遥感图像需要包含经纬度、空间分辨率、投影坐标等地理信息,这是普通图像所不具备的,一般彩色图像只有RGB三个波段,而遥感图像可以包含很多波段。下面的程序是读取MODIS归一化植被指数(NDVI),并将数据保存为带有地理信息的tif文件,必要的解释在代码中已给出。
# _*_ coding: utf-8 _*_
__author__ = 'xbr'
__date__ = '2018/11/26 17:48'
import gdal, osr
def array2raster(newRasterfn, rasterOrigin, xsize, ysize, array):
"""
newRasterfn: 输出tif路径
rasterOrigin: 原始栅格数据路径
xsize: x方向像元大小
ysize: y方向像元大小
array: 计算后的栅格数据
"""
cols = array.shape[1] # 矩阵列数
rows = array.shape[0] # 矩阵行数
originX = rasterOrigin[0] # 起始像元经度
originY = rasterOrigin[1] # 起始像元纬度
driver = gdal.GetDriverByName('GTiff')
outRaster = driver.Create(newRasterfn, cols, rows, 1, gdal.GDT_Float32)
# 括号中两个0表示起始像元的行列号从(0,0)开始
outRaster.SetGeoTransform((originX, xsize, 0, originY, 0, ysize))
# 获取数据集第一个波段,是从1开始,不是从0开始
outband = outRaster.GetRasterBand(1)
outband.WriteArray(array)
outRasterSRS = osr.SpatialReference()
# 代码4326表示WGS84坐标
outRasterSRS.ImportFromEPSG(4326)
outRaster.SetProjection(outRasterSRS.ExportToWkt())
outband.FlushCache()
ds = gdal.Open('D:/osgeopy-data/Modis/MYD13Q1.A2014313.h20v11.005.2014330092746.hdf')
subdatasets = ds.GetSubDatasets()
print('Number of subdatasets: {}'.format(len(subdatasets)))
for sd in subdatasets:
print('Name: {0}\nDescription:{1}\n'.format(*sd))
ndvi_ds = gdal.Open(subdatasets[0][0]).ReadAsArray()
dst_filename = "D:/nc/try.tif"
xsize = 0.0025
ysize = 0.0025
array2raster(dst_filename, [90, 75], xsize, ysize, ndvi_ds)
NDVI第一波段的灰色图像展示
NDVI第一波段的彩色图像展示