C++ GDAL提取多时相遥感影像中像素随时间变化的数值数组
本文介绍基于C++语言GDAL
库,批量读取大量栅格遥感影像文件,并生成各像元数值的时间序列数组的方法。
首先,我们来明确一下本文所需实现的需求。现在有一个文件夹,其中包含了很多不同格式的文件,如下图所示。
其中,我们首先需要遍历这一文件夹,遴选出其中所有类型为.bmp
格式的栅格遥感影像文件(一共有6
个),并分别读取文件(已知这些遥感影像的行数、列数都是一致的);随后,将不同遥感影像的同一个位置的像素的数值进行分别读取,并存储在一个数组中。例如,最终我们生成的第一个数组,其中共有6
个元素,分别就是上图所示文件夹中6
景遥感影像各自(0,0)
位置的像元数值;生成的第二个数组,其中也是6
个元素,分别就是6
景遥感影像各自(1,0)
位置的像元数值,以此类推。其中,显然我们得到的数组个数,就是遥感影像像元的个数。此外,这里6
景遥感影像的排序,是按照文件名称的升序来进行的。
明确了具体需求,接下来就可以开始代码的实践。其中,本文分为两部分,第一部分为代码的分段讲解,第二部分为完整代码。
此外,本文是基于GDAL
库来实现栅格数据读取的;具体GDAL
库的配置方法大家可以参考文章在Visual Studio中部署GDAL库的C++版本(包括SQLite、PROJ等依赖)。
1 代码分段介绍
1.1 代码准备
这一部分主要是代码的头文件、命名空间与我们自行撰写的自定义函数get_need_file()
的声明;具体代码如下所示。
#include <iostream>
#include <vector>
#include <io.h>
#include "gdal_priv.h"using namespace std;void get_need_file(string path, vector<string>& file, string ext);
其中,由于我们在接下来的代码中需要用到容器vector
这一数据类型,因此首先需要添加#include <vector>
;同时,我们在接下来的代码中需要用到头文件io.h
中的部分函数(主要都是一些与计算机系统、文件管理相关的函数),因此需要添加#include <io.h>
;此外,我们是基于GDAL
库来实现栅格数据读取的,因此需要添加#include "gdal_priv.h"
。
接下来,这里声明了一个自定义函数get_need_file()
,具体我们在本文1.2部分介绍。
1.2 栅格文件筛选
由于我这里几乎将全部的代码都放在了主函数中,因此这一部分就先介绍代码main()
函数的第一部分,亦即栅格文件的遴选部分;具体代码如下所示。
int main() {string file_path = R"(E:\02_Project\02_ChlorophyllProduce\01_Data\00_Test)";vector<string> my_file;string need_extension = ".bmp";get_need_file(file_path, my_file, need_extension);int file_size = my_file.size();if (file_size == 0){cout << "No file can be found!" << endl;}else{cout << "Find " << file_size << " file(s).\n" << endl;}
这一部分主要就是做好调用自定义函数get_need_file()
的变量准备,并调用get_need_file()
函数,得到指定文件夹下的栅格文件;随后,将栅格文件的筛选结果进行输出。这一部分的具体代码介绍,大家查看文章C++遴选出特定类型的文件或文件名符合要求的文件即可,这里就不再赘述。
1.3 栅格文件读取
这一部分主要是基于GDAL
库,循环读取前述文件夹中的每一个栅格遥感影像文件。
int nXSize, nYSize;float** pafScanline = new float* [file_size];int pic_index = 1;for (auto x : my_file){GDALDataset* poDataset;GDALAllRegister();CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");poDataset = (GDALDataset*)GDALOpen(x.c_str(), GA_ReadOnly);if (poDataset == NULL){cout << "Open File " << x << " Error!" << endl;}else{cout << "Open File " << x << " Success!" << endl;}GDALRasterBand* poBand;poBand = poDataset->GetRasterBand(1);nXSize = poBand->GetXSize();nYSize = poBand->GetYSize();cout << nXSize << "," << nYSize << "\n" << endl;pafScanline[pic_index - 1] = new float[nXSize * nYSize];poBand->RasterIO(GF_Read, 0, 0, nXSize, nYSize, pafScanline[pic_index - 1], nXSize, nYSize, GDT_Float32, 0, 0);pic_index ++;}
其中,nXSize
与nYSize
分别表示栅格遥感影像的列数与行数,pafScanline
是我们读取栅格遥感影像文件所需的变量,之后读取好的遥感影像数据就会存放在这里;由于我们有多个栅格文件需要读取,因此通过for
循环来实现批量读取的操作,并通过pic_index
这个变量作为每一次读取文件的计数。
在这里,float** pafScanline = new float* [file_size];
这句代码表示我们将pafScanline
作为一个指向指针的指针的数组;在后期读取遥感影像数据后,pafScanline[0]
、pafScanline[1]
一直到pafScanline[5]
,这6
个数值同样分别是指针,分别指向存储6
景遥感影像数据的地址。这里我们通过new
实现对pafScanline
内存的动态分配,因为我们在获取栅格遥感影像的景数(也就是文件夹中栅格遥感影像文件的个数)之前,也不知道具体需要给pafScanline
这一变量分配多少的内存。此外,在for
循环中,我们还对pafScanline[0]
、pafScanline[1]
一直到pafScanline[5]
同样进行了动态内存分配,因为我们在获取每一景栅格遥感影像的行数与列数之前,同样是不知道需要给pafScanline[x]
这6
个数组变量分配多少内存的。
随后,for
循环中的其他部分,就是GDAL
库读取遥感影像的基本代码。读取第一景遥感影像数据后,我们将数据保存至pafScanline[0]
,并随后进行第二次循环,读取第二景遥感影像数据,并将其数据保存至pafScanline[1]
中,随后再次循环;以此类推,直至读取6
景遥感影像完毕。
如果大家只是需要实现C++批量读取栅格遥感影像数据,那么以上操作就已经实现了大家的需求。其中,显然pafScanline[0]
就是第一景遥感影像数据,pafScanline[1]
就是第二景遥感影像数据,pafScanline[2]
就是第三景遥感影像数据,以此类推。
1.4 像元时间序列数组生成
这一部分则是基于以上获取的各景遥感影像数据读取结果,进行每一个像元数值的时间序列数组生成。
float** pixel_paf = new float* [nXSize * nYSize];for (int pixel_num = 0; pixel_num < nXSize * nYSize; pixel_num++){pixel_paf[pixel_num] = new float[file_size];for (int time_num = 0; time_num < file_size; time_num++){pixel_paf[pixel_num][time_num] = pafScanline[time_num][pixel_num];}}
这一部分的代码思路其实也非常简单,就是通过两个for
循环,将原本一共6
个的、每一个表示每一景遥感影像中全部数据的数组,转变为一共X
个的(X
表示每一景遥感影像的像元总个数)、每一个表示每一个位置的像元在6
景遥感影像中的各自数值的数组。
在这里,由于同样的原因,我们对pixel_paf
亦进行了内存的动态分配。
1.5 输出测试与代码收尾
这一部分主要是输出一个我们刚刚配置好的像元数值时间序列数组,从而检查代码运行结果是否符合我们的要求;此外,由于前面我们对很多变量进行了动态内存分配,因此需要将其delete
掉;同时,这里还可以对前面我们定义的指向指针的指针赋值为NULL
,这样子其就不能再指向任何地址了,即彻底将其废除。
for (int i = 0; i < file_size; i++){cout << pixel_paf[0][i] << "," << endl;}delete[] pafScanline;delete[] pixel_paf;pafScanline = NULL;pixel_paf = NULL;return 0;
}
至此,代码的主函数部分结束。
1.6 自定义函数
这一部分是我们的自定义函数get_need_file()
。
void get_need_file(string path, vector<string>& file, string ext)
{intptr_t file_handle = 0;struct _finddata_t file_info;string temp;if ((file_handle = _findfirst(temp.assign(path).append("/*" + ext).c_str(), &file_info)) != -1){do{file.push_back(temp.assign(path).append("/").append(file_info.name));} while (_findnext(file_handle, &file_info) == 0);_findclose(file_handle);}
}
如前所述,这一部分的具体代码介绍,大家查看文章C++遴选出特定类型的文件或文件名符合要求的文件即可,这里就不再赘述。
2 完整代码
本文所需用到的完整代码如下所示。
#include <iostream>
#include <vector>
#include <io.h>
#include "gdal_priv.h"using namespace std;void get_need_file(string path, vector<string>& file, string ext);int main() {string file_path = R"(E:\02_Project\02_ChlorophyllProduce\01_Data\00_Test)";vector<string> my_file;string need_extension = ".bmp";get_need_file(file_path, my_file, need_extension);int file_size = my_file.size();if (file_size == 0){cout << "No file can be found!" << endl;}else{cout << "Find " << file_size << " file(s).\n" << endl;}int nXSize, nYSize;float** pafScanline = new float* [file_size];int pic_index = 1;for (auto x : my_file){GDALDataset* poDataset;GDALAllRegister();CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");poDataset = (GDALDataset*)GDALOpen(x.c_str(), GA_ReadOnly);if (poDataset == NULL){cout << "Open File " << x << " Error!" << endl;}else{cout << "Open File " << x << " Success!" << endl;}GDALRasterBand* poBand;poBand = poDataset->GetRasterBand(1);nXSize = poBand->GetXSize();nYSize = poBand->GetYSize();cout << nXSize << "," << nYSize << "\n" << endl;pafScanline[pic_index - 1] = new float[nXSize * nYSize];poBand->RasterIO(GF_Read, 0, 0, nXSize, nYSize, pafScanline[pic_index - 1], nXSize, nYSize, GDT_Float32, 0, 0);pic_index ++;}float** pixel_paf = new float* [nXSize * nYSize];for (int pixel_num = 0; pixel_num < nXSize * nYSize; pixel_num++){pixel_paf[pixel_num] = new float[file_size];for (int time_num = 0; time_num < file_size; time_num++){pixel_paf[pixel_num][time_num] = pafScanline[time_num][pixel_num];}}for (int i = 0; i < file_size; i++){cout << pixel_paf[0][i] << "," << endl;}delete[] pafScanline;delete[] pixel_paf;pafScanline = NULL;pixel_paf = NULL;return 0;
}void get_need_file(string path, vector<string>& file, string ext)
{intptr_t file_handle = 0;struct _finddata_t file_info;string temp;if ((file_handle = _findfirst(temp.assign(path).append("/*" + ext).c_str(), &file_info)) != -1){do{file.push_back(temp.assign(path).append("/").append(file_info.name));} while (_findnext(file_handle, &file_info) == 0);_findclose(file_handle);}
}
当我们运行上述代码后,将会出现如下所示的界面。
其中,会显示栅格遥感影像文件的筛选情况、具体文件名称及其各自的行号与列号;同时,最后一部分则是本文1.5部分提及的测试输出结果,其表示本文所用的6
景遥感影像各自(0,0)
位置处的像元数值。
至此,大功告成。
参考链接: https://www.cnblogs.com/fkxxgis/p/18004549
相关文章:

