基于PCA-WA(Principal Component Analysis-weight average)的图像融合方法 Matlab代码及示例

摘要:

        高效地将多通道的图像数据压缩(如高光谱、多光谱成像数据)至较低的通道数,对提高深度学习(DL)模型的训练速度和预测至关重要。本文主要展示利用PCA降维结合weight-average的图像融合方法。文章主要参考了题为“Noninvasive Detection of Salt Stress in Cotton Seedlings by Combining Multicolor Fluorescence–Multispectral Reflectance Imaging with EfficientNet-OB2”在论文中使用的方法。

论文源:Noninvasive Detection of Salt Stress in Cotton Seedlinmbining Multicolor Fluorescence–Multispectral Reflectance Imaging with EfficientNet-OB2 | Plant Phenomics (science.org)

PCA-WA简介:

PCA-WA(主成分分析-加权平均)是一种图像融合方法,结合了主成分分析(PCA,principal component analysis)和加权平均(WA,weight average)两种技术。

优点:

  1. 保留主要信息:通过PCA方法,可以提取出源图像中的主要成分,即包含最多信息的特征。这有助于在融合过程中保留关键信息,使得融合后的图像在保留重要特征方面表现较好。
  2. 降低维度:PCA方法可以将高维数据降维,从而减少计算量和存储需求。这在处理大规模图像数据时尤为重要,可以加快处理速度和节省存储空间。

缺点:

  1. 对源图像质量敏感:PCA-WA方法的性能在很大程度上取决于源图像的质量。如果源图像存在噪声、模糊或对比度低等问题,那么融合后的图像质量可能会受到影响。
  2. 可能产生光谱失真:在使用PCA进行降维时,可能会丢失一些光谱信息。这可能导致融合后的图像在光谱特性上与源图像存在差异,从而产生光谱失真现象。

注意事项

数据预处理:在进行数据融合之前需要将数据进行对应的校正,避免后续噪声污染

输入数据:为M*N*C的double矩阵也就是校正后的图像浮点数值。需要事先将这些变量存储为.mat文件。储存变量命为a

操作示范

首先是输入的文件:如图,PCA需要所有处理的样本信息,所以按照格式将所有样本整理好

单个样本的信息如图:我测试的数据是自己采集的4K分辨率且有14个通道的多源光谱数据,变量统一为a,其中几个未融合的通道的图像可以展示如下

 使用PCA-WA算法进行图像融合后,生成的图像会存放至预设的文件夹中

融合后的数据,前三个主成分占95%的贡献率,所以融合后为3个主成分通道。手动将这些数据归一化映射至uint8(0-255)展示如下:融合后数据量得到了充分的压缩。

代码

主脚本代码FusionProject

clear all

获得PCA-WA融合的数据
WA图像融合,全称为Weighted Averaging图像融合,
也叫简单加权融合或者像素加权平均法,是一种图像融合方法。
这种方法的基本思想是将多源信道采集到的关于同一目标的图像
数据经过处理和计算,将各自信道中的有利信息提取出来,然后综合成
一幅高质量的图像。

在具体实现时,WA图像融合通过对来自不同图像的对应像素进行加权平均,
以得到融合后图像中的每个像素值。这种方法具有简单易实现、运算速度快
的优点,并能提高融合图像的信噪比。然而,它也存在一些缺点,比如可能
会削弱图像中的细节信息,降低图像的对比度,并在一定程度上使图像中的
边缘变得模糊。

为了改进这些缺点,可以采用一些优化方法,
如主成分分析(Principal Component Analysis,PCA)来优化权值的选择,
从而得到一幅亮度方差最大的融合图像。

%输入部分(根据自己的需求修改这部分内容)

%要处理文件所在的文件夹
% (多个文件夹则输入多个文件夹,要包含所有样本,PCA计算才准确),样本变量名均为a
% 注意地址要单引号标志
DealPath{1}='F:\Test\A';
DealPath{2}='F:\Test\B';

%处理好的文件输出位置,对应你输入文件的数量
OutputPath{1}='C:\Users\ljy\Desktop\Test1\A';
OutputPath{2}='C:\Users\ljy\Desktop\Test1\B';

%%图片的基本信息
%通道数
ChannelNum=14;
%红色荧光(F740)所在的通道
fluo_CNum=4;
%图像输出的分辨率
outputReso=[300 400];

