ENVI IDL:如何将txt文本文件转化为GeoTIFF文件?

01 前言

此处的文本文件形式如下:

在这里插入图片描述

里面包含了众多点位信息(不是站点数据),我们需要依据上述点的经纬度信息放到对应位置的像素点位置,放置完后如下:

在这里插入图片描述

可以发现,还存在部分缺失值,我们还需要进行缺失值的填补。

02 文本文件的读取

IDL读取文本文件还是不够方便,稍微封装了一下。

;+
;   函数用途:
;       用于读取文本文件
;   函数参数:
;       txt_path: 文本文件的路径
;       ds: 读取的输出数据集(不含表头)
;       header(关键字参数): 读取的输出表头
;       separator(关键字参数): 分隔符,默认空白符 
;-
pro read_txt, txt_path, ds, header=header, separator=separator
    if ~keyword_set(separator) then separator = " "
        
    ; 读取和检索
    openr, 1, txt_path  ; 打开文本文件
    ; 是否指定输出的header
    if ~arg_present(header) then begin
        skip_lun, 1, 0
    endif else begin
        header = ''
        readf, 1, header  ; 读取表头
        header = strsplit(header, separator, /extract)
    endelse
    ; 读取和处理数据集
    ds = strarr(file_lines(txt_path) - 1)
    readf, 1, ds
    ds = list(ds, /extract)  ; 字符串数组转化为列表
    ds = ds.map(lambda(e, separator: double(strsplit(e, separator, /extract))), separator)
    ds = ds.toarray()  ; 列表转化为数组
    
    free_lun, 1
end

还好,算是可以用的程度了。

03 栅格矩阵的放置

于是乎,我们开始进行文件的读取和转数组。

pro txt_to_tiff
    ; 准备
    in_path = 'D:\Objects\JuniorFallTerm\IDLProgram\Experiments\ExperimentalData\Week6\2013_year_aop.txt'
    out_dir = 'D:\Objects\JuniorFallTerm\IDLProgram\Experiments\ExperimentalData\Week6\out_tif_by_txt_me\'
    if ~file_test(out_dir, /directory) then file_mkdir, out_dir
    out_res = 0.18d
    out_res_half = out_res / 2.0d

    ; 读取和检索
    read_txt, in_path, ds, header=header
    lon = ds[*, 0]
    lat = ds[*, 1]
    ds = ds[*, 2:*]
    header = header[2:*]
    lon_min = min(lon) - out_res_half
    lon_max = max(lon) + out_res_half
    lat_min = min(lat) - out_res_half
    lat_max = max(lat) + out_res_half
    cols = ceil((lon_max - lon_min) / out_res)
    rows = ceil((lat_max - lat_min) / out_res)
    lon_cols = floor((lon - lon_min) / out_res)
    lat_rows = floor((lat_max - lat) / out_res)
    foreach header_ele, header, header_ix do begin
        target = make_array(cols, rows, value=!values.F_NAN)
        target[lon_cols, lat_rows] = ds[*, header_ix]
        
        ; 填充
        window_interp, target, target_interp, interp=2
        
        ; 输出
        out_path = out_dir + header_ele + '.tiff'
        write_img, out_path, target_interp, out_res, lon_min, lat_max
    endforeach
end

在循环中,可以发现,使用了自定义的window_interp函数对target栅格矩阵进行缺失值的填补。

关于window_interp函数的定义由于封装的比较多,叠的比较层数比较多,阅读稍微有困难。学python的时候我是真的讨厌那些一个简单的功能的非要定义一个类,类又叠类,方法重组,来回找实现方法,来回折腾,本身功能不算特别复杂,但是被这么一折腾反而给阅读代码带来困难。

然而,我现在还是成为了他们。But 我将尽量让代码的逻辑清晰可见,不过分抽象,如有必要我抽出部分功能进行整合,避免使用过于复杂的代码框架搭建简单的功能。

以下是关于填补缺失值的封装函数,主要基于滑动窗口实现,包括滑动窗口均值填补和最近邻填补。
涉及自定义函数:window_interppaddinginterp_nearestmeshgrid