C++ GDAL提取多时相遥感影像中像素随时间变化的数值数组
本文介绍基于C语言GDAL库,批量读取大量栅格遥感影像文件,并生成各像元数值的时间序列数组的方法。 首先,我们来明确一下本文所需实现的需求。现在有一个文件夹,其中包含了很多不同格式的文件,如下图所示。 其中&#x…...

免费-华为od-C卷-javascript-动态规划-贪心歌手.js
动态规划-贪心歌手 还有很多其他题,链接是github, 进去可以查看对应文件夹就行...

elementui 实现一个固定位置的Pagination(分页)组件
系列文章目录 一、elementui 导航菜单栏和Breadcrumb 面包屑关联 二、elementui 左侧导航菜单栏与main区域联动 三、elementui 中设置图片的高度并支持PC和手机自适应 四、 elementui 实现一个固定位置的Pagination(分页)组件 文章目录 系列文章目录…...

紧急备考全攻略,如何短期通过PMP考试?
今年身边有很多同事朋友都要考PMP,而我属于这些人里”第一个吃螃蟹“的人,一次拿下5A,下面分享一下我自己备考PMP的经验。 我是根据自己的学习计划复习的,不能说这些方法适合所有人,但对备考的伙伴们来说,…...

python开发poc,fofa爬虫批量化扫洞
学习使用python做到批量化的漏洞脚本 1.通过fofa搜索结果来采集脚本 2.批量化扫描漏洞 ---glassfish存在任意文件读取在默认48484端口,漏洞验证的poc为: "glassfish" && port"4848" && country"CN" http://loca…...

