最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++使用HDF5庫實現(xiàn)將h5圖像轉(zhuǎn)為tif格式

 更新時間:2024年12月09日 11:44:57   作者:瘋狂學(xué)習(xí)GIS  
這篇文章主要為大家詳細(xì)介紹了C++ 語言如何通過hdf5庫與gdal庫實現(xiàn)將.h5格式的多波段HDF5圖像批量轉(zhuǎn)換為.tif格式,有需要的可以參考一下

本文介紹基于C++ 語言的hdf5庫與gdal庫,將.h5格式的多波段HDF5圖像批量轉(zhuǎn)換為.tif格式的方法;其中,本方法支持對szip壓縮的HDF5圖像(例如高分一號衛(wèi)星遙感影像)加以轉(zhuǎn)換。

將HDF5圖像批量轉(zhuǎn)換為.tif格式,在部分場景下操作并不難——在我們之前的文章Python中ArcPy實現(xiàn)柵格圖像文件由HDF格式批量轉(zhuǎn)換為TIFF格式中,就介紹過基于Python中的arcpy模塊實現(xiàn)這一需求的方法。但是,正如我們在文末補充內(nèi)容中提到的那樣,由于szip這個壓縮模塊不再受到hdf5庫的支持,導(dǎo)致用szip程序壓縮的HDF5圖像,比如高分系列遙感影像的.h5文件,就沒辦法在Windows中通過Python的h5py、gdal等庫直接打開了。

那么在這里,我們就介紹一下基于C++ 語言的hdf5庫,打開.h5格式圖像(包括那些用到szip壓縮程序的HDF5圖像)的方法。不過需要注意,我這里是在Linux的Ubuntu系統(tǒng)中操作的,至少可以保證這個代碼在Linux下可以正常運行;但能否在Windows中的C++ 環(huán)境下也正常運行,我暫時還沒試過——按道理應(yīng)該也是可行的,大家如果有需要的話可以嘗試一下。

本文所用代碼如下。

#include <iostream>
#include <sstream>
#include <vector>
#include <filesystem>
#include <gdal.h>
#include <gdal_priv.h>
#include "hdf5.h"
#include "ogr_spatialref.h" 