;+
;   函数用途:
;       用于对二维数组进行边界填充
;   函数参数:
;       array: 用于边界填充的数组
;       pad_size: 单边(上下左右)填充的大小
;       pad_value(关键字参数: NAN): 填充的数值
;-
function padding, array, pad_size, pad_value=pad_value
    if ~keyword_set(pad_value) then pad_value = !values.F_NAN
    
    ; 获取基本信息
    ds_size = size(array, /dimensions)
    ds_type = size(array, /type)
    ds_size += pad_size * 2
    
    ; pad
    pad_array = make_array(ds_size, type=ds_type, value=pad_value)
    pad_array[pad_size:(ds_size[0] - pad_size - 1), $
        pad_size:(ds_size[1] - pad_size - 1)] = array
        
    return, pad_array
end

;+
;   函数用途:
;       用于生成行列号格网矩阵
;   函数参数:
;       cols_n: 列数
;       rows_n: 行数
;-
function meshgrid, cols_n, rows_n
    window_cols = rebin(findgen(cols_n, 1), cols_n, rows_n)
    window_rows = rebin(findgen(1, rows_n), cols_n, rows_n)
    
    return, list(window_cols, window_rows)
end

function interp_nearest, window_ds
    ; 获取数组尺寸
    window_size = size(window_ds, /dimensions)
    cols_n = window_size[0]
    rows_n = window_size[1]
    
    ; 生成行列号矩阵
    cols_rows = meshgrid(cols_n, rows_n)
    cols = cols_rows[0]
    rows = cols_rows[1]
    
    ; 计算距离矩阵
    center_col = cols_n / 2
    center_row = rows_n / 2
    distance = sqrt((cols - center_col) ^ 2.0 +(rows - center_row) ^ 2.0)
    invalid_pos = where(finite(window_ds, /nan))
    distance[invalid_pos] = !values.F_NAN
    
    interp_value = (window_ds[where(distance eq min(distance, /nan))])[0]
    
    return, interp_value
end

;+
;   函数用途:
;       该函数用于对栅格矩阵中缺失值基于滑动窗口进行填充
;   函数参数:
;       dataset: 需要进行填补的栅格矩阵
;       dataset_interp: 输出的经填补好的栅格矩阵
;       window_size(默认: 3): 窗口大小(奇数)
;       interp: 填充的方法(1: 窗口均值; 2: 最近邻)
;-
pro window_interp, dataset, dataset_interp, window_size = window_size, interp = interp
    ds_size = size(dataset, /dimensions)
    ds_type = size(dataset, /type)
    
    ; 边界填充
    if ~keyword_set(window_size) then window_size = 3
    padding_size = window_size / 2
    ds_size += padding_size * 2
    dataset_pad = padding(dataset, padding_size)
    dataset_interp = padding(dataset, padding_size)
    
    ; 插值
    for col_ix=padding_size, ds_size[0] - padding_size - 1 do begin
        for row_ix=padding_size, ds_size[1] - padding_size - 1 do begin
            ; 若不是NAN跳过
            if ~finite(dataset_pad[col_ix, row_ix], /nan) then continue
            
            ; 取窗口数组
            window_ds = dataset_pad[col_ix-padding_size: col_ix+padding_size, $
                row_ix-padding_size: row_ix+padding_size]
            if (where(~finite(window_ds, /nan), /null) eq !null) then continue  ; 若窗口内均为NAN则跳过
            
            ; 插值
            if interp eq 1 then interp_value = mean(window_ds, /nan)
            if interp eq 2 then interp_value = interp_nearest(window_ds)
            
            ; 赋值
            dataset_interp[col_ix, row_ix] = interp_value
        endfor
    endfor
    
    ; no padding
    dataset_interp = dataset_interp[padding_size:(ds_size[0] - padding_size - 1), $
        padding_size:(ds_size[1] - padding_size - 1)]
end

还有write_img熬,自带的write_tiff每次都得自己写地理结构体,也稍微封装了一下。

