NetCDF(NC)格式是气象领域比较常见的科学数据格式,该格式的部分数据可以直接使用HDF5库读取,前几天发现NC库的C++接口,用起来很简便,就写了一个读取Himawari-8 NC格式数据的示例,话不多数,直接放代码了:
//作者:宿鑫 //网址:www.ixxin.cn //时间:2019.4 #include <iostream> #include "ReadData.h" using namespace std; using namespace netCDF; using namespace netCDF::exceptions; bool inDsNames(string sInDsName, string inDs[], int nDsName); int Readh8NC(const char* pSrcFile,const char* pDstFile) { try { cout << "Start" << endl; NcFile dataFile(pSrcFile, NcFile::read); string inDsNm[20] = {"SAA","SAZ","SOA","SOZ", //4 "albedo_01","albedo_02","albedo_03","albedo_04","albedo_05","albedo_06", //6 "tbb_07","tbb_08","tbb_09","tbb_10","tbb_11","tbb_12","tbb_13","tbb_14","tbb_15","tbb_16"}; //10 //获取行列号 NcVar Varf = dataFile.getVar("SAA"); NcDim Dimf = Varf.getDim(1); int XSizef = Dimf.getSize(); Dimf = Varf.getDim(0); int YSizef = Dimf.getSize(); int nBand = 20; short * pSrcData = new short[XSizef*YSizef](); float * pDstData = new float[XSizef*YSizef](); GDALAllRegister(); CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); GDALDriver* pDstDrive = (GDALDriver*)GDALGetDriverByName("GTiff"); char** papszOptions = nullptr; //papszOptions = CSLSetNameValue(papszOptions, "COMPRESS", "LZW"); //papszOptions = CSLSetNameValue(papszOptions, "TILED", "YES"); GDALDataset* pDstDs = pDstDrive->Create(pDstFile, XSizef, YSizef, nBand, GDT_Int16, papszOptions); multimap<std::string, NcVar> TestD; TestD = dataFile.getVars(); int VarSize = TestD.size(); multimap<string, NcVar>::iterator i, iend; //迭代器 iend = TestD.end(); int b = 1; for (i = TestD.begin(); i != iend; i++) { cout << (*i).first << endl; if (inDsNames((*i).first, inDsNm, nBand)) //if ((*i).first == "SAA") { cout << "Processing:'" << (*i).first << endl; NcVar VarT = (*i).second; NcVarAtt AttT = VarT.getAtt("scale_factor"); NcType TypeT = AttT.getType(); int TypeId = TypeT.getId(); //float,长度是1 float fScale = 0.0f; AttT.getValues(&fScale); AttT = VarT.getAtt("add_offset"); float fOffset = 0.0f; AttT.getValues(&fOffset); NcDim DimT = VarT.getDim(1); int XSize = DimT.getSize(); DimT = VarT.getDim(0); int YSize = DimT.getSize(); //cout << 1 << endl; //cout << fScale << endl; if (XSize == XSizef && YSize == YSizef) { VarT.getVar(pSrcData); GDALRasterBand* pBand = pDstDs->GetRasterBand(b); b++; for (int t = 0; t < XSize*YSize; t++) { pDstData[t] = pSrcData[t] * fScale + fOffset; } CPLErr Err = pBand->RasterIO(GF_Write, 0, 0, XSizef, YSizef, pSrcData, XSizef, YSizef, GDT_Int16, 0, 0, 0); if(Err != 0) { cout << "写入错误" << (*i).first << endl; return Err_W; } cout << "Process End" << endl; } } } //构建投影 OGRSpatialReference oSRS; char *pszSRS_WKT = NULL; oSRS.SetWellKnownGeogCS("WGS84"); oSRS.exportToWkt(&pszSRS_WKT); pDstDs->SetProjection(pszSRS_WKT); CPLFree(pszSRS_WKT); double dDsGeoTran[6] = {80,0.02,0,60,0,-0.02}; pDstDs->SetGeoTransform(dDsGeoTran); delete[] pSrcData; delete[] pDstData; dataFile.close(); GDALClose(GDALDatasetH(pDstDs)); cout << "End" << endl; return 0; } catch (NcException& e) { e.what(); return e.errorCode(); } return Err_OK; } bool inDsNames(string sInDsName,string inDs[],int nDsName) { bool in = FALSE; for (int i = 0; i < nDsName; i++) { if (sInDsName == inDs[i]) { in = TRUE; break; } } return in; }
令我比较困惑的是,https://www.unidata.ucar.edu/software/netcdf/netcdf-4/newdocs/netcdf-cxx.html 这里给出的API中,在实际使用中竟然没有,所以这应该是网上比较全的一个NetCDF C++接口的读取数据的例子。
另外,配置NetCDF C++库,可以参考以下博客:
https://blog.csdn.net/chenhemin604/article/details/25197693
https://www.cnblogs.com/wang985850293/p/6576533.html
https://blog.csdn.net/toby54king/article/details/78711563