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图像的合并
全色图 完整代码: #include "gdal_priv.h" #include "cpl_string.h" #include <vector> #include <algorithm> #include <iostream> #include <filesystem>using namespace std; namespace fs std::filesystem; vec…...
深入理解AQS:Java并发编程中的核心组件
目录 AQS简介AQS的设计思路AQS的核心组成部分 状态(State)同步队列(Sync Queue)条件队列(Condition Queue) AQS的内部实现 节点(Node)锁的获取与释放 独占锁共享锁 条件变量 AQS的应…...
集合进阶:List集合
一.List集合的特有方法 1.Collection的方法List都继承了 2.List集合因为有索引,所以多了很多索引操作的方法。 3.add // 1.创建一个集合List<String> list new ArrayList<>(); // 2.添加元素list.add("aaa");list.add("bbb"…...
el-table表头修改文字或者背景颜色,通过header-row-style设置样式
方式一 <el-table :header-cell-style"{text-align: center}" />方式二 <template><el-table :header-cell-style"tableHeaderColor" /> </template> <script> export default {methods: {tableHeaderColor ({row, column…...
web前端-CSS
CSS CSS概述: CSS是Cascading Style Sheets(级联样式表),是一种样式表语言,用于控制网页布局,外观(比如背景图片,图片高度,文本颜色,文本字体,高级定位等等) 可将页面的内容与样式分离开,样式放于单独的.css文件或者HTML某处 CSS是网页样式,HTML是网页…...
u8g2 使用IIC驱动uc1617 lcd 字符显示只显示上半部分,不显示下半部
使用u8g2 使用硬件iic驱动某些page为4个字节 带灰度的lcd显示屏幕的时候有时候只显示上半部,下半部不显示,例如uc1617等。 原因: 以uc1617为例,链接https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_uc1617.c 在u8x8_d_uc1617_common方法中的case U8X8_MSG_DI…...
单片机第五季-第八课:STM32CubeMx和FreeRTOS
1,FreeRTOS背景介绍 RTOS简介: 实时操作系统,本用于追求实时性的嵌入式系统,典型:ucos/uclinux/vxworks; 特点:中断响应快、一般可嵌套中断、使用实地址、多任务; (实…...
【Linux】进程控制1——进程创建和进程终止
1.进程创建 1.1.再谈fork 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。 #include <unistd.h> pid_t fork(void);//pid_t为整形 返回值:子进程中的fork()返回0ÿ…...
计算机图形学入门16:曲线
1.曲线 曲线(Curves)在图形学中应用非常广泛,比如:相机的拍摄路径、物体的移动路径、动画曲线、矢量字体等。如下图所示,是使用曲线到矢量字体的应用,通过移动一些控制点来改变字体。 2.贝塞尔曲线 2.1 贝…...
【Ruby基础01】windows和termux中搭建Ruby开发环境
windows下环境搭建 railsinstaller官方git地址 按照文档安装git、nodejs、yarn,安装教程百度一下。railsinstall可以从release页面下载最新版本4.1.0。 安装完成如下 安装RubyMine 下载RubyMine RubyMine下载地址 安装激活 下载文件,按照里面的流程…...
2406c++,iguana动态反射
原文 iguana是一个基于编译期反射的序化库,支持从结构序化到不同数据格式. iguana可序化一个C结构到json,xml,yaml和protobuf格式.这都是通过编译期反射实现的. 现在iguana也支持了动态反射,主要特征: 1,通过对象名创建对象实例 2,取对象所有字段名 3,根据字段名取字段值 4,根…...
干货分享——AB站帮你解决独立站收款难题
目前,国内已经有抖音、拼多多和淘宝平台推出“仅退款”售后服务,无疑是加剧了原本就在疯狂打价格战的国内电商的严峻现状,使得商家不得不担心被顾客“薅羊毛”。在国内电商环境严重“内卷”的情况下,拓宽海外市场不失为一大妙计。…...
C++继承与派生
1.基本知识 类的继承是新类从已有类那里获得特性,从已有的类产生新类的过程称为类的派生; 已有类称为基类或父类,派生出的新类则称为派生类或子类; 继承的功能: (1)使得基类与派生类之间建立…...
Survival Animations
一套生存游戏的动画集,包括采集、建造、捕鱼、剥皮/鞣制、篝火等更多内容。 总动画数:89 建造/制作 30 篝火 28 饮水 3 水壶 3 觅食 2 治疗 3 空闲 1 原始捕鱼 7 剥皮 1 矛捕鱼 4 伐木 5 下载:Unity资源商店链接资源下载链接 效果图:...
Cargo 教程
Cargo 教程 1. 引言 Cargo 是 Rust 编程语言的包管理器和构建工具。它为 Rust 项目提供了依赖管理、编译和打包等功能。本教程将详细介绍 Cargo 的基本用法,帮助您快速上手 Rust 项目开发。 2. 安装 Cargo 在开始使用 Cargo 之前,您需要确保已经安装了 Rust 编程语言。Ru…...
linux中“PXE高效批量装机”
在大规模的 Linux 应用环境中,如 Web 群集、分布式计算等,服务器往往并不配备光驱设备,在这种情况下,如何为数十乃至上百台服务器裸机快速安装系统呢?传统的 USB光驱、移动硬盘等安装方法显然已经难以满足需求。 PXE …...
emm, ComfyUI的作者从Stability.AI离职了
🍖背景 今天在更新ComfyUI的过程中,看到Manager中有这样一段描述: 嗯?做了新的官方网站?然后开始新篇章? 难道说ComfyUI的作者从Stability.AI离职了? 赶紧点开链接看了下,emm&…...
Redis-五种数据结构之列表(ziplist、quicklist)
列表 文章目录 列表压缩列表-ziplistziplist 定义级联更新 快速列表-quicklistquicklistNode 定义quicklist 定义quicklist常用操作其他操作quicklist 相对于普通链表优点quick应用场景在redis 中使用quicklist 列表数据类型可以存储一组按插入顺序排序的字符串,他很…...
记一次全设备通杀未授权RCE的挖掘经历
想来上一次挖洞还在一年前的大一下,然后就一直在忙活写论文,感觉挺枯燥的(可能是自己不太适合弄学术吧QAQ),所以年初1~2月的时候,有空的时候就又会挖一挖国内外各大知名厂商的设备,拿了几份思科…...
【数据库编程-SQLite3(一)】sqlite3数据库在Windows下的配置及测试
学习分析 1、资源准备2、环境配置2.1、将资源包下载解压缩保存。2.2、在QT中创建工程,配置环境 3、测试配置3.1、 sqlite3_open函数3.2、sqlite3_close函数3.3、代码测试 1、资源准备 资源包 2、环境配置 2.1、将资源包下载解压缩保存。 解压缩得到以下文件 2.2、在QT中创建…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