;+
;   函数用途:
;       用于输出tiff文件(封装write_tiff)
;   函数参数:
;       img_path: tiff文件的输出路径
;       img: 栅格矩阵
;       out_res: 输出分辨率
;       ul_x: 左上角格点的左上角位置的X坐标
;       ul_y: 左上角格点的左上角位置的Y坐标
;-
pro write_img, img_path, img, out_res, ul_x, ul_y
    ; 地理结构体
    geo_info={$
        MODELPIXELSCALETAG: [out_res, out_res, 0.0], $  ; 分辨率
        MODELTIEPOINTTAG: [0.0, 0.0, 0.0, ul_x, ul_y, 0.0], $  ; 角点信息
        GTMODELTYPEGEOKEY: 2, $  ; 设置为地理坐标系
        GTRASTERTYPEGEOKEY: 1, $  ; 像素的表示类型, 北上图像(North-Up)
        GEOGRAPHICTYPEGEOKEY: 4326, $  ; 地理坐标系为WGS84
        GEOGCITATIONGEOKEY: 'GCS_WGS_1984', $
        GEOGANGULARUNITSGEOKEY: 9102}  ; 单位为度
        
    ; 输出
    write_tiff, img_path, img, geotiff=geo_info, /float
end

时间精力有限,不再详细说明,Bye~.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/136220.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt实现TCP调试助手 - 简述如何在Qt中实现TCP多并发

简介 软件开发中,可能经常会用到TCP调试工具。本人使用QT开发了一款TCP调试工具,方便大家使用。本文章主要介绍下,该工具的功能,以及如何在Qt中实现TCP服务器的并发。 界面展示 安装界面 桌面图标。安装后会生成桌面图标&#…

【操作系统】1.1 操作系统的基础概念、功能和目标以及特性

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…

手机开机入网流程 KPI接通率和掉线率

今天我们来学习手机开机入网流程是怎么样的。以及RRC连接和重建流程(和博主之前讲TCP三次握手,四次挥手原理很相似)是什么样的,还有天线的KPI指标都包括什么,是不是很期待啊~ 目录 手机开机入网流程 ATTACH/RRC连接建立过程 KPI接通率和掉…

MongoDB基础知识~

引入MongoDB: 在面对高并发,高效率存储和访问,高扩展性和高可用性等的需求下,我们之前所学习过的关系型数据库(MySql,sql server…)显得有点力不从心,而这些需求在我们的生活中也是随处可见的,例如在社交中…

node插件express(路由)的插件使用(二)——cookie 和 session的基本使用区别

文章目录 前言一、express 框架中的 cookie0、cookie的介绍和作用1. 设置cookie2.删除cookie3.获取cookie(1)安装cookie-parser(2)导入cookie-parser(3)注册中间件(4)获取cookie&…

力扣刷题篇之栈与队列2(待修改)

