ENVI_IDL:批量重投影Modis Swath产品并指定范围输出为Geotiff格式+解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: ENVI_IDL:批量重投影Modis Swath产品并指定范围输出为Geotiff格式+解析

1. 实验内容



2. 知识储备


这里就不会对之前学过的一些函数做出声明,只对其中会使用的二次开发接口做出介绍


3.  ENVI实操对对应DL代码部分

这一部分实在没有精力,有需要再来吧,累死了。

简单说一下


1. 打开需要重投影的hdf4文件,选择好数据集(这里只需要选择lon、lat、aod三个数据)

2.打开toolbox工具箱,打开build glt应该是我记得——》这是进行创建glt地理查找表的入口

3. 选择输入输出的投影信息、x方向上的数据集、y方向的数据集。。。。。


等等等。。。。真的累了


4. 编程

function get_hdf4_ds, file_path, ds_name
   ; 函数功能: 获取数据集的数据
   ; 获取文件的id
   file_id = hdf_sd_start(file_path, /read)
   ; 获取数据集的index
   ds_index = hdf_sd_nametoindex(file_id, ds_name)
   ; 获取数据集的id
   ds_id = hdf_sd_select(file_id, ds_index)
   ; 获取数据集的数据
   hdf_sd_getdata, ds_id, ds_data
   ; 关闭数据集以及文件
   hdf_sd_endaccess, ds_id
   hdf_sd_end, file_id
   ; 返回值
   return, ds_data
end
function get_hdf4_att, file_path, ds_name, att_name
  ; 函数功能: 获取数据集的某一属性内容
  ; 获取文件的id
  file_id = hdf_sd_start(file_path, /read)  ; 意外使用中文圆括号报错——》难以发现
  ; 获取数据集的index
  ds_index = hdf_sd_nametoindex(file_id, ds_name)
  ; 获取数据集的id
  ds_id = hdf_sd_select(file_id, ds_index)
  ; 获取该属性的indedx
  att_index = hdf_sd_attrfind(ds_id, att_name)
  ; 获取该数据集的属性内容(注意,返回形式是数组)
  hdf_sd_attrinfo, ds_id, att_index, data=att_data
  ; 关闭打开的数据集以及文件
  hdf_sd_endaccess, ds_id
  hdf_sd_end, file_id
  ; 返回值
  return, att_data
end
pro week_four_test
  ; 批量重投影modis swath产品并输出为tiff格式(且限制范围为39-42, 115-118)
;总体思路:
; 1. 获取lon、lat、aod数据集以及aod数据集的两个属性并进行处理、最后存储在硬盘
; 2. 上面的数据处理包括对aod的数据进行处理,以及对三个数据进行范围限制处理(因为我们只需要北京地区范围)
; 3. 通过envi二次开发接创建glt文件(需要使用上面存储在硬盘中的lon、lat文件)
; 4. 通过envi二次开发接口参照glt地理信息查找表对aod文件进行重投影
; 5. 将上面得到的重投影文件转化为geotiff格式
  ; 由于这里需要使用envi的api接口,所以需要声明(其实我也不知道这是什么)
  compile_opt idl2
  envi,/restore_base_save_files
  envi_batch_init
  ; 路径
  in_path = 'D:/IDL_program/experiment_data/chapter_3/modis_swath'
  out_path = 'D:/IDL_program/experiment_data/chapter_3/modis_swath/geo_out'
  ; 如果out_path不存在那么创建
  if file_test(out_path) eq 0 then begin  ; 不存在函数返回0,否则返回1
    file_mkdir, out_path
  endif
  ; 获取in_path中所有的hdf文件的路径
  file_path_array = file_search(in_path, '*.hdf')  ; 传入目录,指定搜索的文件格式是'*.hdf'——》返回该目录下的所有hdf文件
  ; 获取hdf文件的总数量
  file_count = n_elements(file_path_array)
  ; 循环每一个hdf文件,获取其中的数据,并进行一系列的处理最后输出为北京地区的tiff格式
  for file_i = 0, file_count - 1 do begin
    ; 获取该循环下的文件路径
    file_path = file_path_array[file_i]
    ; 获取该循环下的文件名称
    file_name = file_basename(file_path, '.hdf')
    ; 获取该循环下的文件的数据集以及属性数据
    lon_data = get_hdf4_ds(file_path, 'Longitude')
    lat_data = get_hdf4_ds(file_path, 'Latitude')
    aod_data = get_hdf4_ds(file_path, 'Image_Optical_Depth_Land_And_Ocean')
    aod_fv = get_hdf4_att(file_path, 'Image_Optical_Depth_Land_And_Ocean', '_FillValue')
    aod_sf = get_hdf4_att(file_path, 'Image_Optical_Depth_Land_And_Ocean', 'scale_factor')
    ; 对aod数据集进行处理
    aod_data = (aod_data ne aod_fv[0]) * aod_data * aod_sf[0]  ; 你为什么老是忘记这是数组所以需要[]
    ; 存储时,我们只需要39-42, 115-119的经纬度范围,所以需要对范围进行类似裁剪
    ; 获取在目标范围的所有的像元的下标(以数组形式返回)
    pos = where((lon_data gt 115.0) and (lon_data lt 119.0) and (lat_data gt 39.0) and (lat_data lt 42.0), pos_pixel_count)  ; 119.0 39.0这些最好弄一个浮点型而不是整型会更好
    ; 像元的个数