适用于 Windows 10 的 10 大免费数据恢复软件
数据丢失可能是一场噩梦,尤其是在涉及重要文件和文档时。无论是由于意外删除、系统崩溃还是病毒攻击,找到适合 Windows 10 的文件夹恢复软件都可以在恢复丢失的数据方面发挥重要作用。在本指南中,我们将探索适用于 Windows 10 用户的 10 大免…...

zabbix企业级监控平台
zabbix部署 安装源 重新创建纯净环境,利用base克隆一台虚拟机server1 给server1做快照,方便下次实验恢复使用 进入zabbix官网https://www.zabbix.com rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm …...

如何关闭WordPress的自动更新功能
Wordpress为什么自动更新 WordPress自动更新是为了提供更好的安全性和稳定性。 安全性:WordPress是一个广泛使用的内容管理系统,因此成为恶意攻击的目标。WordPress的自动更新功能确保你的网站及时获得最新的安全补丁和修复程序,以保护你的网…...

【分析 GClog 的吞吐量和停顿时间、heapdump 内存泄漏分析】
文章目录 🔊博主介绍🥤本文内容GClog分析以优化吞吐量和停顿时间步骤1: 收集GClog步骤2: 分析GClog步骤3: 优化建议步骤4: 实施优化 Heapdump内存泄漏分析步骤1: 获取Heapdump步骤2: 分析Heapdump步骤3: 定位泄漏对象步骤4: 分析泄漏原因步骤5: 修复泄漏…...