orinPath=cd();
%%这一过程可能很漫长,运行时间主要取决于你的样本量、数据大小、CPU性能及硬盘速度。
%%1000个样本跑一个小时以上是正常的


%%阶段1:获取数据的通道均值
fileNum=length(DealPath);
allData=[];
%启用红色荧光分割图像,(如果前期工作已经校正及图像分割了,请关闭)
% 其他数据把分割关掉(1改为0)
for i=1:fileNum
    allData=[allData;AverageChannelData(DealPath{i},ChannelNum,[0,fluo_CNum])];
end

%阶段二:PCA分析

%归一化
[ynum,~]=size(allData);
stdr =std(allData); %计算标准差,计算每一列的标准差
averageD=mean(allData,1);

for i=1:ynum
    data2(i,:)=allData(i,:)-averageD(1,:);
end
%sr是预处理后的数据,使原始数据每个参数除于其标准差
sr =data2./repmat(stdr,size(allData,1),1);

%% PCA

%获取主成分系数
[coeff,~,~,~,explained,~]= pca(sr);

%分析占 95% 解释性的主成分
for i=1:ChannelNum
    if sum(explained(1:i))>95
        numP=i
        break
    end
end



%阶段3融合图像
for i=1:fileNum
    srcDir=dir(DealPath{i}); %获得选择的文件夹
    [numFile,~]=size(srcDir);
    for j=3 :numFile
        names_Fir=srcDir(j).('name');
        newfile_Fir=[DealPath{i},'\',names_Fir];%数据文件名
        load(newfile_Fir);
        %图像归一化
        for cn=1:numP
            Nora(:,:,cn)=(a(:,:,cn)-averageD(cn))./stdr(cn);
        end
        %融合
        FusionPic=imresize(FusionPic_WA_PCA(Nora,coeff),outputReso);
        cd(OutputPath{i});
        save(names_Fir,"FusionPic");%储存
        cd(orinPath);
    end
end

附带自定义函数

T_SGM
%阈值分割函数,获得分割的蒙版

%输入:img:图像(灰度图像)  
% ThresH:阈值
% (为0时为二值化分割,为1时为迭代法全局阈值分割,为2时为全局阈值Otsu法阈值分割,三为基于形态学元素的局部分割,4为指定阈值分割)
%pluse:补充数据,当ThresH为3时,pluse表示形态学的元素的半径,其值越大,分割区域越大,为4时为分割的数

function output=T_SGM(img,ThresH,pluse)

img=im2double(img);%图像二值化

if ThresH==0
    output =im2double(imbinarize(I));
elseif ThresH==1
    T=0.5*(min(img(:))+max(img(:)));
    done=false;
    while ~done
       	g=(img>=T);%建立区域g,为大于阈值的部分
       	Tn=0.5*(mean(img(g))+mean(img(~g)));%当图像中g的区域与非g的区域的均值接近于目标阈值时,分割完成
       	done = abs(T-Tn)<0.1;
       	T=Tn;
    end
    output=imbinarize(img,T);
elseif ThresH==2
    Th=graythresh(img);%阈值
    output=imbinarize(img,Th);
elseif ThresH==3
    se=strel('disk',pluse);%建立形态学 结构元素
    ft=imtophat(img,se);%使用结构元素进行滤波
    Thr=graythresh(ft);%早对滤波后的图像进行阈值取值
    output = imbinarize(ft,Thr);
elseif ThresH==4
    output=imbinarize(img,pluse);
end


end

 SelecValueOfPic
function [actualaverageValue,actualNum,segama,K,S] = SlecValueOfPic(img,range,method)
%SLECVALUEOFPIC
%输入一张分割后的灰度图片;根据这这张图片的像素值统计(除零外),取中间range值的范围的内容;并返回这个范围的平均值;
%这个取值的逻辑是取像素值中间的分布,以个数划分,如10个像素取60%取平均,就是取中间值的6个像素的平均;这种方法可以提高图像反射率的数值的鲁棒性,将噪点和背景的反射屏蔽掉一部分;

%   actualavergeValue:最后输出的平均值
%   img:输入的图像
%   range:范围,大小为0-1之间;(折合百分数)
%   method:方法 1为中位数法 2为正太分布法 3为平均数法
%   actualnum:为成像面积
%   segama:偏度

segama=0;
K=0;
S=0;
if method==1
    staticD=imhist(img);
    allN=sum(staticD(2:256,1));
    rangeN=ceil(allN*range);
    thresholdNum=ceil((allN-rangeN)/2);

    thresholdValue=0;%初始化
    thresholdValueHigh=0;
    actualNum=0;

    for i=2:256%计算区间,为0的背景不算;
        nowSum=sum(staticD(2:i,1));

        if nowSum>thresholdNum
            if thresholdValue==0
                thresholdValue=i;%获得了最低门槛;
            end
        end
        if nowSum>(thresholdNum+rangeN)
            if thresholdValueHigh==0
                thresholdValueHigh=i;%获得了最高门槛;
            end
        end
    end
    allV=0;
    if thresholdValue~=0
        for j=thresholdValue:thresholdValueHigh%计算这个像素区间的平均值
            repreValue=staticD(j,1)*(j-1);%统计是从零开始统计;
            allV=allV+repreValue;
        end
        actualNum=sum(staticD(thresholdValue:thresholdValueHigh,1));
        actualaverageValue=allV/rangeN;
    else
        actualNum=0;
        actualaverageValue=0;
    end

elseif method==2%正太分布估计,此时actualnum为偏度
    [r,c]=find(img);
    [actualaverageValue,segama] = normfit(img(find(img)));
    K=kurtosis(img(find(img)));%峰度
    S=skewness(img(find(img)));%偏度
    [actualNum,~]=size(r);

elseif method==3%平均,正太分布和平均效果一致(如果符合正太分布的话);
    [r,c]=find(img);
    actualaverageValue = mean(img(find(img)),'all');
    [actualNum,~]=size(r);
end

end
Map_uint8
function U8_p =Map_uint8(doubleP,num_min,num_max)
band_div=(num_max-num_min)/256;
U8_p=(doubleP-num_min)/band_div;
MapMax=find(U8_p(:,:)>255);
MapMin=find(U8_p(:,:)<0);
U8_p(MapMax)=255;
U8_p(MapMin)=0;
U8_p=uint8(U8_p);
end
FusionPic_WA_PCA
function FusionPic=FusionPic_WA_PCA(IMGmat,PCAdet)

%输入:IMGmat 为基本处理(校正)后的成像数据(储存格式为matlab data *.mat)
%               大小为M(图像高度)*N(图像宽度)*C(图像通道数)
%输入: PCAdet 为PCA的降维数据,为PCA-WA的权重提供参考


[y,x,cnum]=size(IMGmat);
FusionPic=zeros(y,x,cnum);
%数据叠加
for i=1:cnum
    for j=1:cnum
        FusionPic(:,:,i)=FusionPic(:,:,i)+PCAdet(i,j)*IMGmat(:,:,j);
    end
end


 DeleNos_dot
%输入 mask为2值化图像
%在特定区域内的分割若达不到比例,则进行消除

function output=DeleNos_dot(mask,length,Percent)

numDiv=ceil(Percent*length^2);
[ysize,xsize]=size(mask);

for i=length:xsize-length%用区域蒙版的量做判断消除杂点
    for j=length:ysize-length
        if mask(j,i)==1
            if sum(sum(mask(j-3:j+3,i-3:i+3)))<numDiv
                mask(j,i)=0;
            end
        end
    end
end
output=mask;
AverageOneSample

function data = AverageOneSample(Sample,EX)
%主要是求图像校正后,分割后的平均值
%EX为1*2的double 分别代表范围和取值的方法 默认【0.6,3】

%[actualaverageValue,actualNum,segama,K,S] = slecValueOfPic(img,range,method)
%SLECVALUEOFPIC
%输入一张分割后的灰度图片;根据这这张图片的像素值统计(除零外),取中间range值的范围的内容;并返回这个范围的平均值;
%   actualavergeValue:最后输出的平均值
%   img:输入的图像
%   range:范围,大小为0-1之间;
%   method:方法 1为中位数法 2为正太分布法 3为平均数法,基本上2和3一致
%   actualnum:为成像面积
%   segama:偏度

[x,y,z]=size(Sample);
for i=1:z
    [data(i,1),data(i,2),~,~,~] = SlecValueOfPic(Sample(:,:,i),EX(1),EX(2));
end



end
AverageChannelData
%检查文件数量是否匹配
function allData=AverageChannelData(aimPath,numchannel,IFSGM)

%输入部分
%aimPath:采集目标的路径
%aimPath='F:\23新疆大田数据校正后\SSS';%目标路径,得用单引号"
%IFSGM 大小为1*2,(1,1)若为1则执行基于荧光的分割,(1,2)为红色荧光所在的位置

orinPath=cd();%函数执行所在的路径,默认原路径
%目标文件
srcDir=dir(aimPath); %获得选择的文件夹
[numFile,~]=size(srcDir);
data=zeros(numchannel,2);
for j=3 :numFile
    names_Fir=srcDir(j).('name');
    newfile_Fir=[aimPath,'\',names_Fir];%数据文件名
    load(newfile_Fir);
    if IFSGM(1,1)==1
        tureMask=T_SGM(Map_uint8(a(:,:,3),min(min(a(:,:,3))),max(max(a(:,:,3)))),4,0.045);%图像分割
        tureMask2=DeleNos_dot(tureMask,10,0.2);%清理噪点
        [yn,xn,zn]=size(a);
        b=zeros(yn,xn,zn);
        for i=1:14
            b(:,:,i)=a(:,:,i).*tureMask2;
        end
    else
        b=a;
    end
    data = AverageOneSample(b,[0.6,3]);
    allData(j-2,1:14)=data(1:14,1)';
end


end

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Leetcode】466. 统计重复个数

文章目录 题目思路代码 题目 466. 统计重复个数 思路 题目要求找出一个最大整数 m&#xff0c;使得经过 n2 个字符串 s2 组成的字符串能够被经过 n1 个字符串 s1 组成的字符串完全包含的次数。使用动态规划来记录每个位置匹配的情况&#xff0c;并通过循环节的分析来计算最…

leetcode刷题日记:222. Count Complete Tree Nodes(完全二叉树的节点个数)

这一道题&#xff0c;我们可以选择直接进行二叉树的遍历&#xff0c;将所有结点遍历一遍就能得到完全二叉树的结点个数&#xff0c;时间复杂度为O(n)。 代码如下&#xff1a; int countNodes(struct TreeNode* root) {if(rootNULL){return 0;}return countNodes(root->left…

(NeRF学习)NeRFStudio安装win11

参考&#xff1a; 【深度学习】【三维重建】windows11环境配置tiny-cuda-nn详细教程nerfstudio介绍及在windows上的配置、使用NeRFStudio官网githubRuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory原因及解决 目录 requireme…

element-ui table-自定义表格某列的表头样式或者功能

自带表格 自定义表格某列的表头样式或者功能 <el-table><el-table-column :prop"date">//自定义表身每行数据<template slot-scope"scope">{{scope.row[scope.column.label] - ? - : scope.row[scope.column.label]}}</template>…

使用Gitea搭建自己的git远程仓库

Gitea 为什么需要自建仓库 原因只有一个&#xff1a;折腾。其实国内的码云加上github已经足够用了。 官方原话 Gitea 的首要目标是创建一个极易安装&#xff0c;运行非常快速&#xff0c;安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言&#xff0c;这使我们…

计算机毕业设计 SpringBoot的乡村养老服务管理系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

是否需要跟上鸿蒙(OpenHarmony)开发岗位热潮?

前言 自打华为2019年发布鸿蒙操作系统以来&#xff0c;网上各种声音百家争鸣。尤其是2023年发布会公布的鸿蒙4.0宣称不再支持Android&#xff0c;更激烈的讨论随之而来。 本文没有宏大的叙事&#xff0c;只有基于现实的考量。 通过本文&#xff0c;你将了解到&#xff1a; Har…

使用Wireshark进行网络流量分析

目录 Wireshark是什么&#xff1f; 数据包筛选 筛选指定ip 使用逻辑运算符筛选 HTTP模式过滤 端口筛选 协议筛选 包长度筛选 数据包搜索 数据流分析 数据包导出 Wireshark是什么&#xff1f; 通过Wireshark&#xff0c;我们可以捕获和分析网络数据包&#xff0c;查看…

用ChatGPT方式编程!GitHub Copilot Chat全面开放使用

全球著名开源分享平台GitHub在官网宣布&#xff0c;经过几个月多轮测试的GitHub Copilot Chat&#xff0c;全面开放使用&#xff0c;一个用ChatGPT方式写代码的时代来啦&#xff01; 据悉&#xff0c;Copilot Chat是基于OpenAI的GPT-4模型&#xff0c;再结合其海量、优质的代码…

GitHub Copilot 最佳免费平替:阿里通义灵码

之前分享了不少关于 GitHub Copilot 的文章&#xff0c;不少粉丝都评论让我试试阿里的通义灵码&#xff0c;这让我对通义灵码有了不少的兴趣。 今天&#xff0c;阿七就带大家了解一下阿里的通义灵码&#xff0c;我们按照之前 GitHub Copilot 的顺序分享通义灵码在相同场景下的…

【Linux 内核源码分析】GPIO子系统软件框架

Linux内核的GPIO子系统是用于管理和控制通用输入输出&#xff08;GPIO&#xff09;引脚的软件框架。它提供了一套统一的接口和机制&#xff0c;使开发者能够方便地对GPIO进行配置、读写和中断处理。 主要组件&#xff1a; GPIO框架&#xff1a;提供了一套API和数据结构&#x…

【深度学习-基础学习】Self-Attention 自注意力机制 笔记

本篇文章学习总结 李宏毅 2021 Spring 课程中关于 Self-Attention 自注意力 机制相关的内容。课程链接以及PPT&#xff1a;李宏毅Spring2021ML 关于 Self-Attention 机制想要解决的问题 通常来说&#xff0c; 我们的模型的输入会是一个vector&#xff0c;然后输出可能是 一个数…

python图形界面设计工具,python的图形界面gui编程

大家好&#xff0c;小编为大家解答python编写图形化界面的工具的问题。很多人还不知道python图形界面设计工具&#xff0c;现在让我们一起来看看吧&#xff01; 1.根窗体 &#xff08;1&#xff09;创建根窗体对象 ①tkinter.Tk():创建一个根窗体对象。使用后会立即显示窗口&am…

基于 vite 创建 Vue3 项目

1、基于 vue-cli 创建 ## 查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上 vue --version## 安装或者升级你的vue/cli npm install -g vue/cli## 执行创建命令 vue create vue_test## 随后选择3.x ## Choose a version of Vue.js that you want to start the proje…

通过IP地址防范钓鱼网站诈骗的有效措施

随着互联网的普及&#xff0c;钓鱼网站诈骗成为一种广泛存在的网络犯罪行为。通过冒充合法网站&#xff0c;攻击者试图窃取用户的敏感信息。本文将探讨如何通过IP地址防范钓鱼网站诈骗&#xff0c;提供一系列有效的措施&#xff0c;以加强网络安全&#xff0c;保护用户免受诈骗…

审计报告翻译服务,如何确保翻译质量?

近年来&#xff0c;随着跨国经济活动的增多&#xff0c;越来越多的企业需要进行跨国审计&#xff0c;而审计报告的翻译就变得尤为重要。那么&#xff0c;审计报告翻译服务&#xff0c;如何确保翻译质量&#xff1f;  据了解&#xff0c;审计报告翻译是全面揭示被审计单位实质情…

【Jenkins】centos服务器部署jenkins2.426

Jenkins部署 版本选择说明 目前项目上用的版本是比较旧的&#xff0c;现在用不了&#xff0c;插件版本问题比较恶心。试过2.346&#xff0c;插件问题没解决&#xff0c; 单独找&#xff08;*.hpi&#xff09;插件匹配的版本太麻烦了。 前置环境部署 git 略 JDK11 该jenk…

企业招聘信息发布平台

吉鹿力招聘网是中国有名的专业招聘网站&#xff0c;拥有超过1500万招聘信息&#xff0c;涵盖了全国各地的企业招聘信息&#xff0c;是求职者获取新招聘信息的良好渠道。百度搜索吉鹿力招聘网就能下载并投递简历&#xff0c;开启求职之旅。 吉鹿力招聘网企业注册流程 首先打开…

c语言:用指针输入两个数组|练习题

一、题目 利用指针&#xff0c;输入两个数组 如图&#xff1a; 二、代码截图【带注释】 三、源代码【带注释】 #include <stdio.h> int main() { int a[50]; int b[50]; int *paa,*pbb; //输入第一组数组 printf("请输入第一组5个数字&#xff1a;…

C++ 二进制图片的读取和blob插入mysql_stmt_init—新年第一课

关于二进制图片的读取和BLOB插入一共包含五步 第一步&#xff1a;初始化 MYSQL_STMT* stmt mysql_stmt_init(&mysql); 第二步&#xff1a;预处理sql语句 mysql_stmt_prepare(stmt,sql,sqllen); 第三步&#xff1a;绑定字段 mysql_stmt_bind_param(stmt,bind); 第四…