int main(int argc, char *argv[]) {
    const std::string h5_path = "/home/ctj/data/H5/";
    const std::string tif_path = "/home/ctj/data/TIFF_48SUB/";
    // const std::string h5_path = argv[1];
    // const std::string tif_path = argv[2];
    const char *dataset_0 = "/Cloud_Mask/cloudmask";
    const char *dataset_1 = "/GeometricCorrection/DataSet_16_1";
    const char *dataset_2 = "/GeometricCorrection/DataSet_16_2";
    const char *dataset_3 = "/GeometricCorrection/DataSet_16_3";
    const char *dataset_4 = "/GeometricCorrection/DataSet_16_4";
    const char *projection_para = "ProjectionPara";
    const char *projection_str = "ProjectionStr";

    hid_t file_id;
    hid_t dataset_id;
    hid_t attr_id;
    hid_t attr_dtype;
    herr_t status;
    hid_t mem_type_id = H5T_NATIVE_UINT16;
    int size = 6863;
    int band_num = 5;

    // namespace fs = filesystem;

    status = H5open();
    GDALAllRegister();

    for (const auto& entry : std::filesystem::directory_iterator(h5_path)) {
        if (entry.path().extension() == ".h5") {
            std::string filename = entry.path().filename().string();
            std::cout << filename << std::endl;
            std::string baseName = filename.substr(0, filename.find_last_of('.'));
            const std::string output_filename = tif_path + baseName + ".tif";

            file_id = H5Fopen((h5_path + filename).c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);

            attr_id = H5Aopen(file_id, projection_para, H5P_DEFAULT);
            attr_dtype = H5Aget_type(attr_id);
            size_t string_length = H5Tget_size(attr_dtype);
            char *attr_data = new char[1000];
            status = H5Aread(attr_id, attr_dtype, attr_data);

            std::istringstream iss(attr_data);
            std::vector<double> transform(6);
            int i = 0;
            std::string str;
            while (getline(iss, str, ',')) {
                    transform[i] = stod(str);
                    ++i;
                }

            attr_id = H5Aopen(file_id, projection_str, H5P_DEFAULT);
            attr_dtype = H5Aget_type(attr_id);
            char *attr_data_str = new char[1000];
            status = H5Aread(attr_id, attr_dtype, attr_data_str);

            dataset_id = H5Dopen1(file_id, dataset_0);
            std::vector<u_int16_t> data_0(size * size);
            status = H5Dread(dataset_id, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_0.data());

            dataset_id = H5Dopen1(file_id, dataset_1);
            std::vector<u_int16_t> data_1(size * size);
            status = H5Dread(dataset_id, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_1.data());

            dataset_id = H5Dopen1(file_id, dataset_2);
            std::vector<u_int16_t> data_2(size * size);
            status = H5Dread(dataset_id, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_2.data());

            dataset_id = H5Dopen1(file_id, dataset_3);
            std::vector<u_int16_t> data_3(size * size);
            status = H5Dread(dataset_id, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_3.data());

            dataset_id = H5Dopen1(file_id, dataset_4);
            std::vector<u_int16_t> data_4(size * size);
            status = H5Dread(dataset_id, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_4.data());

            status = H5Fclose(file_id);

            GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");

            GDALDataset *poDstDS = poDriver->Create(output_filename.c_str(), size, size, band_num, GDT_UInt16, nullptr);
            u_int16_t *band_data_0 = &data_0[0];
            poDstDS->GetRasterBand(1)->RasterIO(GF_Write, 0, 0, size, size, band_data_0, size, size, GDT_UInt16, 0, 0);
            u_int16_t *band_data_1 = &data_1[0];
            poDstDS->GetRasterBand(2)->RasterIO(GF_Write, 0, 0, size, size, band_data_1, size, size, GDT_UInt16, 0, 0);
            u_int16_t *band_data_2 = &data_2[0];
            poDstDS->GetRasterBand(3)->RasterIO(GF_Write, 0, 0, size, size, band_data_2, size, size, GDT_UInt16, 0, 0);
            u_int16_t *band_data_3 = &data_3[0];
            poDstDS->GetRasterBand(4)->RasterIO(GF_Write, 0, 0, size, size, band_data_3, size, size, GDT_UInt16, 0, 0);
            u_int16_t *band_data_4 = &data_4[0];
            poDstDS->GetRasterBand(5)->RasterIO(GF_Write, 0, 0, size, size, band_data_4, size, size, GDT_UInt16, 0, 0);

            for (int i = 1; i <= band_num; ++i) {
                GDALRasterBand *poBand = poDstDS->GetRasterBand(i);
                if (poBand != nullptr) {
                    poBand->SetNoDataValue(0);
                }
            }

            poDstDS->SetGeoTransform(transform.data());
            poDstDS->SetProjection(attr_data_str);

            GDALClose(poDstDS);
        }
    }

    status = H5close();
    return 0;
}

上述是本文完整代碼。接下來,就分段介紹一下每段代碼的具體含義。

首先,需要包含必要的頭文件。在這里,包括標(biāo)準(zhǔn)輸入輸出、字符串流、向量、文件系統(tǒng)等功能,以及hdf5庫與gdal庫。同時,定義了兩個常量字符串h5_path與tif_path,分別指向轉(zhuǎn)換前的HDF5圖像和轉(zhuǎn)換后的TIFF圖像的目錄。

#include <iostream>
#include <sstream>
#include <vector>
#include <filesystem>
#include <gdal.h>
#include <gdal_priv.h>
#include "hdf5.h"
#include "ogr_spatialref.h" 

