【c++GDAL】IHS融合

【c++&GDAL】IHS融合
基于IHS变换融合,实现多光谱和全色影像之间的融合。IHS分别指亮度(I)、色度(H)、饱和度(S)。IHS变换融合基于亮度I进行变换,色度和饱和度空间保持不变。
IHS融合步骤:
(1)将多光谱RGB影像变换到IHS空间;
(2)基于一定融合规则使用亮度分量I与全色影像进行变换,得到新的全色I’,
(3)将I’HS逆变换到RGB空间,得到融合影像。

文章目录

      • 1.RGB2IHS
      • 2.IHS2RGB
      • 3. IHS融合
      • 4. 完整程序

1.RGB2IHS

在这里插入图片描述


void RGBtoHIS(double* R, double* G, double* B, double* pan, int w, int h,double* H,double* I,double* S)
{int sum = w * h * sizeof(double);   //图像所占容量memcpy((double *)H, (double *)R, sum);memcpy((double *)I, (double *)R, sum);memcpy((double *)S, (double *)R, sum);int i, j;double theta = 0,n;for (j = 0; j < h; j++){for (i = 0; i < w; i++){int m = j * w + i;//HIS转换公式中的RGB均需要归一化至[0,1]区间内,matlab的im2double()转换后已然至该区间内R[m] = R[m] / 255;G[m] = G[m] / 255;B[m] = B[m] / 255;//I,S,H分量转弧度,分量范围[0,1],I[m] = (R[m] + G[m] + B[m]) / 3;S[m] = 1 - min(min(R[m], G[m]), B[m]) / I[m];//acos()返回以弧度表示的 x 的反余弦,弧度区间为 [0, pi]theta = acos(0.5*((R[m] - G[m]) + (R[m] - B[m])) / sqrt((R[m] - G[m])*(R[m] - G[m]) + (R[m] - B[m]) * (G[m] - B[m])));theta = theta * 180 / pi;   //转角度if (B[m] <= G[m]){H[m] = theta;}else{H[m] = 360 - theta;}if (S[m] == 0 )    //H的非法值  && S[m]==NULL{H[m] = 0;S[m] = 0;}H[m] = H[m] * 255 /360;S[m] = S[m] * 255;I[m] = I[m] * 255;//cout <<I[m] <<"   ";  //为什么S会出现非法值}}}

2.IHS2RGB

在这里插入图片描述

void HIStoRGB(double* H, double* I, double* S, double* R, double* G, double* B, int w, int h)
{int sum = w * h * sizeof(double);   //图像所占容量memcpy((double *)R, (double *)H, sum);memcpy((double *)G, (double *)S, sum);memcpy((double *)B, (double *)I, sum);int i, j,m;for (j = 0; j < h; j++){for (i = 0; i < w; i++){m = j * w + i;H[m] = H[m] * 360 / 255;   //区间[0,360]S[m] = S[m] / 255;    //S,I的范围都在区间[0,1]上,计算得出R,G,B范围也在区间[0,1]上I[m] = I[m] / 255;if (H[m] >= 0 && H[m] < 120){B[m] = I[m] * (1 - S[m]);R[m] = I[m] * (1 + (S[m] * cos(H[m] * pi / 180)) / cos((60 - H[m])* pi / 180));G[m] = 3 * I[m] - (R[m] + B[m]);}else if (H[m] >= 120 && H[m] < 240){H[m] = H[m] - 120;R[m]= I[m] * (1 - S[m]);G[m] = I[m] * (1 + (S[m] * cos(H[m] * pi / 180)) / cos((60 - H[m])* pi / 180));B[m] = 3 * I[m] - (R[m] + G[m]);}else //(H[m] >= 240 && H[m] < 360){H[m] = H[m] - 240;G[m] = I[m] * (1 - S[m]);B[m] = I[m] * (1 + (S[m] * cos(H[m] * pi / 180)) / cos((60 - H[m])* pi / 180));R[m] = 3 * I[m] - (G[m] + B[m]);}R[m] = max(min(1.0, R[m]), 0.0);G[m] = max(min(1.0, G[m]), 0.0);B[m] = max(min(1.0, B[m]), 0.0);}}
}

3. IHS融合

一般而言融合规则为使用I和pan进行直方图匹配,下列代码使用的融合规则为线性拉伸。融合的步骤即将高分辨率影像进行线性拉伸,使之与多光谱影像亮度分量灰度范围一致,拉伸后的作为新的亮度分量newI。
线性拉伸公式:

void HIS_fusion(double* H, double* I, double* S,double * pan,double *newI,int w,int h)
{int sum = w * h * sizeof(double);   //图像所占容量memcpy((double *)newI, (double *)pan, sum);int i, j;//全色波段与I的直方图匹配double max1, min1, max2, min2;//将高分辨率影像拉伸与亮度分量一致,变换前范围[min1,max1],后[min2,max2]//获取全色影像范围[min1,max1],和多光谱I分量范围[min2,max2]max1 = pan[0]; min1 = pan[0];max2 = I[0]; min2 = I[0];for (i = 0; i < w*h; i++){max1 = max(pan[i], max1);min1 = min(pan[i], min1);max2 = max(I[i], max1);min2 = min(I[i], min1);}double A, B;A = (max2 - min2) / (max1 - min1);B = (max1*min2 - min1 * max2) / (max1 - min1);for (i = 0; i < w*h; i++){	newI[i] = pan[i] * A + B;newI[i] = newI[i] / 255;}GDALDriver* imgDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); const char* outFilename = "Inew.tif";   GDALDataset* o = imgDriver->Create(outFilename,w, h, 1, GDT_Float64, NULL);o->GetRasterBand(1)->RasterIO(GF_Write, 0, 0, w, h, newI, w, h, GDT_Float64, 0, 0);cout << "基于HIS变换的融合完成" << endl;
}

4. 完整程序

在进行匹配前,一般要将多光谱影像采样至全色影像范围内,直接设置RasterIO()的第七八个参数(nBufXSize,nBufYSize)为全色影像的大小,来进行多光谱影像的缩放,GDAL默认最邻近采样。

#include<iostream>
#include<math.h>
#include<iomanip>
#include <algorithm>
#include "gdal_priv.h"
#include "gdalwarper.h"
#define pi 3.1415926using namespace std;void RGBtoHIS(double* R, double* G, double* B, double* pan, int w, int h,double* H,double* I,double* S)
{int sum = w * h * sizeof(double);   //图像所占容量memcpy((double *)H, (double *)R, sum);memcpy((double *)I, (double *)R, sum);memcpy((double *)S, (double *)R, sum);int i, j;double theta = 0,n;for (j = 0; j < h; j++){for (i = 0; i < w; i++){int m = j * w + i;//HIS转换公式中的RGB均需要归一化至[0,1]区间内,matlab的im2double()转换后已然至该区间内R[m] = R[m] / 255;G[m] = G[m] / 255;B[m] = B[m] / 255;//I,S,H分量转弧度,分量范围[0,1],I[m] = (R[m] + G[m] + B[m]) / 3;S[m] = 1 - min(min(R[m], G[m]), B[m]) / I[m];//acos()返回以弧度表示的 x 的反余弦,弧度区间为 [0, pi]theta = acos(0.5*((R[m] - G[m]) + (R[m] - B[m])) / sqrt((R[m] - G[m])*(R[m] - G[m]) + (R[m] - B[m]) * (G[m] - B[m])));theta = theta * 180 / pi;   //转角度if (B[m] <= G[m]){H[m] = theta;}else{H[m] = 360 - theta;}if (S[m] == 0 )    //H的非法值  && S[m]==NULL{H[m] = 0;S[m] = 0;}H[m] = H[m] * 255 /360;S[m] = S[m] * 255;I[m] = I[m] * 255;//cout <<I[m] <<"   ";  //为什么S会出现非法值}}}void HIStoRGB(double* H, double* I, double* S, double* R, double* G, double* B, int w, int h)
{int sum = w * h * sizeof(double);   //图像所占容量memcpy((double *)R, (double *)H, sum);memcpy((double *)G, (double *)S, sum);memcpy((double *)B, (double *)I, sum);int i, j,m;for (j = 0; j < h; j++){for (i = 0; i < w; i++){m = j * w + i;H[m] = H[m] * 360 / 255;   //区间[0,360]S[m] = S[m] / 255;    //S,I的范围都在区间[0,1]上,计算得出R,G,B范围也在区间[0,1]上I[m] = I[m] / 255;if (H[m] >= 0 && H[m] < 120){B[m] = I[m] * (1 - S[m]);R[m] = I[m] * (1 + (S[m] * cos(H[m] * pi / 180)) / cos((60 - H[m])* pi / 180));G[m] = 3 * I[m] - (R[m] + B[m]);}else if (H[m] >= 120 && H[m] < 240){H[m] = H[m] - 120;R[m]= I[m] * (1 - S[m]);G[m] = I[m] * (1 + (S[m] * cos(H[m] * pi / 180)) / cos((60 - H[m])* pi / 180));B[m] = 3 * I[m] - (R[m] + G[m]);}else //(H[m] >= 240 && H[m] < 360){H[m] = H[m] - 240;G[m] = I[m] * (1 - S[m]);B[m] = I[m] * (1 + (S[m] * cos(H[m] * pi / 180)) / cos((60 - H[m])* pi / 180));R[m] = 3 * I[m] - (G[m] + B[m]);}R[m] = max(min(1.0, R[m]), 0.0);G[m] = max(min(1.0, G[m]), 0.0);B[m] = max(min(1.0, B[m]), 0.0);}}
}void HIS_fusion(double* H, double* I, double* S,double * pan,double *newI,int w,int h)
{int sum = w * h * sizeof(double);   //图像所占容量memcpy((double *)newI, (double *)pan, sum);int i, j;//全色波段与I的直方图匹配double max1, min1, max2, min2;//将高分辨率影像拉伸与亮度分量一致,变换前范围[min1,max1],后[min2,max2]max1 = pan[0]; min1 = pan[0];max2 = I[0]; min2 = I[0];for (i = 0; i < w*h; i++){max1 = max(pan[i], max1);min1 = min(pan[i], min1);max2 = max(I[i], max1);min2 = min(I[i], min1);}double A, B;A = (max2 - min2) / (max1 - min1);B = (max1*min2 - min1 * max2) / (max1 - min1);for (i = 0; i < w*h; i++){	newI[i] = pan[i] * A + B;newI[i] = newI[i] / 255;}GDALDriver* imgDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); const char* outFilename = "Inew.tif";   GDALDataset* o = imgDriver->Create(outFilename,w, h, 1, GDT_Float64, NULL);o->GetRasterBand(1)->RasterIO(GF_Write, 0, 0, w, h, newI, w, h, GDT_Float64, 0, 0);cout << "基于HIS变换的融合完成" << endl;
}
void main()
{GDALAllRegister();CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");const char* file1 = "多光谱.tif"; const char* file2 = "全色.tif";  GDALDataset* Mul = (GDALDataset*)GDALOpen(file1, GA_ReadOnly);GDALDataset* Pan = (GDALDataset*)GDALOpen(file2, GA_ReadOnly);if (Mul == NULL || Pan == NULL){cout << "读取图像失败" << endl;}else {cout << "读取成功" << endl;}int MulW = Mul->GetRasterXSize();int MulH = Mul->GetRasterYSize();int MulC = Mul->GetRasterCount();int PanW = Pan->GetRasterXSize();int PanH = Pan->GetRasterYSize();int PanC = Pan->GetRasterCount();GDALDataType Mtype = Mul->GetRasterBand(1)->GetRasterDataType();GDALDataType Ptype = Pan->GetRasterBand(1)->GetRasterDataType();GDALRasterBand* MulR = Mul->GetRasterBand(1);GDALRasterBand* MulG = Mul->GetRasterBand(2);GDALRasterBand* MulB = Mul->GetRasterBand(3);GDALRasterBand* P = Pan->GetRasterBand(1);//Uint16 --多光谱   Uint8 --全色unsigned short* r = new unsigned short[PanW*PanH*Mtype];unsigned short* g= new unsigned short[PanW*PanH*Mtype];unsigned short* b = new unsigned short[PanW*PanH*Mtype];unsigned char* p = new unsigned char[PanW*PanH*Ptype];P->RasterIO(GF_Read, 0, 0, PanW, PanH, p, PanW, PanH, Ptype, 0, 0);//注:设置RasterIO()的第七八个参数(nBufXSize,nBufYSize)为全色影像的大小,来进行多光谱影像的缩放,GDAL默认最邻近采样MulR->RasterIO(GF_Read, 0, 0, MulW, MulH, r , PanW, PanH, Mtype, 0, 0);MulG->RasterIO(GF_Read, 0, 0, MulW, MulH, g, PanW, PanH, Mtype, 0, 0);MulB->RasterIO(GF_Read, 0, 0, MulW, MulH, b, PanW, PanH, Mtype, 0, 0);//类型转换------------------------------------------double* R = new double[PanW*PanH];double* G = new double[PanW*PanH];double* B = new double[PanW*PanH];double* pan = new double[PanW*PanH];int i;for (i = 0; i < PanW*PanH; i++){R[i] = double(r[i]);G[i] = double(g[i]);B[i] = double(b[i]);pan[i] = double(p[i]);}GDALDriver* imgDriver = GetGDALDriverManager()->GetDriverByName("GTiff");  const char* outFilename = "Result.tif"; GDALDataset* out = imgDriver->Create(outFilename, PanW, PanH ,MulC, GDT_Float64, NULL);double* H = new double[PanW*PanH];double* I = new double[PanW*PanH];double* S = new double[PanW*PanH];RGBtoHIS(R,G,B,pan, PanW, PanH, H, I, S);double* newI = new double[PanW*PanH];HIS_fusion(H, I, S, pan, newI, PanW, PanH);   //全色波段拉伸替代I分量//最后融合的结果以RGB的形式显示double* newr = new double[PanW*PanH];double* newg = new double[PanW*PanH];double* newb = new double[PanW*PanH];HIStoRGB(H, newI, S, newr, newg, newb, PanW, PanH);out->GetRasterBand(1)->RasterIO(GF_Write, 0, 0, PanW, PanH, newr, PanW, PanH, GDT_Float64, 0, 0);out->GetRasterBand(2)->RasterIO(GF_Write, 0, 0, PanW, PanH, newg, PanW, PanH, GDT_Float64, 0, 0);out->GetRasterBand(3)->RasterIO(GF_Write, 0, 0, PanW, PanH, newb, PanW, PanH, GDT_Float64, 0, 0);/*计算得出R,G,B范围也在区间[0,1]上则以GDT_Float64存储,若转换到区间[0,255]上,若是char类型的以GDT_Byte存储*/GDALClose(Mul);GDALClose(Pan);GDALClose(out);delete R, G, B, P;delete r,g,b,pan;delete H,I,S,newI;delete newr, newg, newb;system("pause");}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/81335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全:保护你的系统

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

地牢大师问题(bfs提高训练 + 免去边界处理的特殊方法)

地牢大师问题 文章目录 地牢大师问题前言题目描述题目分析输入处理移动方式【和二维的对比】边界判断问题的解决 代码总结 前言 在之前的博客里面&#xff0c;我们介绍了bfs 基础算法的模版和应用,这里我们再挑战一下自己&#xff0c;尝试一个更高水平的题目&#xff0c;加深一…

Docker部署单点Elasticsearch与Kibana

一 、 创建网络 因为需要部署kibana容器&#xff0c;因此需要让es和kibana容器互联。这里创建一个网络&#xff1a; docker network create es-net # 创建一个网络名称为:es-net 二 、拉取并加载镜像 方式一 docker pull elasticsearch:7.12.1 版本为elasticsearch的7…

列属性与数据完整性

1.2 数据类型——值类型 1.2.1 整型 类型字节范围tinyint1-128~127smallint2-32768~32767mediumint3-8388608~8388607int4-231~231-1bigint8-263~263-1 1、无符号整数&#xff08;unsigned&#xff09;&#xff1a;无符号数没有负数&#xff0c;正数部分是有符号的两倍。 例…

Linux驱动之INPUT子系统框架

目录 一、input 子系统简介 二、input 驱动编写流程 1、注册 input_dev 2、上报输入事件 三、input_event 结构体 按键、鼠标、键盘、触摸屏等都属于输入(input)设备&#xff0c; Linux 内核为此专门做了一个叫做 input子系统的框架来处理输入事件。输入设备本质上还是字符设…

Go语言开发环境搭建指南:快速上手构建高效的Go开发环境

Go 官网&#xff1a;https://go.dev/dl/ Go 语言中文网&#xff1a;https://studygolang.com/dl 下载 Go 的语言包 进入官方网站 Go 官网 或 Go 语言中文网&#xff1a; 选择下载对应操作系统的安装包&#xff1a; 等待下载完成&#xff1a; 安装 Go 的语言包 双击运行上…

udp的简单整理

最近思考udp处理的一些细节&#xff0c;根据公开课&#xff0c;反复思考&#xff0c;终于有所理解&#xff0c;做整理备用。 0&#xff1a;简单汇总 1&#xff1a;udp是基于报文传输的&#xff0c;接收方收取数据时要一次性读完。 2&#xff1a;借助udp进行发包&#xff0c;…

C++数据结构 -- 哈希表

目录 一、哈希概念二、 哈希冲突三、 哈希函数四、 减少哈希冲突常用的方法4.1 闭散列4.1.1 闭散列的开放定址法的增容4.1.2 闭散列的开放定址法的哈希结构的实现 4.3 开散列4.3.1 开散列概念4.3.2 插入元素4.3.2 删除元素4.3.3 开散列的哈希桶的增容4.3.4 开散列的哈希桶(拉链…

快速搭建SpringBoot3.x项目

快速搭建SpringBoot3.x项目 写在前面一、创建项目二、配置多环境三、连接数据库查询数据3.1 新建数据库mybatisdemo并且创建sys_user表3.2 创建实体类3.2 创建Mapper接口3.3 添加mybatis.xml文件3.4 新建service 接口及实现类3.5 创建Controller 四、封装统一结果返回4.1 定义 …

Attention is all you need 论文笔记

该论文引入Transformer&#xff0c;主要核心是自注意力机制&#xff0c;自注意力&#xff08;Self-Attention&#xff09;机制是一种可以考虑输入序列中所有位置信息的机制。 RNN介绍 引入RNN为了更好的处理序列信息&#xff0c;比如我 吃 苹果&#xff0c;前后的输入之间是有…

【问题记录】解决Git上传文件到GitHub时收到 “GH001: Large files detected” 错误信息!

环境 Windows 11 家庭中文版git version 2.41.0.windows.1GitHub 问题情况 在命令行中使用git上传pdf文件到GitHub服务器时&#xff0c;提示了如下警告信息&#xff1a; 原因是 GitHub 有一个文件大小限制&#xff0c;通常为 100 MB。 如果尝试上传大于此限制的文件&#xff0c…

Long类型雪花算法ID返回前端后三位精度缺失问题解决

目录 一、问题描述二、问题复现1.Maven依赖2.application.yml 配置3.DemoController.java4.snowflakePage.html 页面5.DemoControllerAdvice.java 监听6.问题复现 三、原因分析四、问题解决方案一方案二 一、问题描述 Java 后端使用雪花算法生成 Long 类型的主键 ID&#xff0…

快速学会搭建微信小程序的基础架构

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 基础架构 构建界面 引入 uni-ui 组件库 组件自动引入 配置TS类型 状态管理 持久化 数据交互 请…

最小二乘法

Least Square Method 1、相关的矩阵公式2、线性回归3、最小二乘法3.1、损失函数&#xff08;Loss Function&#xff09;3.2、多维空间的损失函数3.3、解析法求解3.4、梯度下降法求解 1、相关的矩阵公式 P r e c o n d i t i o n : ξ ∈ R n , A ∈ R n ∗ n i : σ A ξ σ ξ…

leetcode 332. Reconstruct Itinerary(重构行程)

有一些票tickets, tickets[ i ] [from, to], 每个出发到达城市名字都是3个大写英文字母&#xff0c; 同一个出发城市时&#xff0c;优先去字母顺序较小的到达城市。 必须先从“JFK”出发。 每个ticket必须用且只用一次&#xff0c;所有ticket一定会形成至少一个有效的行程&…

【JAVA-Day21】序列化和反序列化,学会Java的编解码方法

标题序列化和反序列化&#xff0c;学会Java的编解码方法 序列化和反序列化&#xff0c;学会Java的编解码方法摘要引言一、什么是序列化1.1 序列化的过程 二、什么是反序列化2.1 反序列化的过程 三、为什么要进行序列化和反序列化3.1 主要目的3.2 应用场景 四、总结参考资料 博主…

Springboot 实践(18)Nacos配置中心参数自动刷新测试

前文讲解了Nacos 2.2.3配置中心的服务端的下载安装&#xff0c;和springboot整合nacos的客户端。Springboot整合nacos关键在于使用的jar版本要匹配&#xff0c;文中使用版本如下&#xff1a; ☆ springboot版本: 2.1.5.RELEASE ☆ spring cloud版本 Greenwich.RELEASE ☆ sp…

辅助驾驶功能开发-功能规范篇(21)-4-XP行泊一体方案功能规范

XPilot Parking 自动泊车系统 • 超级自动泊车辅助(Super AutoParking Assist)、语音控制泊车辅助(Autoparking with Speech) - 产品定义 超级自动泊车辅助是⼀个增强的自动泊车辅助系统。在超级自动泊车辅助系统中,识别车位将会变得实时可见, 并且不可泊入的⻋位也将…

如何在 Excel 中计算日期之间的天数

计算两个日期之间的天数是 Excel中的常见操作。无论您是规划项目时间表、跟踪时间还是分析一段时间内的趋势&#xff0c;了解如何在 Excel 中查找日期之间的天数都可以提供强大的日期计算功能。 幸运的是&#xff0c;Excel 提供了多种简单的方法来获取两个日期之间的天数。继续…

数据可视化

一、Flask #通过访问路径&#xff0c;获取用户的字符串参数 app.route(/user/<name>) def welcome(name):return "你好&#xff0c;%s"%nameapp.route(/user/<int:id>) def welcome2(id):return "你好&#xff0c;%d号的会员"%id能够自动根据…