[STL-list]介绍、与vector的对比、模拟实现的迭代器问题
一、list使用介绍 list的底层是带头双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行…...

代码随想录-035期-算法训练营【博客笔记汇总表】
ヾ(◍∇◍)ノ゙加油~ 目录 00、说明 01、刷题网址 02、每日打卡任务 03、博客打卡笔记 01、数组 02、链表 03、哈希表 04、字符串 05、双指针法 06、栈与队列 07、二叉树 08、回溯算法 09、贪心算法 10、动态规划 11、单调栈 12、图论 04…...

postgresql数据库|数据整合的好工具--Oracle-fdw的部署和使用
概述 Oracle_fdw 是一种postgresql外部表插件,可以读取到Oracle上面的数据。是一种非常方便且常见的pg与Oracle的同步数据的方法 Oracle_fdw 适用场景: Oracle_fdw 是一个开源的 Foreign Data Wrapper (FDW),主要用于在 PostgreSQL 数据库中…...

让php开发更优雅-Laravel篇
前言 随着开发经验的增加,也伴随团队开发的积累,规范开发显得越来越重要,本文给大家提供一些laravel开发的进阶思路和经验,让大家开发更加统一规范,代码看起来更加优雅。 1.更多使用第三方库。团队开发的时候…...

自动化测试之httprunner框架hook函数实操
本篇介绍httprunner中hook函数的使用,以及通过编程能力实现建设自动化测试更全面的场景覆盖 前置: 互联网时代让我们更快的学习到什么是Httprunner 正文: 经过上文了解到这个框架怎么使用之后,我们开始来探讨一下我们为什么要用…...

物联网实战--入门篇之(七)嵌入式-MQTT
目录 一、MQTT简介 二、MQTT使用方法 三、MQTT驱动设计 四、代码解析 五、使用过程 六、总结 一、MQTT简介 MQTT因为其轻量、高效和稳定的特点,特别适合作为物联网系统的数据传输协议,已经成为物联网事实上的通信标准了。关于协议的具体内容看看这…...

跑模型——labelme的json文件转成yolo使用的txt文件(语义分割)
前言 将labelme多边形标注的json文件转换成yolo使用的txt文件 import os import json import numpy as np from tqdm import tqdm#实现函数 def json2txt(path_json, path_txt): # 可修改生成格式with open(path_json, r) as path_json:jsonx json.load(path_json)with open…...

一个项目仿京东商场代码
git clone http://git.itcast.cn/heimaqianduan/erabbit-uni-app-vue3-ts.git...

计算机网络——WEB服务器编程实验
实验目的 1. 处理一个 http 请求 2. 接收并解析 http 请求 3. 从服务器文件系统中获得被请求的文件 4. 创建一个包括被请求的文件的 http 响应信息 5. 直接发送该信息到客户端 具体内容 一、C 程序来实现 web 服务器功能。 二、用 HTML 语言编写两个 HTML文件,并…...