int main(int argc, char *argv[]) {
    const std::string h5_path = "/home/ctj/data/H5/";
    const std::string tif_path = "/home/ctj/data/TIFF_48SUB/";

隨后,設(shè)定要讀取的HDF5圖像的數(shù)據(jù)集(波段)的路徑,以及空間參考信息的屬性名稱;這些參數(shù)大家就按照自己HDF5圖像的實際情況來修改即可。

接下來,初始化hdf5庫的狀態(tài)變量,這些變量是hdf5庫操作需要的。同時,用size表示圖像的寬度和高度,因為我這里HDF5圖像是正方形,所以只需指定1個值。此外,band_num表示待轉(zhuǎn)換遙感影像的波段數(shù)。

const char *dataset_0 = "/Cloud_Mask/cloudmask";
const char *dataset_1 = "/GeometricCorrection/DataSet_16_1";
// ... 省略部分代碼 ...
const char *projection_para = "ProjectionPara";
const char *projection_str = "ProjectionStr";

hid_t file_id;
hid_t dataset_id;
hid_t attr_id;
hid_t attr_dtype;
herr_t status;
hid_t mem_type_id = H5T_NATIVE_UINT16;
int size = 6863;
int band_num = 5;

緊接著,初始化hdf5庫,注冊所有可用的GDAL驅(qū)動程序。

status = H5open();
GDALAllRegister();

隨后,使用std::filesystem::directory_iterator遍歷指定目錄中的所有文件,并只處理擴(kuò)展名為.h5的文件;對于這些文件,構(gòu)建輸出文件名——基于原始文件名,去掉擴(kuò)展名并添加.tif擴(kuò)展名。

for (const auto& entry : std::filesystem::directory_iterator(h5_path)) {
    if (entry.path().extension() == ".h5") {
        std::string filename = entry.path().filename().string();
        std::cout << filename << std::endl;
        std::string baseName = filename.substr(0, filename.find_last_of('.'));
        const std::string output_filename = tif_path + baseName + ".tif";

隨后,使用H5Fopen打開HDF5圖像,在這里選擇以只讀模式訪問。

file_id = H5Fopen((h5_path + filename).c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);

隨后,需要讀取原本HDF5圖像的空間參考信息。在這里,首先打開名為projection_para的屬性,讀取其內(nèi)容到attr_data中;隨后,解析attr_data為一個包含6個元素的double向量transform——這些元素用于地理變換。

attr_id = H5Aopen(file_id, projection_para, H5P_DEFAULT);
attr_dtype = H5Aget_type(attr_id);
size_t string_length = H5Tget_size(attr_dtype);
char *attr_data = new char[1000];
status = H5Aread(attr_id, attr_dtype, attr_data);

std::istringstream iss(attr_data);
std::vector<double> transform(6);
int i = 0;
std::string str;
while (getline(iss, str, ',')) {
    transform[i] = stod(str);
    ++i;
}

類似地,讀取名為projection_str的屬性,該屬性包含投影信息的WKT字符串。

attr_id = H5Aopen(file_id, projection_str, H5P_DEFAULT);
attr_dtype = H5Aget_type(attr_id);
char *attr_data_str = new char[1000];
status = H5Aread(attr_id, attr_dtype, attr_data_str);

到這里,我們就可以對每個數(shù)據(jù)集調(diào)用H5Dopen1將其打開,并使用H5Dread將數(shù)據(jù)讀入向量中

dataset_id = H5Dopen1(file_id, dataset_0);
std::vector<u_int16_t> data_0(size * size);
status = H5Dread(dataset_id, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_0.data());

???????// ... 重復(fù)上述步驟讀取其他數(shù)據(jù)集 ...

隨后,記得關(guān)閉HDF5圖像以釋放資源。

status = H5Fclose(file_id);

接下來,就該gdal庫登場了。使用gdal庫創(chuàng)建一個新的TIFF文件,并使用RasterIO方法將每個波段的數(shù)據(jù)寫入到TIFF文件中。

GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");

GDALDataset *poDstDS = poDriver->Create(output_filename.c_str(), size, size, band_num, GDT_UInt16, nullptr);
u_int16_t *band_data_0 = &data_0[0];
poDstDS->GetRasterBand(1)->RasterIO(GF_Write, 0, 0, size, size, band_data_0, size, size, GDT_UInt16, 0, 0);
// ... 寫入其他波段 ...

同時,設(shè)置每個波段的NoData值為0,同時按照前述從HDF5圖像中讀取到的信息,設(shè)置TIFF圖像的地理變換參數(shù)和投影信息。

for (int i = 1; i <= band_num; ++i) {
    GDALRasterBand *poBand = poDstDS->GetRasterBand(i);
    if (poBand != nullptr) {
        poBand->SetNoDataValue(0);
    }
}

poDstDS->SetGeoTransform(transform.data());
poDstDS->SetProjection(attr_data_str);

GDALClose(poDstDS);

最后,不要忘記關(guān)閉hdf5庫以釋放資源。

status = H5close();

至此,大功告成。

知識補充

Windows打開HDF5圖像:HDFView軟件的下載、安裝

下面為大家介紹在Windows電腦中,下載、安裝用以查看HDF5圖像數(shù)據(jù)的軟件HDFView的方法。

HDF5(Hierarchical Data Format 5)是一種用于存儲和管理大量科學(xué)數(shù)據(jù)的文件格式,其由HDF Group開發(fā)和維護(hù),廣泛應(yīng)用于科學(xué)計算、工程、金融和醫(yī)學(xué)等領(lǐng)域。談及HDF5圖像數(shù)據(jù)在Windows中的打開方式,主要包括基于HDF Group開發(fā)的HDFView軟件來打開,以及用C++、Python來打開等2種方式。

在之前,我很少選擇用HDFView軟件來打開HDF5,因為早些時候這個軟件的安裝比較麻煩,還需要修改一下環(huán)境變量什么的,不如在Python中配置對應(yīng)的庫(比如h5py、gdal等)然后用代碼讀取來的容易。但是,后來發(fā)現(xiàn)由于szip這個壓縮模塊不再受到hdf5等庫的支持(我看網(wǎng)上說好像是因為這個庫不再是非盈利的了還是怎么),導(dǎo)致那些用到szip壓縮的HDF5圖像(比如高分系列遙感影像數(shù)據(jù)的.h5文件),就沒辦法在Windows中通過Python的h5py、gdal等方便地打開了(Linux下C++ 的hdf5庫我試了,還是可以正常打開的,但是Windows中C++ 的hdf5庫是否能打開我還沒試過)。所以,在Windows中,如果只是需要打開、查看一下數(shù)據(jù)的話(不需要代碼執(zhí)行一些分析或批處理),通過HDFView軟件來打開HDF5還是很方便的。

這里就介紹一下HDFView軟件的下載、安裝方法。

首先,我們打開HDFView軟件的Github下載網(wǎng)站(https://github.com/HDFGroup/hdfview/releases)。當(dāng)然,也可以先進(jìn)入官方下載網(wǎng)站(https://portal.hdfgroup.org/downloads/index.html),找到其中的HDFView軟件下載位置,如下圖所示。

隨后,在彈出的窗口中,點擊Download下的here字樣,如下圖所示。

隨后,進(jìn)入的就是前面提到的Github網(wǎng)站。選擇適合自己的軟件版本,如下圖所示。

下載完畢后,將壓縮包放在一個自己指定的路徑中,并解壓壓縮包,雙擊打開其中的.exe文件,如下圖所示。

隨后,將彈出安裝窗口,如下圖所示。

其中,需要注意的就是配置一下軟件的安裝路徑,如下圖所示。

完成安裝后,可以在開始菜單中看到HDFView軟件的圖標(biāo),如下圖所示。

雙擊圖標(biāo),即可打開軟件,如下圖所示。

新版本的HDFView軟件也不需要再額外配置環(huán)境變量了,按照以上方法完成安裝后,直接打開就可以使用。

到此這篇關(guān)于C++使用HDF5庫實現(xiàn)將h5圖像轉(zhuǎn)為tif格式的文章就介紹到這了,更多相關(guān)C++ HDF5實現(xiàn)h5轉(zhuǎn)tif內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解C語言初階基礎(chǔ)(2)

    詳解C語言初階基礎(chǔ)(2)

    這篇文章主要介紹了C語言中的初階基礎(chǔ),介紹了其相關(guān)概念,具有一定參考價值。需要的朋友可以了解下,希望能夠給你帶來幫助
    2021-11-11
  • 深入C++中inline關(guān)鍵字的使用

    深入C++中inline關(guān)鍵字的使用

    本篇文章是對C++中inline關(guān)鍵字的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++利用libcurl庫實現(xiàn)多線程文件下載

    C++利用libcurl庫實現(xiàn)多線程文件下載

    這篇文章主要為大家詳細(xì)介紹了C++如何利用libcurl庫實現(xiàn)多線程文件下載,文章的示例代碼講解詳細(xì),具有一定的借鑒價值,有需要的小伙伴可以參考下
    2024-01-01
  • C語言常用標(biāo)準(zhǔn)頭文件使用實例

    C語言常用標(biāo)準(zhǔn)頭文件使用實例

    在C的系列語言程序中,頭文件(通常擴(kuò)展名為.h)被大量使用,它通常包含函數(shù)、變量、結(jié)構(gòu)體等的聲明和定義,以及一些宏定義和類型定義,這篇文章主要給大家介紹了關(guān)于C語言常用標(biāo)準(zhǔn)頭文件使用的相關(guān)資料,需要的朋友可以參考下
    2024-08-08
  • C++與Lua協(xié)程交互的示例詳解

    C++與Lua協(xié)程交互的示例詳解

    Lua 語言不支持真正的多線程,即不支持共享內(nèi)存的搶占式線程,在執(zhí)行協(xié)程體的 Lua 腳本時,Lua 同樣可以調(diào)用 C++ 的函數(shù),本文給大家介紹了C++ 與 Lua 的協(xié)程交互,需要的朋友可以參考下
    2024-02-02
  • Visual?C++?6.0添加一個對話框的實現(xiàn)步驟

    Visual?C++?6.0添加一個對話框的實現(xiàn)步驟

    VC6.0是微軟公司推出的一款集成開發(fā)環(huán)境,本文主要介紹了Visual?C++?6.0添加一個對話框的實現(xiàn)步驟,具有一定的參考價值,感興趣的可以了解一下
    2024-06-06
  • C語言實現(xiàn)繪制貝塞爾曲線的函數(shù)

    C語言實現(xiàn)繪制貝塞爾曲線的函數(shù)

    貝塞爾曲線,又稱貝茲曲線或貝濟(jì)埃曲線,是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。本文將利用C語言實現(xiàn)繪制貝塞爾曲線的函數(shù),需要的可以參考一下
    2022-12-12
  • 關(guān)于C++靜態(tài)數(shù)據(jù)成員的實現(xiàn)講解

    關(guān)于C++靜態(tài)數(shù)據(jù)成員的實現(xiàn)講解

    今天小編就為大家分享一篇關(guān)于關(guān)于C++靜態(tài)數(shù)據(jù)成員的實現(xiàn)講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • C++ 實現(xiàn)桶排序的示例代碼

    C++ 實現(xiàn)桶排序的示例代碼

    桶排序或所謂的箱排序,是一個排序算法,工作的原理是將數(shù)組分到有限數(shù)量的桶子,本文詳細(xì)的介紹了如何實現(xiàn),感興趣的可以了解一下
    2021-07-07
  • C語言結(jié)構(gòu)體超詳細(xì)講解

    C語言結(jié)構(gòu)體超詳細(xì)講解

    C語言結(jié)構(gòu)體(Struct)從本質(zhì)上講是一種自定義的數(shù)據(jù)類型,只不過這種數(shù)據(jù)類型比較復(fù)雜,是由?int、char、float?等基本類型組成的。你可以認(rèn)為結(jié)構(gòu)體是一種聚合類型
    2022-04-04

最新評論

威海市| 龙川县| 会宁县| 竹北市| 荆州市| 平阴县| 沿河| 黄龙县| 祁阳县| 云梦县| 灵山县| 常山县| 广州市| 兴业县| 庐江县| 崇阳县| 永春县| 越西县| 铁力市| 漳浦县| 柯坪县| 锡林郭勒盟| 红安县| 莲花县| 汝南县| 屏山县| 工布江达县| 龙泉市| 平乡县| 札达县| 丽江市| 栖霞市| 怀柔区| 东城区| 黄梅县| 宜丰县| 西贡区| 会东县| 徐闻县| 台安县| 新余市|