C++读取NC数据的结果与真实数值不一致的解决方法

news2025/1/15 13:51:37

  本文介绍基于C++ 语言的netCDF库读取.nc格式的栅格文件时,代码读取到的数据栅格文件的实际数据不一致的解决方法。

  最近,由于需要读取ERA5气象数据,因此使用C++ 语言中的netCDF库读取.nc格式文件。其中,偶然发现在Visual Studio的代码中读取到的.nc文件的数据,和其实际的数据(ArcMap等软件打开所显示的数据)不一致;这里就介绍一种可能导致上述情况的原因,以及对应的解决方法。此外,关于Visual Studio中配置C++ 语言netCDF库的方法,大家可以参考在Visual Studio配置C++的netCDF库的方法(https://blog.csdn.net/zhebushibiaoshifu/article/details/136451536);关于Python语言读取.nc数据的方法,大家可以参考Python读取.nc数据并提取指定时间、经纬度维度对应的变量数值(https://blog.csdn.net/zhebushibiaoshifu/article/details/136264348)。

  首先,在C++ 语言的代码读取.nc格式文件时,出现了如下图所示的情况,可以看到这些值都是负值;而实际上我这里的这个.nc格式文件肯定不应该如此。

  正常情况下,在ArcMap软件中打开上述这个.nc格式的文件,其数值正常范围的区间应该是如下图所示,肯定都是在大于0的区间内;当然,数据中确实可能会有NoData值,但尽管如此,这个.nc格式文件也不可能像上图那样,出现这么多不同的负数值。

  那么,如果出现类似上述这样的情况,大家就可以多多注意,很可能是由于存在scaleoffset导致的问题了。

  首先,什么是scaleoffset呢?简单来说,为了存储方便,.nc格式文件在保存数据的时候,可能会让原本的真实数据先乘以某个数,然后再加上某个数(很多.tif格式的遥感影像也是这么存储的,也就是常说的缩放系数)。例如,假设一个.nc格式文件原本的数值都是大于0、小于1的数值(例如反射率数据,都是0.X的数据),那么直接存储小数就需要占用大量的存储空间(因为需要float格式或者double格式);而如果让这些数据都乘上1000或者10000,也就是尽可能让小数部分消除,那么就可以用int格式来存储数据,从而降低了对存储空间的占用。

  因此,如果我们待读取的.nc格式文件含有这个scaleoffset,那么在使用C++ 语言中的netCDF库读取.nc格式文件时,读到的数据就是经过缩放处理后的数据;对此,我们需要手动将这个缩放后的数据,先乘上scale,再加上offset,从而得到最终的真实结果数据。这一个步骤,在Python语言的netCDF库中,应该是会自动帮我们处理(好像是这样的,因为之前用Python语言读取.nc格式文件的时候,都没有注意到过这个scaleoffset);而在C++ 语言的netCDF库中,就需要我们自行手动处理了。

  在netCDF库的官方网站中,也有关于这个scaleoffset的说明——如下图所示,二者在其中分别写作scale_factoradd_offset;在官方网站中提到,只要在.nc格式文件中看到这2个参数,都需要在读取数据后,自行手动将其乘以或添加到原数据中。

  因此,在用C++ 语言netCDF库读取.nc格式的栅格文件时,如果我们是第一次读取它,那么可以通过如下的代码,获取其变量的属性。

	NcFile file(path, NcFile::read);
	NcVar var = file.getVar(type);
	map<string, NcVarAtt> attributes_map = var.getAtts();

  其中,NcFile file(path, NcFile::read);含义为创建一个NcFile对象,path是要打开的.nc格式的栅格文件的路径,NcFile::read表示以只读模式打开文件;随后,NcVar var = file.getVar(type);表示调用file对象的getVar()方法,获取了指定变量名type(也就是我们需要读取的变量)的NcVar对象;最后,map<string, NcVarAtt> attributes_map = var.getAtts();调用var对象的getAtts()方法,获取了变量的所有属性,并将它们存储在一个map<string, NcVarAtt>对象中。在这个map中,属性的名称是键,对应的NcVarAtt对象是值。

  其中,这个attributes_map如下图所示;可以看到,其中是具有scale_factoradd_offset的。

  但是,如果此时我们直接查看这个attributes_map,是看不到scale_factoradd_offset具体的值的,因为它的值还是一个NcAtt对象;如下图所示。

  我们需要通过如下的代码,首先通过.getAtt()方法获取这个属性,然后用.getValues()方法获取这个属性的具体数值

	NcVarAtt attribute_offset = var.getAtt("add_offset");
	NcVarAtt attribute_scale = var.getAtt("scale_factor");
	double offset, scale;
	attribute_offset.getValues(&offset);
	attribute_scale.getValues(&scale);

  其中,对于上述代码,如果大家对变量值的精度有较高要求,记得要选择double类型的变量来存储scale_factoradd_offset——如果选择的是float,可能会丢失一些精度。

  运行上述代码,我们将得到如下图所示的结果。

  可以看到,scale_factoradd_offset的值都已经显示出来了。

  那么,我们就可以将这个scale_factoradd_offset,分别作用到我们读取得到的原始数据上(因为我这里.nc格式数据的数据量非常大,所以我们就只处理前100个),来看看其数值是否正确;具体代码如下。

	vector<double> var_array(time_size * latitude_size * longitude_size);
	var.getVar(var_array.data());
	for (int i = 0; i < 100; ++i) {
		var_array[i] *= scale;
		var_array[i] += offset;
	}

  可以看到,此时得到的结果,就符合实际了;如下图所示。

  此外,我们可以在ArcGIS软件中打开这个.nc格式的数据,找到其左上角的像元,获取一下这个像元的数值,如下图所示。

  可以看到,此时上图中所显示的数据,就和上上图中,我们在Visual Studio的代码中读取到的.nc文件的数据是一致的了。

  当然,这里也需要注意,有些.nc格式的数据,其变量也可能不含有scale_factoradd_offset这两个属性的,如下图所示;所以我们都可以用本文前述的代码,先获取其属性,看看到底有没有scale_factoradd_offset;如果有的话,在执行对应的数据恢复操作即可。

  至此,大功告成。

欢迎关注:疯狂学习GIS

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卷积神经网络(CNN)算法详解

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 引言 卷积神经网络&#xff08;Convolutional Neural Networks, CNN&#xff09;是一类包含卷积计算且具有深度结构的前馈神经网络&#xff08;…

Android Termux系统安装openssh实现公网使用SFTP远程访问

文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 SFTP&#xff08;SSH File Transfer Protocol&#xff09;是一种基于SSH&#xff08;Secure Shell&#xff09;安全协议的文件传输协议。与FTP协议相比&#xff0c;SFTP使用了…

外包干了5天,技术退步明显。。。。。

在湖南的一个安静角落&#xff0c;我&#xff0c;一个普通的大专生&#xff0c;开始了我的软件测试之旅。四年的外包生涯&#xff0c;让我在舒适区里逐渐失去了锐气&#xff0c;技术停滞不前&#xff0c;仿佛被时间遗忘。然而&#xff0c;生活的转机总是在不经意间降临。 与女…

【系统学习】2-Java进阶知识总结-3-集合-1-补充【泛型、树、数据结构】

文章目录 泛型什么是泛型&#xff1f;常见的泛型标识符泛型类泛型方法泛型接口通配符 树树的基本概念什么是二叉树&#xff1f;二叉树--普通二叉树二叉树--二叉查找树定义规则优缺点 二叉树--平衡二叉树定义规则旋转机制 二叉树--红黑树定义规则红黑规则 常见数据结构总体特点结…

node的安装与介绍

安装 下载地址 node官网首页就会有两个安装选择&#xff0c;会根据当前电脑的系统自动显示对应的安装包&#xff0c;一个长期维护版&#xff08;LTS&#xff09;,一个是尝鲜版&#xff0c;记住选择LTS版本 安装指定版本下载截图 安装过程截图&#xff08;非常简单&#xff…

STM32CubeMX学习笔记14 ---SPI总线

1. 简介 1.1 SPI总线介绍 SPI 是英语Serial Peripheral interface的缩写&#xff0c;顾名思义就是串行外围设备接口。是Motorola(摩托罗拉)首先在其MC68HCXX系列处理器上定义的。 SPI&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并且在…

掌握Linux之巅:RHCE认证快速攻略

在数字化时代&#xff0c;Linux系统已经成为企业级应用的重要支柱。RHCE&#xff08;Red Hat Certified Engineer&#xff09;认证&#xff0c;作为Linux领域的权威认证&#xff0c;不仅代表了专业技术的认可&#xff0c;更是职业发展的有力武器。本文将为你揭秘如何快速掌握Li…

@Autoweird和@Resourse的区别 java定义Bean的方式

Autoweird private Apple apple; Autoweird首先是根据类型来找 就是这个Apple 如果找到多个 会在根据名称就是这个apple来找&#xff0c;如果再找不到&#xff0c;就报错 Resourse相反 举例说明&#xff1a; 我们使用Autoweird ZhouyuService zhouyuService Resourse特别之…

C语言题目练习

目录 前言 1、转置矩阵 1.1 题目 描述 输入描述&#xff1a; 输出描述&#xff1a; 1.2解题 分析&#xff1a; 程序&#xff1a; 2、KiKi判断上三角矩阵 2.1 题目 描述 输入描述&#xff1a; 输出描述&#xff1a; 2.2 解题 分析&#xff1a; 程序&#xff1a; 3、…

什么是工业交换机?

如今&#xff0c;工业交换机在能源、环保、交通、智慧城市监控等各个行业都发挥着至关重要的作用&#xff0c;其需求也日益增长。本文将全面介绍工业交换机&#xff0c;帮助你进一步加深了解。 什么是工业交换机&#xff1f; 工业交换机&#xff0c;又称工业以太网交换机&…

基于微信小程序的电影院订票选座系统的设计与实现(程序+数据库+)

** &#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;** 一、研究背景…

轻薄蓝牙工牌室内人员定位应用

在现代化企业管理的背景下&#xff0c;轻薄蓝牙工牌人员定位应用逐渐崭露头角&#xff0c;成为提升企业效率和安全性的重要工具。本文将从轻薄蓝牙工牌的定义、特点、应用场景以及未来发展趋势等方面&#xff0c;对其进行全面深入的探讨。 一、轻薄蓝牙工牌的定义与特点 轻薄…

Vue:纯前端实现文件拖拽上传

先看一下拖拽相关的事件&#xff1a;dragover、dragenter drop和dragleave 。 dragover事件&#xff1a;当被拖动的元素在一个可放置目标上方时&#xff0c;该事件会被触发。 通常&#xff0c;我们会使用event.preventDefault()方法来取消浏览器默认的拖放行为&#xff0c;以便…

赛事通知丨2024年(第12届)“泰迪杯”挑战赛即将开始

2024年&#xff08;第12届&#xff09;“泰迪杯”数据挖掘挑战赛将于3月8日开放报名。“泰迪杯”数据挖掘挑战赛始创于2013年&#xff0c;迄今已经连续举办了12年。累计参赛高校千余所&#xff0c;累计参赛人数逾10万人&#xff0c;全国各省份均有参加。大赛的开展始终秉持推动…

局域网管理工具

每个组织的业务运营方法都是独一无二的&#xff0c;其网络基础设施也是如此&#xff0c;由于随着超融合基础设施等新计算技术的发展&#xff0c;局域网变得越来越复杂&#xff0c;因此局域网管理也应该如此&#xff0c;组织需要量身定制的局域网管理解决方案&#xff0c;这些解…

QT6.6 android开发环境搭建

一.目标 本文目的为实现在QT6.6下搭建android开发环境&#xff0c;可以实现QT6.6开发的QT程序&#xff08;widget及qml工程&#xff09;部署到android设备中。 二.环境安装 1.QT6.6环境安装 &#xff08;1&#xff09;在线安装器下载&#xff1a; https://download.qt.io/a…

手动更新服务器node新版本

1.安装nodejs下载到本地 2.下载后放到服务器上的指定目录中。例如/usr/local/src/node 3.执行tar -xvf node-v20.10.0-linux-x64.tar.xz解压 4.执行一下命令配置软连接 -f是如果文件存在就覆盖 # 将node源文件映射到usr/bin下的node文件 ln -fs /usr/local/src/node/node-…

10G Ethernet Subsystem 基于K7芯片的UDP通讯

此文章只用于教程开发笔记&#xff0c;不做过多的废话介绍。 IP核的建立 此选项不进行共享时钟逻辑。优点接口少好操作&#xff0c;缺点只可以建立一个IP核。&#xff08;我有一篇文章介绍了如何进行多个核互联&#xff09;传送门&#xff1a;FPGA光纤Aurora_8B_10B_fpga auro…

实现vue elmentUI图片本地上传

实现思路 后端代码 //上传头像PostMapping("/uplaod")public String upload(MultipartFile file) { // System.out.println(file"图片上次");//图片校验if (file.isEmpty()) {return "图片上传失败";}//可以自己加一点校验 例如上传的是不…

HBase 的安装与部署

目录 1 启动 zookeeper2 启动 Hadoop3 HBase 的安装与部署4 HBase 高可用 1 启动 zookeeper [huweihadoop101 ~]$ bin/zk_cluster.sh start2 启动 Hadoop [huweihadoop101 ~]$ bin/hdp_cluster.sh start3 HBase 的安装与部署 &#xff08;1&#xff09;将 hbase-2.0.5-bin.tar.…