蓝桥杯算法题:最大比例
题目描述: X星球的某个大奖赛设了 M 级奖励。 每个级别的奖金是一个正整数。 并且,相邻的两个级别间的比例是个固定值。 也就是说:所有级别的奖金数构成了一个等比数列。 比如:16,24,36,54,其等比值为:3/2。…...

【堡垒机】堡垒机的介绍
目前,常用的堡垒机有收费和开源两类。 收费的有行云管家、纽盾堡垒机; 开源的有jumpserver; 这几种各有各的优缺点,如何选择,大家可以根据实际场景来判断 什么是堡垒机 堡垒机,即在一个特定的网络环境下&…...

通过 ffmpeg命令行 调节视频播放速度
1. 仅调整视频速率 视频调速原理:修改视频的pts,dts # 可能会丢帧 ffmpeg -i input.mkv -an -filter:v "setpts0.5*PTS" output.mkv # 可用-r参数指定输出视频FPS以防止丢帧 ffmpeg -i input.mkv -an -r 60 -filter:v "setpts2.0*PTS&q…...

SQLite数据库在Linux系统上的使用
SQLite是一个轻量级的数据库解决方案,它是一个嵌入式的数据库管理系统。SQLite的特点是无需独立的服务器进程,可以直接嵌入到使用它的应用程序中。由于其配置简单、支持跨平台、服务器零管理,以及不需要复杂的设置和操作,SQLite非…...

Spring中依赖注入的方法有几种,分别是什么?
依赖注入的目的: 都是为了减少对象之间的紧密耦合 1. 构造函数注入:通过在类的构造函数中接受依赖对象作为参数,Spring在创建对象时将依赖注入。 2. Setter方法注入:在类中提供setter方法,Spring通过调用这些setter方法…...

【面试精讲】MyBatis设计模式及源码分析,MyBatis设计模式实现原理
【面试精讲】MyBatis设计模式及源码分析,MyBatis设计模式实现原理 目录 本文导读 一、MyBatis中运用的设计模式详解 1. 工厂模式(Factory Pattern) 2. 单例模式(Singleton Pattern) 3. 建造者模式(Bu…...

Acrel-1000DP光伏监控系统在尚雷仕(湖北)健康科技有限公司5.98MW分布式光伏10KV并网系统的应用
摘 要:分布式光伏发电特指在用户场地附近建设,运行方式多为自发自用,余电上网,部分项目采用全额上网模式。分布式光伏全额上网的优点是可以充分利用分布式光伏发电系统的发电量,提高分布式光伏发电系统的利用率。发展分…...

电脑远程控制esp32上的LED
1、思路整理 首先esp32需要连接上wifi 然后创建udp socket 接受udp数据 最后解析数据,控制LED 2、micropython代码实现 import network from socket import * from machine import Pin p2Pin(2,Pin.OUT)def do_connect(): #连接wifi wlan network.WLAN(network.…...

ARXML处理 - C#的解析代码(一)
目的 本文介绍通过AUTOSAR组织提供的xsd文件,自动生成对应的C#解析代码的框架。 自动生成方法:Microsoft SDKs\Windows\v7.0A\bin\xsd.exe 命令:xsd.exe AUTOSAR_4-0-3.xsd /c /l:CS /n:AUTOSAR4 AUTOSAR_4-0-3.xsd 是需要生成代码的xsd文…...

OJ 栓奶牛【C】【Python】【二分算法】
题目 算法思路 要求的距离在最近木桩与最远木桩相隔距离到零之间,所以是二分法 先取一个中间值,看按照这个中间值可以栓多少奶牛,再与输入奶牛数比较,如果大于等于,则增大距离,注意这里等于也是增大距离…...

Spring6-单元测试:JUnit
1. 概念 在进行单元测试时,特别是针对使用了Spring框架的应用程序,我们通常需要与Spring容器交互以获取被测试对象及其依赖。传统做法是在每个测试方法中手动创建Spring容器并从中获取所需的Bean。以下面的两行常见代码为例: ApplicationCo…...

ubuntu系统安装k8s1.28精简步骤
目录 一、规划二、环境准备2.1 配置apt仓库配置系统基本软件仓库配置k8s软件仓库安装常用软件包 2.2 修改静态ip、ntp时间同步、主机名、hosts文件、主机免密2.3 内核配置2.4 关闭防火墙、selinux、swap2.5 安装软件安装docker安装containerd安装k8s软件包 三、安装配置k8s3.1 …...