;    pos_pixel_count = n_elements(pos)
    ; 注意,这里本来是既可以n_elements()函数获取pos的元素个数,也可以再where()函数运行时指定/count(譬如现在就是)
    ; 但是,这里需要注意,如果where里面全为0(也就是说该图像没有一个像元在北京地区,那么where会返回一个数值),那么pos会返回-1
    ; 使用where()函数接收的count参数会返回0,而使用n_elements()函数会返回1,这回导致下面这个if判断出现错误
    ; 所以推荐使用where()函数去取count即数组元素个数
    ; 如果像元个数小于0,那么也就是说这个文件一点也不包含北京地区,那么我们就不需要对其进行后续的处理了
    if pos_pixel_count eq 0 then continue  ; 那么结束循环
    ; 获取lon_data数据的总的行列数(其它lat_data、aod_data的行列数肯定也是这个)
    lon_size = size(lon_data)  ; 传入数据,返回该数据的的一些信息
    ; aod_size是一个数组,第0个数字表示aod_data数组的维度,第1个数字表示aod_data数组的总列数,第2个数表示总行数,第3个数表示元素类型的代号,第4个数表示aod_data数组的所有元素的个数
    ; 我们需要总列数
    max_cols = lon_size[1]
    ; 找到最左最右最上最下的行列号
    rows = pos / max_cols  ; 这个自己列个简单的数组试一下就知道是怎么回事,直接讲比较费劲
    cols = pos mod max_cols  ; 这个也是
    up_row = min(rows)
    down_row = max(rows)
    left_col = min(cols)
    right_col = max(cols)
    ; 对输出的lon_data、lat_data、aod_data的范围进行限制处理(下面的取值中[a:b, c:d]表示从第a列到第b列,从第c行到第d行)
    out_lon_data = lon_data[left_col:right_col, up_row:down_row]
    out_lat_data = lat_data[left_col:right_col, up_row:down_row]
    out_aod_data = aod_data[left_col:right_col, up_row:down_row]
    ; 将得到的数据存储在硬盘中,方便后envi二次开发接口api调用这些数据文件
    ; 输出路径
    out_lon_path = out_path + '/out_lon.tiff'
    out_lat_path = out_path + '/out_lat.tiff'
    out_aod_path = out_path + '/out_aod.tiff'
    ; 输出
    write_tiff, out_lon_path, out_lon_data, /float
    write_tiff, out_lat_path, out_lat_data, /float
    write_tiff, out_aod_path, out_aod_data, /float
    ; 使用envi的二次开发接口api打开上面存储的三个数据文文件——》传入文件的路径,使用关键字传参返回该文件的id
    envi_open_file, out_lon_path, r_fid=lon_id   ; 用关键字r_fid返回打开文件的id,这里用变量lon_id接收(下面类似)
    envi_open_file, out_lat_path, r_fid=lat_id
    envi_open_file, out_aod_path, r_fid=aod_id
    ; 创建glt文件(需要使用lon和lat数据文件)
    ; 创建的glt文件的输出路径
    out_glt_path = out_path + '/out_glt.img'
    out_glt_hdr_path = out_path + '/out_glt.hdr'
    ; 输入和输出的投影信息
    in_proj = envi_proj_create(/GEOGRAPHIC)
    out_proj = envi_proj_create(/GEOGRAPHIC)
    ; 调用envi_glt_doit创建glt文件
    envi_glt_doit, $
      i_proj=in_proj, x_fid=lon_id, y_fid=lat_id, x_pos=0, y_pos=0, $  ; 输入设置
      o_proj=out_proj, pixel_size=pixel_size, rotation=0.0, $  ; 输出设置pixel_size=pixel_size表示选择默认
      out_name=out_glt_path, r_fid=glt_id  ; 输出
    ; 使用glt文件对aod数据进行重投影
    ; 重投影结果的输出路径
    out_georef_path = out_path + '/georef.img'
    out_georef_hdr_path = out_path + '/georef.hdr'
    ; 开始进行重投影
    ENVI_GEOREF_FROM_GLT_DOIT, $
      glt_fid=glt_id, pos=0, $  ; 输入glt文件的id以及所在层数
      fid=aod_id, $  ; 输入需要进行重投影的文件的id
      out_name=out_georef_path, $  ; 传入输出的路径
      r_fid=georef_id  ; 输出重投影文件的id
    ; 对上面的重投影转化为tiff格式
    ; 获取重投影文件的map_info信息————》因为转化为geotiff需要地理信息
    map_info = envi_get_map_info(fid=georef_id)  ; 传入文件id,返回该文件的map_info信息(结构体形式)
    ; 但是map_info不是所有的信息都是有用的(对于我们创建geo_info结构体而言)
    ; 获取map_info的第一行(索引为0开始)的数据——》返回数组,包含四个数值,前两数是某一像元的行列数(一般是左上角的原点,行列数为0, 0),后两个数是对应前面像元的经纬度数值
    pixel_geo = map_info.(1)  ; 取值方式和之前的不一样,需要注意
    ; 获取map_info第2行的数据——》一个像元的宽和长分别表示的距离(单位是°),实际上就是空间分辨率嘛
    pixel_space = map_info.(2)
    ; 获取重投影文件的数据
    ; 首先需要获取重投影文件的dims——》调用envi_file_quer接口并传入重投影文件的id,通过关键字传参获取该重投影文件的dims
    envi_file_query, georef_id, dims=georef_dims
    ; 再获取重投影文件的数据——》
    georef_data = envi_get_data(fid=georef_id, pos=0, dims=georef_dims)
    ; 创建geo_info结构体
    geo_info={$
      MODELPIXELSCALETAG:[pixel_space[0],pixel_space[1],0.0],$
      MODELTIEPOINTTAG:[0.0,0.0,0.0,pixel_geo[2],pixel_geo[3],0.0],$
      ; 这里需要注意:我他妈傻子了,填的是pixel_geo[0],[1]——》错了,这两个数分别是左上角点的列号行号,后面两个数是左上角点的经度和纬度,所以是填pixel_geo[2], pexel_geo[3]
      GTMODELTYPEGEOKEY:2,$
      GTRASTERTYPEGEOKEY:1,$
      GEOGRAPHICTYPEGEOKEY:4326,$
      GEOGCITATIONGEOKEY:'GCS_WGS_1984',$
      GEOGANGULARUNITSGEOKEY:9102,$
      GEOGSEMIMAJORAXISGEOKEY:6378137.0,$
      GEOGINVFLATTENINGGEOKEY:298.25722}
    ; 转化为tiff文件的输出路径
    out_georef_tiff_path = out_path + '/' + file_name + '_georef.tiff'
    ; 转化为geotiff文件
    write_tiff, out_georef_tiff_path, georef_data, /float, geotiff=geo_info
    ; 关闭打开的文件
    envi_file_mng, id = lon_id, /remove
    envi_file_mng, id = lat_id, /remove
    envi_file_mng, id = aod_id, /remove
    envi_file_mng, id = glt_id, /remove
    file_delete, [out_lon_path, out_lat_path, out_aod_path, out_glt_path, out_glt_hdr_path, $
      out_georef_path, out_georef_hdr_path]
  endfor
  ; 调用接口结束声明
  envi_batch_exit,/no_confirm
