日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

使用GDAL库读取SRTM格式的高程数据

發(fā)布時(shí)間:2023/12/31 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用GDAL库读取SRTM格式的高程数据 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文件格式以及原理參考老外的文章:https://librenepal.com/article/reading-srtm-data-with-python/

?

GDAL包:https://github.com/OSGeo/gdal/releases/tag/v3.1.3

其實(shí)文件格式很容易理解,比如是1/3弧度的精度情況下,就是1度分為1/1200份,所以一個(gè)文件表示經(jīng)度和維度各1度的方格,就是切成1200x1200份,存儲(chǔ)為二維矩陣是1201x1201,因?yàn)檫吔缯剂?行1列:

其中二維數(shù)組是按照地圖來(lái)存儲(chǔ)的,所以從低維度和低經(jīng)度取索引時(shí)候需要計(jì)算下:

老外是用python寫(xiě)的,我用c++重寫(xiě)的,歌詞大意如下:

#pragma once#include <math.h> #include <string.h> #include <stdio.h> #include <string> #include <math.h> #include <iostream> #include <memory> #include <algorithm> #include <map> #include <mutex> #include <thread>//#include "include/gdal.h" #include <gdal_priv.h>#ifdef _DEBUG#pragma comment(lib, "gdal_i_d.lib") #else #pragma comment(lib, "gdal_i.lib") #endifusing namespace std; // 數(shù)據(jù)結(jié)構(gòu) class SRTM { public:SRTM(){if (runOnce == false){GDALAllRegister();// windows操作系統(tǒng)使用GBKCPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");runOnce = true;}}~SRTM(){if (pData != nullptr)delete[] pData;//std::cerr << "SRTM析構(gòu)釋放數(shù)據(jù)" << endl;};// 分辨率const int sample = 1200;static bool runOnce;private:SRTM(const SRTM & other) = delete;SRTM & operator = (const SRTM & other) = delete;SRTM(SRTM && other) = delete;SRTM & operator = (SRTM && other) = delete;unsigned int nWidth = 1201;unsigned int nHeight = 1201;// c++17以前不支持動(dòng)態(tài)數(shù)組使用shared_ptr管理// std::unique_ptr<short[]> data;short int *pData = nullptr;double minLat;double maxLat;double minLon;double maxLon;static double Mercator2Lon(double lon)//墨卡托轉(zhuǎn)WGS84:經(jīng)度{return lon / 20037508.34 * 180.0;}static double Mercator2Lat(double lat)//墨卡托轉(zhuǎn)WGS84:緯度{double result = 0;double mid = lat / 20037508.34 * 180.0;result = 180.0 / M_PI * (2.0 * atan(exp(mid * M_PI / 180.0)) - M_PI / 2.0);return result;}public:// 從二維數(shù)組中查詢(xún),但是編號(hào)是二維數(shù)組的左下角,需要重新計(jì)算一下indexbool query(short & height, double lat, double lon){if (pData == nullptr)return false;int lat_row = int(round((lat - int(lat)) * sample));int lon_row = int(round((lon - int(lon)) * sample));//lat_row = int(round((lat - minLat) * sample));//lon_row = int(round((lon - minLon) * sample));lat_row = abs(lat_row);lon_row = abs(lon_row);size_t index = (nHeight - 1 - lat_row) * nWidth + lon_row;if (index >= sample * sample)return false;height = pData[index];return true;}bool load(const std::string fileName){return load(fileName.c_str());}bool load(const char * fileName){GDALDataset *poDataSet;GDALRasterBand *pBand;poDataSet = (GDALDataset*)GDALOpen(fileName, GA_ReadOnly);if (poDataSet == nullptr)return false;this->nWidth = poDataSet->GetRasterXSize();//獲取圖像寬度this->nHeight = poDataSet->GetRasterYSize();//獲取圖像高度// 存儲(chǔ)邊界信息double adfGeoTransform[6];double value[6];if (poDataSet->GetGeoTransform(adfGeoTransform) == CE_None){value[0] = adfGeoTransform[0]; // 起點(diǎn),左上經(jīng)度value[1] = adfGeoTransform[3]; // 起點(diǎn),左上維度value[2] = adfGeoTransform[1] * (double)nWidth + adfGeoTransform[0]; // 右側(cè)經(jīng)度value[3] = adfGeoTransform[5] * (double)nHeight + adfGeoTransform[3]; // 右下if (value[0] > 180 || value[0] < -180)//墨卡托轉(zhuǎn)WGS84{value[0] = Mercator2Lon(value[0]);value[1] = Mercator2Lat(value[1]);value[2] = Mercator2Lon(value[2]);value[3] = Mercator2Lat(value[3]);}}this->minLon = value[0];this->maxLon = value[2];this->minLat = value[3];this->maxLat = value[1];if (pData != nullptr)delete[] pData;this->pData = new short[nWidth * nHeight];pBand = poDataSet->GetRasterBand(1);pBand->RasterIO(GF_Read, 0, 0, nWidth, nHeight, pData, nWidth, nHeight,pBand->GetRasterDataType(), 0, 0);//int i = pData[1000 * nWidth + 1];GDALClose(poDataSet);//關(guān)閉數(shù)據(jù)集return true;}public:// 通過(guò)經(jīng)緯度計(jì)算標(biāo)準(zhǔn)文件名static std::string getFileName(double lat, double lon){char ns;char ew;if (lat >= 0)ns = 'N';elsens = 'S';if (lon >= 0)ew = 'E';elseew = 'W';char buffer[20];int i_lat = abs(int(lat));int i_lon = abs(int(lon));//snprintf(buffer, 20, "%.1s", &ns);snprintf(buffer, 20, "%.1s%02d%.1s%03d.hgt", &ns, i_lat, &ew, i_lon);return buffer;}}; // 初始化 bool SRTM::runOnce = false;// c++ 17 //namespace fs = std::filesystem; // 對(duì)緩存進(jìn)行管理 class SRTM_Cache { public:SRTM_Cache(const char * dir) : rootDir(dir){setRootPath(dir);}~SRTM_Cache(){// 自動(dòng)釋放資源//dataMap.clear();}void setRootPath(const char * dir){rootDir = dir;// 去掉末尾的\\ size_t off = rootDir.rfind('\\', rootDir.size());if (off > 0 && (off == rootDir.size()-1))rootDir = rootDir.substr(0, off);}bool query(short & height, double lat, double lon){std::string fileName = SRTM::getFileName(lat, lon);bool ret = false;std::shared_ptr<SRTM> ptr = nullptr;{ // 添加作用域,提早解鎖std::lock_guard<std::mutex> autoLock(mapMutex); // 加鎖auto it = dataMap.find(fileName);if (it == dataMap.end()){// 嘗試加載文件std::string filePath = rootDir + "\\" + fileName;ptr = std::make_shared<SRTM>();ret = ptr->load(filePath);if (ret){dataMap.insert(std::pair<std::string, std::shared_ptr<SRTM> >(fileName, ptr));}else{return false;}return ret;}else{std::shared_ptr<SRTM> ptr = it->second;}} // 添加作用域,提早解鎖//std::cout << ptr.use_count() << endl;if (ptr != nullptr){ret = ptr->query(height, lat, lon);return ret;}return false;} // end of queryprivate:SRTM_Cache(const SRTM_Cache & other) = delete;SRTM_Cache& operator =(const SRTM_Cache & other) = delete;// 用智能指針管理數(shù)據(jù)類(lèi)實(shí)例,因?yàn)橐呀?jīng)禁止了賦值和拷貝構(gòu)造,std::map<std::string, std::shared_ptr<SRTM> > dataMap;std::string rootDir;// 添加多線程互斥std::mutex mapMutex; };

