基於GDAL庫,讀取.nc檔案(以海洋表溫資料為例)
對於做海洋資料處理的同學,會經常遇到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: 8void 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 { 15vector <string>vFileSets; 16vector <string>pStrDesc; 17vector<vector<float>>allSSTPixelNum; 18 19GDALAllRegister(); 20CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");//中文路徑 21GDALDataset* fileDataset = (GDALDataset*) GDALOpen(ncFileName,GA_ReadOnly);//開啟HDF資料集 22if (fileDataset == NULL) 23{ 24return; 25} 26 27char** sublist = GDALGetMetadata((GDALDatasetH) fileDataset,"SUBDATASETS");//獲得資料的字串,可以打印出來看看自己需要的資料在那 28 29int iCount = CSLCount(sublist); 30if(iCount <= 0){ 31qDebug() << "該檔案沒有子資料" << endl; 32GDALClose((GDALDriverH)fileDataset); 33} 34 35//儲存資料集資訊 36for(int i = 0; sublist[i] != NULL;i++){ 37 38qDebug() << sublist[i] << endl; 39 40if(i%2 != 0){ 41continue; 42} 43 44/** 45* 01、海洋表溫度資料集 float32 46* 02、資料丟失補充資訊 int8 47* */ 48string tmpstr = sublist[i]; 49tmpstr = tmpstr.substr(tmpstr.find_first_of("=")+1); 50const char *tmpc_str = tmpstr.c_str(); 51 52string tmpdsc = sublist[i+1]; 53tmpdsc = tmpdsc.substr(tmpdsc.find_first_of("=")+1); 54 55GDALDataset* hTmpDt = (GDALDataset*)GDALOpen(tmpc_str,GA_ReadOnly);//開啟該資料 56 57if (hTmpDt != NULL) 58{ 59vFileSets.push_back(tmpc_str); 60} 61if(&pStrDesc != NULL){ 62pStrDesc.push_back(tmpdsc); 63} 64GDALClose(hTmpDt); 65} 66 67 68//資料處理 69 70qDebug() << "read RasterBand(1) ......" << endl; 71 72//讀取第一個波段 73 74QString qtmpdsc = QString::fromStdString(pStrDesc[0]); 75QStringList qtmpdsclist = qtmpdsc.split(" "); 76QString dataset_name = qtmpdsclist[1]; 77 78float *lineData = NULL; 79if (dataset_name == "sea_surface_temperature") 80{ 81GDALDataset*tempDt = (GDALDataset *)GDALOpen(vFileSets[0].data(), GA_ReadOnly); 82int BandNum = tempDt->GetRasterCount(); 83 84GDALRasterBand * poBand = tempDt->GetRasterBand(1); 85lineData = new float[1 * poBand->GetXSize()]; 86for (int iLine = 0; iLine < poBand->GetYSize(); iLine++) 87{ 88allSSTPixelNum.resize(poBand->GetYSize()); 89for (int iPixel = 0; iPixel < poBand->GetXSize(); iPixel++) 90{ 91allSSTPixelNum[iLine].resize(poBand->GetXSize()); 92poBand->RasterIO(GF_Read, 0, iLine, poBand->GetXSize(), 1,lineData, poBand->GetXSize(), 1, GDT_Float32, 0, 0); 93allSSTPixelNum[iLine][iPixel] = lineData[iPixel]; 94} 95} 96if (lineData) 97{ 98delete[]lineData; 99lineData = NULL; 100} 101GDALClose((GDALDatasetH)tempDt); 102} 103 104 105qDebug() << "read complete!" << endl; 106 107GDALClose((GDALDriverH)fileDataset); 108 109 }
主函式呼叫
1 #include <QCoreApplication> 2 3 #include "ncfileread.h" 4 #include <QWidget> 5 6 int main(int argc, char *argv[]) 7 { 8QCoreApplication a(argc, argv); 9 10ncFileRead nfr; 11nfr.fileRead("F:/Data File/test/SEAFLUX-OSB-CDR_V02R00_SST_D20060101_C20160824.nc"); 12 13return 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】