• 基于GDAL库,读取.nc文件(以海洋表温数据为例)C++版


      对于做海洋数据处理的同学,会经常遇到nc格式的文件,nc文件的格式全称是NetCDF,具体的详细解释请查询官网【https://www.unidata.ucar.edu/software/netcdf/docs/index.html】,一般从全球大洋数据库里面下载的温盐、风场及云量等数据,基本上是nc文件格式,每一个文件里面包含多个数据集,例如最简单的海面表温数据(Sea surface temperature data),数据范围是全球,空间分辨率为0.25 *0.25(~25km),时间分辨率为3 hour,所以一天的观测数据里面包含着两个子数据集(subDataset),一是海洋表温数据集,另一个是遗失数据说明信息数据集,在第一个子数据集(海洋表温数据集)内,又会包含分层数据,也就是每隔3个小时时间分辨率下的表温数据。

      基于前期查询李民录老师的《GDAL源码剖析与开发指南》一书才了解到,GDAL库本身是支持上述文件的读取的,故编译GDAL库(2.3.2版本),编译器采用MSVC2017版本,开发平台采用QT 5.11.2版本,由于QT本身不具有MSVC编译器配套的调试器,所以去微软官网下载了相应的调试器(winsdksetup.exe,安装的时候只选择安装Debugging Tools for Windows即可);经过查找GDAL官网的资料,GDAL库如若进行nc文件的读取和创建,必须还要单独下载NetCDF库文件,安装好后,配置环境变量即可,编译GDAL库时,设定好opt文件,开始编译,编译成功后即可通过下述参考博客1(Qt配置GDAL)方法,配置GDAL库。

      配置完成以后,即可进行文件的读取工作,话不多说,献上代码

    读取-头文件

     1 #ifndef NCFILEREAD_H
     2 #define NCFILEREAD_H
     3 
     4 
     5 class ncFileRead
     6 {
     7 public:
     8     void ncFileRead::fileRead(const char *ncFileName);
     9 };
    10 
    11 #endif // NCFILEREAD_H

    读取-源文件

      1 #include "ncfileread.h"
      2 
      3 #include <gdal_priv.h>
      4 #include <vector>
      5 #include <QVector>
      6 #include <string>
      7 #include <QString>
      8 #include <QStringList>
      9 #include <QDebug>
     10 
     11 using namespace std;
     12 
     13 void ncFileRead::fileRead(const char *ncFileName)
     14 {
     15     vector <string>         vFileSets;
     16     vector <string>         pStrDesc;
     17     vector<vector<float>>   allSSTPixelNum;
     18 
     19     GDALAllRegister();
     20     CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");//中文路径
     21     GDALDataset* fileDataset = (GDALDataset*) GDALOpen(ncFileName,GA_ReadOnly);//打开HDF数据集
     22     if (fileDataset == NULL)
     23     {
     24         return;
     25     }
     26 
     27     char** sublist = GDALGetMetadata((GDALDatasetH) fileDataset,"SUBDATASETS");//获得数据的字符串,可以打印出来看看自己需要的数据在那
     28 
     29     int iCount = CSLCount(sublist);
     30     if(iCount <= 0){
     31         qDebug() << "该文件没有子数据" << endl;
     32         GDALClose((GDALDriverH)fileDataset);
     33     }
     34 
     35     //存储数据集信息
     36     for(int i = 0; sublist[i] != NULL;i++){
     37 
     38         qDebug() << sublist[i] << endl;
     39 
     40         if(i%2 != 0){
     41             continue;
     42         }
     43 
     44         /**
     45          * 01、海洋表温度数据集 float32
     46          * 02、数据丢失补充信息 int8
     47          * */
     48         string tmpstr = sublist[i];
     49         tmpstr = tmpstr.substr(tmpstr.find_first_of("=")+1);
     50         const char *tmpc_str = tmpstr.c_str();
     51 
     52         string tmpdsc = sublist[i+1];
     53         tmpdsc = tmpdsc.substr(tmpdsc.find_first_of("=")+1);
     54 
     55         GDALDataset* hTmpDt = (GDALDataset*)GDALOpen(tmpc_str,GA_ReadOnly);//打开该数据
     56 
     57         if (hTmpDt != NULL)
     58         {
     59             vFileSets.push_back(tmpc_str);
     60         }
     61         if(&pStrDesc != NULL){
     62             pStrDesc.push_back(tmpdsc);
     63         }
     64         GDALClose(hTmpDt);
     65     }
     66 
     67 
     68     //数据处理
     69 
     70     qDebug() << "read RasterBand(1) ......" << endl;
     71 
     72     //读取第一个波段
     73 
     74     QString qtmpdsc = QString::fromStdString(pStrDesc[0]);
     75     QStringList qtmpdsclist = qtmpdsc.split(" ");
     76     QString dataset_name = qtmpdsclist[1];
     77 
     78     float *lineData = NULL;
     79     if (dataset_name == "sea_surface_temperature")
     80     {
     81         GDALDataset  *tempDt = (GDALDataset *)GDALOpen(vFileSets[0].data(), GA_ReadOnly);
     82         int BandNum = tempDt->GetRasterCount();
     83 
     84         GDALRasterBand * poBand = tempDt->GetRasterBand(1);
     85         lineData = new float[1 * poBand->GetXSize()];
     86         for (int iLine = 0; iLine < poBand->GetYSize(); iLine++)
     87         {
     88             allSSTPixelNum.resize(poBand->GetYSize());
     89             for (int iPixel = 0; iPixel < poBand->GetXSize(); iPixel++)
     90             {
     91                 allSSTPixelNum[iLine].resize(poBand->GetXSize());
     92                 poBand->RasterIO(GF_Read, 0, iLine, poBand->GetXSize(), 1,lineData, poBand->GetXSize(), 1, GDT_Float32, 0, 0);
     93                 allSSTPixelNum[iLine][iPixel] = lineData[iPixel];
     94              }
     95         }
     96         if (lineData)
     97         {
     98             delete[]lineData;
     99             lineData = NULL;
    100         }
    101         GDALClose((GDALDatasetH)tempDt);
    102     }
    103 
    104 
    105     qDebug() << "read complete!" << endl;
    106 
    107     GDALClose((GDALDriverH)fileDataset);
    108 
    109 }

    主函数调用

     1 #include <QCoreApplication>
     2 
     3 #include "ncfileread.h"
     4 #include <QWidget>
     5 
     6 int main(int argc, char *argv[])
     7 {
     8     QCoreApplication a(argc, argv);
     9 
    10     ncFileRead nfr;
    11     nfr.fileRead("F:/Data File/test/SEAFLUX-OSB-CDR_V02R00_SST_D20060101_C20160824.nc");
    12 
    13     return a.exec();
    14 }

     文件读取结果

      至此,nc文件的读取工作已经完成,数据读取上来以后,即可进行进一步的数据处理工作。

    致谢

      感谢李民录老师的指导,以及其他不知姓名的的博主,再次感谢你们对于技术的分享!

      

    参考博客

    1、Qt配置GDAL【https://blog.csdn.net/u010670734/article/details/53106786?locationNum=13&fps=1】

    2、使用GDAL读取necdf数据【https://blog.csdn.net/bluels01/article/details/8091260】

    3、使用GDAL获取HDF等数据集中的图像【https://blog.csdn.net/liminlu0314/article/details/8478339】

  • 相关阅读:
    javascript无提示关闭窗口,兼容IE,Firefox
    vbs简单制作U灵大盗带发送功能的代码
    正则表达式提取网址、标题、图片等一例(.Net Asp Javascript/Js)的实现
    在asp.net中保持Session的有效期
    批处理编程 介绍
    IIS日志清理CMD版,VBS版,JS版,WSH版
    正则表达式提取图片地址
    用U盘安装GNU/Linux
    三核浏览器Lunascape新版发布
    黑客基础之DOS(最齐全)
  • 原文地址:https://www.cnblogs.com/thyou/p/9953845.html
Copyright © 2020-2023  润新知