使用的方法如下:

// readDEM.cpp : 此文件包含 "main" 函數(shù)。程序執(zhí)行將在此處開(kāi)始并結(jié)束。 //#include <iostream> #include "SRTM.h"int main() {SRTM_Cache manager("D:\\DEM數(shù)據(jù)\\SRTM3-90米全國(guó)DEM\\");double lat = 39.990618;double lon = 116.169644;short heiht;bool ret = manager.query(heiht, lat, lon);if (ret == false){std::cout << "false" << endl;}else{string str;str.resize(100, '\0');snprintf(const_cast<char *>(str.data()), 100, "%.5f, %.5f 高程:%d", lat, lon, heiht);std::cout << str.c_str() << endl;}lat = 41.56;ret = manager.query(heiht, lat, lon);if (ret == false){std::cout << "false" << endl;}else{string str;str.resize(100, '\0');snprintf(const_cast<char *>(str.data()), 100, "%.5f, %.5f 高程:%d", lat, lon, heiht);std::cout << str.c_str() << endl;} }

結(jié)果:

39.99062, 116.16964 高程:509 41.56000, 116.16964 高程:1792

備注:

使用vcpkg管理各種開(kāi)源包真的非常的方便,比自己一個(gè)一個(gè)找強(qiáng)多了。

總結(jié)

以上是生活随笔為你收集整理的使用GDAL库读取SRTM格式的高程数据的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。