end


运行结果展示:



产生的geotiff文件:



5. 题外话

5.1 n_element()与一些函数自带的count参数返回的区别

       ; 注意,这里本来是既可以n_elements()函数获取pos的元素个数,也可以再where()函数运行时指定/count(譬如现在就是)

       ; 但是,这里需要注意,如果where里面全为0(也就是说该图像没有一个像元在北京地区,那么where会返回一个数值),那么pos会返回-1

       ; 使用where()函数接收的count参数会返回0,而使用n_elements()函数会返回1,这回导致下面这个if判断出现错误

      ; 所以推荐使用where()函数去取count即数组元素个数

5.2 发现一个难以发现的错误

补(代码已经订正>>>2022-7-14):这里发现了重大错误,虽然原来的代码可以运行,也能出图,但是,出的每一幅图的左上角的经纬度都是0°,0°。这是由于我写Geotiff结构体时,误操作了,将每一幅图的左上角点的列号行号作为左上角点的经度纬度填上去了。

下面是错误代码:


   

 

下面是修改之后的代码:



目录
相关文章
|
3月前
|
自然语言处理 数据可视化 API
淘宝商品评论 API 接口:深度解析用户评论,优化产品与服务
淘宝是领先的中国电商平台,其API为开发者提供商品信息、交易记录及用户评价等数据访问服务。对于获授权的开发者和商家,可通过申请API权限、获取并解析评论数据来进行情感分析和统计,进而优化产品设计、提升服务质量、增强用户互动及调整营销策略。未授权用户可能受限于数据访问。
|
2月前
|
测试技术 UED 开发者
软件测试的艺术:从代码审查到用户反馈的全景探索在软件开发的宇宙中,测试是那颗确保星系正常运转的暗物质。它或许不总是站在聚光灯下,但无疑是支撑整个系统稳定性与可靠性的基石。《软件测试的艺术:从代码审查到用户反馈的全景探索》一文,旨在揭开软件测试这一神秘面纱,通过深入浅出的方式,引领读者穿梭于测试的各个环节,从细微处着眼,至宏观视角俯瞰,全方位解析如何打造无懈可击的软件产品。
本文以“软件测试的艺术”为核心,创新性地将技术深度与通俗易懂的语言风格相结合,绘制了一幅从代码审查到用户反馈全过程的测试蓝图。不同于常规摘要的枯燥概述,这里更像是一段旅程的预告片,承诺带领读者经历一场从微观世界到宏观视野的探索之旅,揭示每一个测试环节背后的哲学与实践智慧,让即便是非专业人士也能领略到软件测试的魅力所在,并从中获取实用的启示。
|
3月前
|
JSON Java Android开发
Android 开发者必备秘籍:轻松攻克 JSON 格式数据解析难题,让你的应用更出色!
【8月更文挑战第18天】在Android开发中,解析JSON数据至关重要。JSON以其简洁和易读成为首选的数据交换格式。开发者可通过多种途径解析JSON,如使用内置的`JSONObject`和`JSONArray`类直接操作数据,或借助Google提供的Gson库将JSON自动映射为Java对象。无论哪种方法,正确解析JSON都是实现高效应用的关键,能帮助开发者处理网络请求返回的数据,并将其展示给用户,从而提升应用的功能性和用户体验。
82 1
|
4月前
|
存储 分布式计算 DataWorks
MaxCompute产品使用合集之如何在代码中解析File类型的文件内容
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
74 11
|
4月前
|
JSON 分布式计算 大数据
MaxCompute产品使用合集之如何解析嵌套的JSON数据
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
174 0
|
29天前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
64 0
|
29天前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
51 0
|
29天前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
58 0
|
29天前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
74 0
|
9天前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
28 3

推荐镜像

更多
下一篇
无影云桌面