C++使用GDAL库完成tiff图像的合并

2024-06-19 17:12

本文主要是介绍C++使用GDAL库完成tiff图像的合并,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

全色图

完整代码:

#include "gdal_priv.h"
#include "cpl_string.h"
#include <vector>
#include <algorithm>
#include <iostream>
#include <filesystem>using namespace std;
namespace fs = std::filesystem;
vector<pair<int, int>> imageDims; // 存储每个图像的宽和高
vector<string> fileNames;void concatenateImages(const string& folderPath, const string& outputFilePath) {GDALAllRegister();//注册驱动CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");//支持中文路径GDALDataType dataType{};// 遍历文件夹获取图像for (const auto& entry : fs::directory_iterator(folderPath)) {if (entry.is_regular_file() && entry.path().extension() == ".tiff") {fileNames.push_back(entry.path().string());GDALDataset* ds = (GDALDataset*)GDALOpen(entry.path().string().c_str(), GA_ReadOnly);if (ds) {imageDims.push_back({ ds->GetRasterXSize(), ds->GetRasterYSize() });GDALClose(ds);// 获取第一个波段的数据类型GDALRasterBand* band = ds->GetRasterBand(1);dataType = band->GetRasterDataType();}else {cerr << "无法打开文件: " << entry.path() << endl;}}}// 计算新图像的尺寸int totalWidth = 0;int maxHeight = 0;for (const auto& dim : imageDims) {totalWidth += dim.first;maxHeight = max(maxHeight, dim.second);}// 创建输出图像GDALDriver* driver = GetGDALDriverManager()->GetDriverByName("GTiff");GDALDataset* outDataset = driver->Create(outputFilePath.c_str(), totalWidth, maxHeight, 1, dataType, nullptr);if (outDataset == nullptr) {cerr << "创建输出文件失败." << endl;return;}GDALRasterBand* outBand = outDataset->GetRasterBand(1);outBand->Fill(0); // 填充黑色背景// 拼接图像int xOff = 0;vector<unsigned short> buffer; // 缓冲区for (size_t i = 0; i < fileNames.size(); ++i) {GDALDataset* dataset = (GDALDataset*)GDALOpen(fileNames[i].c_str(), GA_ReadOnly);if (dataset) {GDALRasterBand* inBand = dataset->GetRasterBand(1);int width = imageDims[i].first; // 当前处理图像的宽度int height = imageDims[i].second;// 动态调整缓冲区大小,适应当前图像宽度buffer.resize(width);// 从输入波段读取数据到缓冲区for (int j = 0; j < height; ++j) {CPLErr err = GDALRasterIO(inBand, GF_Read, 0, j, width, 1,&buffer[0], width, 1, dataType, 0, 0);if (err != CE_None) {cerr << "从输入波段读取数据时出错." << endl;break;}// 再从缓冲区写入到输出波段err = GDALRasterIO(outBand, GF_Write, xOff, j, width, 1,&buffer[0], width, 1, dataType, 0, 0);if (err != CE_None) {cerr << "将数据写入输出波段时出错." << endl;break;}}GDALClose(dataset);xOff += width; // 更新x偏移量,准备拼接下一幅图像}}// 写入并关闭输出文件outDataset->FlushCache();GDALClose(outDataset);
}int main() {string folderPath = "C:\\Users\\WHU\\Desktop\\PAN"; // 文件夹路径string outputFilePath = "C:\\Users\\WHU\\Desktop\\PAN\\image.tiff"; // 输出文件路径concatenateImages(folderPath, outputFilePath);return 0;
}

多光谱:

完整代码:

#include "gdal_priv.h"
#include <vector>
#include <algorithm>//计算图像宽度和高度
#include <filesystem>//读文件
#include <numeric> //数值操作   
#include <iostream>
#include <memory>//智能指针using namespace std;// 初始化GDAL
void InitializeGDAL()
{GDALAllRegister();CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");//支持中文路径
}// 获取图像的宽度、高度和波段数
bool GetImageSizeAndBands(const string& filePath, int& width, int& height, int& bands)
{GDALDataset* dataset = (GDALDataset*)GDALOpen(filePath.c_str(), GA_ReadOnly);if (!dataset){printf("打开失败 %s\n", filePath.c_str());return false;}width = dataset->GetRasterXSize();height = dataset->GetRasterYSize();bands = dataset->GetRasterCount();GDALClose(dataset);return true;
}// 拼接多波段图像
void StitchMultiBandImages(const vector<string>& fileNames, const string& outputFilePath)
{InitializeGDAL();vector<int> widths, heights, bandCounts;for (const auto& fileName : fileNames){int width, height, bands;if (GetImageSizeAndBands(fileName, width, height, bands)){widths.push_back(width);heights.push_back(height);bandCounts.push_back(bands);}else{printf("获取失败 %s\n", fileName.c_str());}}int totalWidth = accumulate(widths.begin(), widths.end(), 0);int maxHeight = *max_element(heights.begin(), heights.end());int maxBands = *max_element(bandCounts.begin(), bandCounts.end());GDALDriver* driver = GetGDALDriverManager()->GetDriverByName("GTiff");char** options = nullptr; //创建输出图像GDALDataset* dstDataset = driver->Create(outputFilePath.c_str(), totalWidth, maxHeight, maxBands, GDT_UInt16, options);for (int band = 1; band <= maxBands; ++band){// 初始化输出波段为黑色GDALRasterBand* dstBand = dstDataset->GetRasterBand(band);//智能管理缓冲区内存unique_ptr<float[]> buffer(new float[totalWidth * maxHeight]);fill_n(buffer.get(), totalWidth * maxHeight, 0); // 填充黑色dstBand->RasterIO(GF_Write, 0, 0, totalWidth, maxHeight, buffer.get(), totalWidth, maxHeight, GDT_UInt16, 0, 0);}// 逐个读取并写入图像数据int xOffset = 0;for (size_t i = 0; i < fileNames.size(); ++i){GDALDataset* srcDataset = (GDALDataset*)GDALOpen(fileNames[i].c_str(), GA_ReadOnly);if (srcDataset){for (int band = 1; band <= bandCounts[i]; ++band){GDALRasterBand* srcBand = srcDataset->GetRasterBand(band);GDALRasterBand* dstBand = dstDataset->GetRasterBand(band);unique_ptr<float[]> buffer(new float[widths[i] * heights[i]]);CPLErr readErr = srcBand->RasterIO(GF_Read, 0, 0, widths[i], heights[i], buffer.get(), widths[i], heights[i], GDT_UInt16, 0, 0);if (readErr == CE_None){dstBand->RasterIO(GF_Write, xOffset, 0, widths[i], heights[i], buffer.get(), widths[i], heights[i], GDT_UInt16, 0, 0);}}GDALClose(srcDataset);}xOffset += widths[i];}GDALClose(dstDataset);
}
// 从指定目录获取所有.tiff文件路径
vector<string> GetTiffFilesFromDirectory(const string& directoryPath)
{vector<string> tiffFiles;for (const auto& entry : filesystem::directory_iterator(directoryPath)){if (entry.is_regular_file() && entry.path().extension() == ".tiff"){tiffFiles.push_back(entry.path().string());}}return tiffFiles;
}
int main() {string folderPath = "C:\\Users\\WHU\\Desktop\\MSS"; // 文件夹路径string outputFilePath = "C:\\Users\\WHU\\Desktop\\MSS\\stitched_image.tiff"; // 输出文件路径// 获取指定文件夹内的所有.tiff文件路径vector<string> tiffFiles = GetTiffFilesFromDirectory(folderPath);if (!tiffFiles.empty()) {// 使用获取到的文件列表进行图像拼接StitchMultiBandImages(tiffFiles, outputFilePath);cout << "图像成功生成" << endl;}else {cerr << "没有找到该路径: " << folderPath << endl;}return 0;
}


 

这篇关于C++使用GDAL库完成tiff图像的合并的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1075645

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash