01 HDF4文件读取示例-数据信息查询
pro week_two_study1 ; one ————》打开hdf文件以及获取数据集名称以及对应数据集的相关属性 ; 1. 获取需要打开文件的路径并赋值给变量file_path file1_path = 'D:/MYD04_3K.A2018121.0545.061.2018121172155.hdf' ; 2. 打开文件————》hdf_sd_start()函数打开hdf4文件, 返回打开文件的id(这里用变量file_id接收) file1_id = hdf_sd_start(file1_path, /read) ; 第一个参数传入文件路径, 第二个参数传入打开方式(/read表示只读, /rdwr表示读写, /create表示创建新文件) ; 3. 获取文件的数据集个数以及全局属性个数————》hdf_sd_fileinfo()函数获取文件的数据集以及全局属性个数 hdf_sd_fileinfo, file1_id, file1_ds_num, file1_attr_num ; 第一个参数传入文件地址即file1_id, 第二个传入变量file1_ds_num接收数据集个数, 第三个file1_attr_num接收属性个数 ; 接下来, 由于数据集个数我们已经知道,所以我们可以通过循环获取数据集的信息(名称以及每个数据集的内部属性名称(如果它有内部属性的话)) ; 4. 循环获取数据集信息 for file1_ds_i = 0, file1_ds_num - 1 do begin ; 由于索引是从0开始,所以数据集最大个数是file1_ds_num - 1 ; file1_ds_i只是数据集的编号, 计算机不认识, 需要通过数据集的编号得到数据集在地层中的内存地址(或者说是id) ; 4.1 获取数据集的id————》通过hdf_sd_select()函数获取编号为file1_ds_i的数据集的id file1_ds_id = hdf_sd_select(file1_id, file1_ds_i) ; 这里需要传入两个参数, 第一个就是数据集所在的文件的id(即file1_id), 第二个参数就是数据集的编号(即file1_ds_i) ; 4.2 获取数据集的名称以及其内部属性个数————》通过hdf_sd_getinfo函数获取 hdf_sd_getinfo, file1_ds_id, name=file1_ds_name, natts=file1_ds_attr_num ; 第一个参数传入数据集的id,后面 name,natts是函数内置的参数, =左边是接收的变量(和一般等号左边是变量不同) ; 4.3 输出数据集名称 ; 给出提示 print, '数据集编号为' + strcompress(string(file1_ds_i)) + ':' ; 上面的string()函数是将long int型的文件数据集编号(file1_ds_i) 转化为str型, 另外strcompress()函数将多余的空位删掉,只在有效位数前面保留一个空位 print, file1_ds_name ; 4.4 循环输出对应数据集的属性名称 ; ; 4.4.1 判断对应数据集属性个数是否为0, 如果为0则不进入循环输出 if file1_ds_attr_num ne 0 then begin ; 4.4.2 循环开始进入循环 for file1_ds_attr_i = 0, file1_ds_attr_num - 1 do begin ; 类似地, 下标为0, 所以file1_ds_attr_num - 1 ; 这里不需要根据数据集地属性编号获取数据集地id,因为下面输出属性时需要传入属性所在数据集的id ; 4.4.3 获取属性名称————》 hdf_sd_attrinfo函数获取属性的名称(其实还可以指定data=变量获取属性的信息而不只是属性名称) hdf_sd_attrinfo, file1_ds_id, file1_ds_attr_i, name=file1_ds_attr_name, data=file1_ds_attr_info ; 第一二个参数传入属性所在数据集的id,属性的编号,第三个函数内置参数name=需要接收的变量,第四个函数函数内置参数data=需要接收的变量 ; 4.4.4 输出属性名称以及属性的内容 print, file1_ds_attr_name + ':' + strcompress(string(file1_ds_attr_info)) ; 这里的string和strcompress函数和前面的类似就不赘述 endfor ; 提示数据集的属性获取成功 print, '——————获取数据集(' + file1_ds_name + ')的属性完毕!!!——————' endif ; 关闭打开的专题数据集,避免占用内存资源以及下次使用出现错误————》使用hdf_sd_endaccess函数关闭需要关闭的数据集 hdf_sd_endaccess, file1_ds_id ; 传入需要关闭数据集的内存地址即id(在哪个循环里, 那么哪个循环一开始就会打开该数据集(hdf_sd_select()),那么现在使用完毕就需要关闭该文件) ; 提示该数据集的全部信息全部获取成功 print, '——————获取数据集(' + file1_ds_name + ')相关信息完毕!!!——————' endfor ; 关闭打开的hdf4文件——————》使用hdf_sd_end函数关闭文件 hdf_sd_end, file1_id ; 传入需要关闭文件的内存地址即id ; 提示该文件的信息全部获取成功 print, '——————获取文件的相关信息完毕——————' end
02 HDF4文件读取示例-目标数据TIFF输出
pro week_two_study2 ; 本次程序需要完成的是: 便捷打开hdf4文件以及读取相关内容并做一些简单的处理输出tif影像 ; ; ; 打开文件的路径 modis_load_path = 'D:\IDL编程设计\实验数据\chapter_1\MODIS_2018_mod04_3k\MYD04_3K.A2018121.0545.061.2018121172155.hdf' modis_save_path = 'D:\IDL编程设计\实验数据\chapter_1\MODIS_2018_mod04_3k\MYD04_3K.A2018121.0545.061.2018121172155.tif' ; 打开文件————》使用hdf_sd_start()函数打开文件 modis_id = hdf_sd_start(modis_load_path, /read) ; 传入需要打开文件的路径以及读取的方式(/read, /rewr, /create三种), 返回文件的内存地址即id ; 通过HDF explorer读取到hdf4文件的相关内容,所以不再需要循环知道内部具体名字之类的信息了 ; 读取的需要的数据集的名称 modis_ds = 'Latitude' ; 获取数据集的index————》通过hdf_sd_nametoindex获取数据集的indedx(或者说是数据集的编号, 索引从0开始) modis_ds_index = hdf_sd_nametoindex(modis_id, modis_ds) ; 第一个参数传入该数据集所在文件的内存地址(即id), 第二个参数传入该数据集的名称, 返回该数据集的索引或者说是编号 ; 获取数据集的内存地址(即id)————》通过hdf_sd_select()函数获取数据集的内存地址 modis_ds_id = hdf_sd_select(modis_id, modis_ds_index) ; 第一个参数传入该数据集所在文件的id, 第二个参数传入该数据集的index ; 获取该数据集的数据————》通过hdf_sd_getdata() 获取该数据集的相关数据 hdf_sd_getdata, modis_ds_id, modis_lat_data ; 第一个参数传入该数据集的内存地址, 第二个传入的是变量, 用来接收该数据集的数据 ; 类似, 这里还需要读取Longitude数据集、Image_Optical_Depth Land And Ocean数据集, 这里不再详述 ; 获取Longitude数据集的数据 modis_ds = 'Longitude' modis_ds_indedx = hdf_sd_nametoindex(modis_id, modis_ds) modis_ds_id = hdf_sd_select(modis_id, modis_ds_index) hdf_sd_getdata, modis_ds_id, modis_lon_data ; 获取Image_Optical_Depth Land And Ocean数据集的数据 modis_ds = 'Image_Optical_Depth Land And Ocean' modis_ds_index = hdf_sd_nametoindex(modis_id, modis_ds) modis_ds_id = hdf_sd_select(modis_id, modis_ds_index) hdf_sd_getdata, modis_ds_id, modis_target_data ; 另外,由于对modis_target_data进行处理还需要该数据集下的两个属性 ; 获取属性内容(这里我们依旧通过HDF explorer软件获取了该数据集下的两个属性的名字) ; 获取该数据集下属性scale_factor的索引(或者说是编号)——————》通过函数hdf_sd_attrfind()函数获取该属性的索引 modis_att_index = hdf_sd_attrfind(modis_ds_id, 'scale_factor') ; 第一个参数传入该属性所在的数据集的id, 第二个参数传入该属性的名称 hdf_sd_attrinfo, modis_ds_id, modis_att_index, data=sf ; 第一个参数传入该属性所在数据集的id, 第二个参数传入该属性的index, 第三个传入的是变量, 用来接收该属性的内容 ; 另外还要注意的是, 得到的数据一般是数组, 所以这里得到sf也是数组 ; 类似的,获取属性_FillValue的内容, 这里不再详述 modis_att_index = hdf_sd_attrfind(modis_ds_id, '_FillValue') hdf_sd_attrinfo, modis_ds_id, modis_att_index, data=fv ; 使用完毕后需要关闭文件,这是习惯!! hdf_sd_endaccess, modis_ds_id ; hdf_sd_endaccess函数关闭数据集, 传入该数据集的内存地址即可 hdf_sd_end, modis_id ; hdf_sd_end函数关闭文件, 传入该文件的内存地址即可 ; 最后,对取出的modis_target_data, sf, fv进行处理 modis_target_data = (modis_target_data ne fv[0]) * modis_target_data * sf[0] ; 上面有两个点需要注意, 第一个fv和sf是数组, 虽然它们只有一个数,但是要取第一个数就需要加上[], 不然就会变成数组相乘 ; 第二个, 这里有modis_targte_data得到是什么反射率还是什么, 有一些是观测时有云层遮挡所以无法观测所以填充的是属性_FillValue的值, ; 还有存储的时候由于整数存储相对于浮点数存储节省空间, 所以这里还将反射率(假设我们获取的是反射率, 我没有学, 这个)乘以了某一个数使所有的观测 ; 数据都为int型或long型, 而这里的scale_factor就是这个数的倒数, 所以我们上面这个等式实际上就是将真实的观测数据计算出来 ; 这里我们让等于fillvalue的数据等于0 ; 将计算得到的真实数据保存 write_tiff, modis_save_path, modis_target_data, /float ; 另外要注意, 这里我们得到的是float型(因为sf是float型)的,所以保存格式应该指定为/float, 默认是int型 end
03 题外话
3.1 问题的出现
十分遗憾, 我的电脑由于某些原因, 无法运行这两个文件, 已经试过多种方法。
错误原因如下:
HDF_SD_START: Unable to start the HDF-SD interface.
IDL> .compile -v 'E:\IDL_workspace\Study\week_two_study2.pro' % Compiled module: WEEK_TWO_STUDY2. IDL> week_two_study2 % Compiled module: WEEK_TWO_STUDY2. % HDF_SD_START: Unable to start the HDF-SD interface. % Execution halted at: WEEK_TWO_STUDY2 10 E:\IDL_workspace\Study\week_two_study2.pro % $MAIN$
如果你的电脑也发生这种情况, 那么请告知我, 谢谢。
3.2 问题的解决
2022-7-6补:
现在已经解决了
<如果你也遇到这个问题,那么有可能该文件下载出现问题或者解压等出现问题导致该文件无法打开>
1. 一开始我以为时中文路径的原因,后来将路径修改后发现不是中文路径的缘故,而且中文路径IDL是可以的
2. 后来我以为是代码的一些拼写错误之类,后来认真检查了,发现不是。
3. 后来我以为是ENVI破解不成功,于是重装了,发现也不是
4. 在后来我以为是自身电脑品牌以及windows版本的缘故,所以我创建了虚拟机,发现不是。
以上总共花费我一个下午以及一个晚上的时间
5.最后发现是bandzip解压我的modis文件时出现了一个失误,第一个modis文件的没解压出来, 只是一个空文件。之前的所有测试都是基于第一个文件进行的。fuck!