系列文章目录 目录 系列文章目录 前言 一、最小/大栈 二、字符串去重问题 三、栈与括号匹配 总结 前言 本系列是个人力扣刷题汇总,本文是栈与队列。刷题顺序按照[力扣刷题攻略] Re:从零开始的力扣刷题生活 - 力扣(LeetCode&#xff09…

Nginx:Windows详细安装部署教程

一、Nginx简介 Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的。 它也是一种轻量级的Web服务器…

解决springboot接受buffer文件为null(从picgo上传buffer看springmvc处理过程)

1. 前言: picgo插件的简单开发 上篇文章我们简单写了picgo上传插件,但是当我们测试的时候,发现问题了,后端MultipartFile file接受到的文件为null。 2. 排查问题: 参考的文档 picgo api列表关于multipart form-data中…

C语言从入门到精通之【概述】

#include指令和头文件 例如#include <stdio.h>&#xff0c;我们经常看到C文件最上面会有类似这样的语句&#xff0c;它的作用相当于把stdio.h文件中的所有内容都输入该行所在的位置。实际上&#xff0c;这是一种“拷贝-粘贴”的操作。 #include这行代码是一条C预处理器…

LeetCode200.岛屿数量

看完题目我还感觉这道题目有点难&#xff0c;没想到20分钟不到就完全靠自己给写出来了。我就是按照自己的想法来&#xff0c;我用一个等大的visit数组来表示grid数组中的这个元素是否被访问过&#xff08;是否已经被判断了是不是岛屿&#xff09;。 先用一个大的循环对grid数组…

按键精灵中的字符串常用的场景

在使用按键精灵编写脚本时&#xff0c;与字符串有关的场景有以下几种&#xff1a; 1. 用时间字符串记录脚本使用截止使用时间 Dim localTime "2023-11-12 00:15:14" Dim networkTime GetNetworkTime() TracePrint networkTime If networkTime > localTime The…

KT6368A蓝牙芯片的出现部分芯片距离短换芯片就好是什么问题呢

一、简介 KT6368A蓝牙芯片的出现部分芯片距离短&#xff0c;换一个芯片距离就好了&#xff0c;是什么问题呢&#xff1f;生产2K的样子 详细说明 按照我们出货客户的跟踪情况&#xff0c;这种问题&#xff0c;可能性极低因为芯片本身的不良率&#xff0c;目前是控制在千分之三…

无需公网IP,贝锐花生壳内网穿透远程访问NAS

群晖DSM 7.0及以上版本 1.1 安装运行花生壳套件 &#xff08;1&#xff09;通过浏览器输入群晖NAS的内网地址&#xff0c;登录进去后&#xff0c;点击【套件中心】&#xff0c;搜索【花生壳】&#xff0c;并点击【安装套件】&#xff1b; &#xff08;2&#xff09; 勾选我接…

【C++】手写堆

手写堆&#xff08;小顶堆&#xff09; 堆使用数组存储&#xff0c;下标从1开始&#xff08;下标从0开始也可以&#xff09;。 下标为u的节点&#xff1a; 左子节点下标为&#xff1a;2 * u&#xff08;下标从0开始&#xff0c;左子节点则为2 * i 1&#xff09;右子节点下标…

No184.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

NGINX三种虚拟主机的配置

基于IP的配置 首先在原本基础上增加两个IP地址 [rootlocalhost conf.d]# nmcli connection modify ens33 ipv4.addresses 192.168.38.140 [rootlocalhost conf.d]# nmcli connection modify ens33 ipv4.addresses 192.168.38.150 [rootlocalhost conf.d]# nmcli connection u…

绝了!现在制作电子期刊这么快而有效了?

​随着科技的进步&#xff0c;制作电子期刊已经变得越来越简单和高效。现在&#xff0c;您只需要一台电脑或手机&#xff0c;就可以快速制作出精美的电子期刊&#xff0c;而且还能有效地吸引读者的注意力。 但是如何快而有效的制作电子期刊呢&#xff1f; 1.首先打开FLBOOK在线…

网络安全之认识托管威胁检测与响应(MDR)

随着数字化转型加速&#xff0c;企业的IT环境日益复杂&#xff0c;面临的网络安全威胁也在不断增加。传统的防御措施已经无法有效应对新型威胁&#xff0c;而且很多企业缺乏专业的网络安全团队和技术手段&#xff0c;导致大量的安全事件未能及时被发现和处理。 在这种背景下&a…

Java --- 直接内存

一、直接内存 1、不是虚拟机运行时数据区的一部分&#xff0c;也不是《Java虚拟机规范》中定义的内存区域。 2、直接内存是在Java堆外的&#xff0c;直接向系统申请的内存区间。 3、来源于NIO&#xff0c;通过存在堆中的DirectByteBuffer操作Native内存。 4、访问直接内存的…

贝锐蒲公英X1解决远程访问NAS难题

由于经常在外出差和旅游&#xff0c;需要实现即使在外地也能远程登录回去家里的NAS去处理事情或传输文件&#xff0c;因此解决方案之一是搭建一个安全简易的个人私有云。 实施难度 &#xff08;1&#xff09;家庭网络无公网IP&#xff0c;且公网IP价格昂贵&#xff08;2&…