├── ERGAS.m ├── ERGAS_Index.m ├── Main_PSO.m ├── Objective_Evaluation ├── CC.m ├── D_lambda.m ├── D_s.m ├── ERGAS.m ├── MTF.m ├── MTF_PAN.m ├── Q.m ├── QNR.m ├── RASE.m ├── RMSE.m ├── SAM.m ├── img_qi.m ├── norm_blocco.m ├── odd_extension.m ├── onion_mult.m ├── onion_mult2D.m ├── onions_quality.m ├── q2n.m ├── ssim.m └── uqi.m ├── QuickBird_Data ├── MS.mat └── PAN.mat ├── README.md ├── expEdge.m └── impGradDes.m /ERGAS.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArianAzg/Image-Fusion-with-PSO-Algorithm/cae732d40d2a5ea972402687345e31285baa07a5/ERGAS.m -------------------------------------------------------------------------------- /ERGAS_Index.m: -------------------------------------------------------------------------------- 1 | function ERGAS_ind = ERGAS_Index(x) 2 | 3 | %% Description 4 | 5 | % This code provides the fuison results of PANchromatic (PAN) and MultiSpectral (MS) images 6 | % based on Particle Swarm Optimization (PSO) algorithm proposed in the following reference: 7 | 8 | % [1] A. Azarang and H. Ghassemian, "An adaptive multispectral image fusion 9 | % using particle swarm optimization," in Proc. Iranian Conf. Elec. Eng. 10 | % (ICEE), May 2017, pp. 1708-1712. 11 | 12 | % [2] S. Rahmani, M. Strait, D. Merkurjev, M. Moeller, and T. Wittman, 13 | % "An adaptive IHS Pan-sharpening method," IEEE Geosci. Remote Sens. 14 | % Lett., vol. 7, no. 4, pp. 746-750, Oct. 2010. 15 | 16 | %% Load images and pre-processing steps 17 | addpath QuickBird_Data 18 | load PAN; %% loading the MS image 19 | load MS; %% Loading the PAN image 20 | 21 | %% Make the PAN and MS data ready for the processing 22 | 23 | MSWV_db = double(MS); 24 | PANWV_db = double(PAN); 25 | MS_ORG = double(MS); 26 | 27 | %% Resizing, Upsampling the MS data to the size of PAN 28 | 29 | MSWV_US = imresize(MSWV_db, 1/4, 'bicubic'); 30 | MSWV_US = imresize(MSWV_US, 4, 'bicubic'); 31 | MS_OBJ = MSWV_US; 32 | PANWV_DS = imresize(PANWV_db, 1/4, 'bicubic'); 33 | PANWV_US = imresize(PANWV_DS, 4, 'bicubic'); 34 | 35 | %% Seperating the spectral bands 36 | 37 | R = MSWV_US(:,:,1); 38 | G = MSWV_US(:,:,2); 39 | B = MSWV_US(:,:,3); 40 | NIR = MSWV_US(:,:,4); 41 | 42 | %% Data Normialization 43 | 44 | for i=1:size(MSWV_US,3) 45 | bandCoeffs(i) = max(max(MSWV_US(:,:,i))); 46 | MSWV_US(:,:,i) = MSWV_US(:,:,i)/bandCoeffs(i); 47 | end 48 | 49 | P = PANWV_DS; 50 | panCoeff = max(max(P)); 51 | P = P/panCoeff; 52 | 53 | lamda = 10^-9; 54 | eps = 10^-10; 55 | 56 | % PAN weight in edge detector 57 | 58 | F_P = expEdge(P, lamda,eps); 59 | 60 | % MS weight in edge detector 61 | Red_W = max(max(R)); %% Red component 62 | R = R/Red_W; 63 | F_R = expEdge(R, lamda, eps); 64 | 65 | Green_W = max(max(G)); %% Green component 66 | G = G/Green_W; 67 | F_G = expEdge(G, lamda,eps); 68 | 69 | Blue_W = max(max(B)); %% Blue component 70 | B = B/Blue_W; 71 | F_B = expEdge(B, lamda,eps); 72 | 73 | NIR_W=max(max(NIR)); %% NIR component 74 | NIR=NIR/NIR_W; 75 | F_NIR = expEdge(NIR, lamda,eps); 76 | 77 | 78 | W = impGradDes(MSWV_US,P); 79 | 80 | I = W(1)*MSWV_US(:,:,1) + W(2)*MSWV_US(:,:,2) + W(3)*MSWV_US(:,:,3) + W(4)*MSWV_US(:,:,4); 81 | 82 | P = (P-mean(P(:)))*std(I(:))/std(P(:)) + mean(I(:)); 83 | 84 | F_PSO(:,:,1) = MSWV_US(:,:,1) + (x(1)*F_P+(1-x(1))*F_R).*(P-I); 85 | F_PSO(:,:,2) = MSWV_US(:,:,2) + (x(2)*F_P+(1-x(2))*F_G).*(P-I); 86 | F_PSO(:,:,3) = MSWV_US(:,:,3) + (x(3)*F_P+(1-x(3))*F_B).*(P-I); 87 | F_PSO(:,:,4) = MSWV_US(:,:,4) + (x(4)*F_P+(1-x(4))*F_NIR).*(P-I); 88 | 89 | 90 | for i=1:size(MS_ORG, 3) 91 | 92 | F_PSO(:,:,i)=F_PSO(:,:,i)*bandCoeffs(i); 93 | 94 | end 95 | 96 | ERGAS_ind = ERGAS(MS_OBJ, F_PSO, 4); 97 | 98 | end 99 | -------------------------------------------------------------------------------- /Main_PSO.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | clc; 3 | clear; 4 | close all; 5 | %% Description 6 | 7 | % This code provides the fuison results of PANchromatic (PAN) and MultiSpectral (MS) images 8 | % based on Particle Swarm Optimization (PSO) algorithm proposed in the following reference: 9 | 10 | % [1] A. Azarang and H. Ghassemian, "An adaptive multispectral image fusion 11 | % using particle swarm optimization," in Proc. Iranian Conf. Elec. Eng. 12 | % (ICEE), May 2017, pp. 1708-1712. 13 | 14 | % [2] S. Rahmani, M. Strait, D. Merkurjev, M. Moeller, and T. Wittman, 15 | % "An adaptive IHS Pan-sharpening method," IEEE Geosci. Remote Sens. 16 | % Lett., vol. 7, no. 4, pp. 746-750, Oct. 2010. 17 | 18 | % [3] Y. Leung, J. Liu, and J. Zhang, "An improved adaptive intensity-huesaturation 19 | % method for the fusion of remote sensing images," IEEE Geosci. 20 | % Remote Sens. Lett., vol. 11, no. 5, pp. 985-989, May 2014. 21 | %% The steps invovled in the proposed method is summerized as: 22 | 23 | % 1) Pre-processing the datasets, 24 | % 2) Estimating the primitive detail map, 25 | % 3) Extracting the primitive PAN and MS edge detectors, 26 | % 4) Optimizing the weights of edge detectors using the PSO algorithm 27 | % and ERGAS loss function to be applied on primitive detail map. 28 | 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | %% Loading the images and pre-processing steps 31 | addpath QuickBird_Data %% Dataset path 32 | load PAN; %% loading the MS image 33 | load MS; %% Loading the PAN image 34 | 35 | %% Make the PAN and MS data ready for the processing 36 | 37 | MSWV_db = double(MS); 38 | PANWV_db = double(PAN); 39 | MS_ORG = double(MS); 40 | 41 | %% Resizing, Upsampling the MS data to the size of PAN 42 | 43 | MSWV_US = imresize(MSWV_db, 1/4, 'bicubic'); 44 | MSWV_US = imresize(MSWV_US, 4, 'bicubic'); 45 | MSWV_DG = MSWV_US; 46 | PANWV_DS = imresize(PANWV_db, 1/4, 'bicubic'); 47 | PANWV_US = imresize(PANWV_DS, 4, 'bicubic'); 48 | 49 | %% Seperating the spectral bands 50 | 51 | R = MSWV_US(:,:,1); 52 | G = MSWV_US(:,:,2); 53 | B = MSWV_US(:,:,3); 54 | NIR = MSWV_US(:,:,4); 55 | 56 | %% Data Normialization 57 | 58 | for i=1:size(MSWV_US,3) 59 | bandCoeffs(i) = max(max(MSWV_US(:,:,i))); 60 | MSWV_US(:,:,i) = MSWV_US(:,:,i)/bandCoeffs(i); 61 | end 62 | 63 | P = PANWV_DS; 64 | panCoeff = max(max(P)); 65 | P = P/panCoeff; 66 | 67 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 68 | %% Problem Definition 69 | CostFunction=@(x) ERGAS_Index(x); % Cost Function 70 | 71 | nVar = 4; % Number of Decision Variables 72 | 73 | VarSize = [1 nVar]; % Size of Decision Variables Matrix 74 | 75 | VarMin = 0; % Lower Bound of Variables 76 | VarMax = 1; % Upper Bound of Variables 77 | 78 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 79 | %% PSO Parameters 80 | 81 | MaxIt = 25; % Maximum Number of Iterations 82 | 83 | nPop = 10; % Population Size (Swarm Size) 84 | 85 | % PSO Parameters 86 | % w=0.9; % Inertia Weight 87 | % wdamp=0.9958; % Inertia Weight Damping Ratio 88 | % c1=2.0; % Personal Learning Coefficient 89 | % c2=2.0; % Global Learning Coefficient 90 | 91 | % If you would like to use Constriction Coefficients for PSO, 92 | % uncomment the following block and comment the above set of parameters. 93 | 94 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 95 | %% Constriction Coefficients 96 | phi1 = 2.05; 97 | phi2 = 2.05; 98 | phi = phi1+phi2; 99 | chi = 2/(phi-2+sqrt(phi^2-4*phi)); 100 | w = chi; % Inertia Weight 101 | wdamp = 1; % Inertia Weight Damping Ratio 102 | c1 = chi*phi1; % Personal Learning Coefficient 103 | c2 = chi*phi2; % Global Learning Coefficient 104 | 105 | % Velocity Limits 106 | 107 | VelMax = 0.1*(VarMax-VarMin); 108 | VelMin = -VelMax; 109 | 110 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 111 | %% Initialization 112 | 113 | empty_particle.Position = []; 114 | empty_particle.Cost = []; 115 | empty_particle.Velocity = []; 116 | empty_particle.Best.Position = []; 117 | empty_particle.Best.Cost = []; 118 | 119 | particle = repmat(empty_particle,nPop,1); 120 | 121 | GlobalBest.Cost = 0; 122 | 123 | for i = 1:nPop 124 | 125 | % Initialize Position 126 | particle(i).Position = unifrnd(VarMin,VarMax,VarSize); 127 | 128 | % Initialize Velocity 129 | particle(i).Velocity = zeros(VarSize); 130 | 131 | % Evaluation 132 | particle(i).Cost = CostFunction(particle(i).Position); 133 | 134 | % Update Personal Best 135 | particle(i).Best.Position = particle(i).Position; 136 | particle(i).Best.Cost = particle(i).Cost; 137 | 138 | % Update Global Best 139 | if particle(i).Best.Cost > GlobalBest.Cost 140 | 141 | GlobalBest = particle(i).Best; 142 | 143 | end 144 | 145 | end 146 | 147 | BestCost = zeros(MaxIt,1); 148 | 149 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 150 | %% PSO Main Loop 151 | 152 | for it = 1:MaxIt 153 | % figure 154 | for i=1:nPop 155 | 156 | % Update Velocity 157 | particle(i).Velocity = w*particle(i).Velocity ... 158 | +c1*rand(VarSize).*(particle(i).Best.Position-particle(i).Position) ... 159 | +c2*rand(VarSize).*(GlobalBest.Position-particle(i).Position); 160 | 161 | % Apply Velocity Limits 162 | particle(i).Velocity = max(particle(i).Velocity,VelMin); 163 | particle(i).Velocity = min(particle(i).Velocity,VelMax); 164 | 165 | % Update Position 166 | particle(i).Position = particle(i).Position + particle(i).Velocity; 167 | 168 | % Velocity Mirror Effect 169 | IsOutside=(particle(i).PositionVarMax); 170 | particle(i).Velocity(IsOutside)=-particle(i).Velocity(IsOutside); 171 | 172 | % Apply Position Limits 173 | particle(i).Position = max(particle(i).Position,VarMin); 174 | particle(i).Position = min(particle(i).Position,VarMax); 175 | 176 | %% Plot Nodes 177 | % plot(particle(i).Position,'*r','MarkerSize',8) 178 | % axis tight 179 | % hold on 180 | % grid on 181 | % Evaluation 182 | particle(i).Cost = CostFunction(particle(i).Position); 183 | 184 | % Update Personal Best 185 | if particle(i).Cost 3) 78 | quality = -Inf; 79 | quality_map = -1*ones(size(img1)); 80 | return; 81 | end 82 | 83 | if (size(img1) ~= size(img2)) 84 | quality = -Inf; 85 | quality_map = -1*ones(size(img1)); 86 | return; 87 | end 88 | 89 | if (nargin == 2) 90 | block_size = 8; 91 | end 92 | 93 | N = block_size.^2; 94 | sum2_filter = ones(block_size); 95 | 96 | img1_sq = img1.*img1; 97 | img2_sq = img2.*img2; 98 | img12 = img1.*img2; 99 | 100 | img1_sum = filter2(sum2_filter, img1, 'valid'); 101 | img2_sum = filter2(sum2_filter, img2, 'valid'); 102 | img1_sq_sum = filter2(sum2_filter, img1_sq, 'valid'); 103 | img2_sq_sum = filter2(sum2_filter, img2_sq, 'valid'); 104 | img12_sum = filter2(sum2_filter, img12, 'valid'); 105 | 106 | img12_sum_mul = img1_sum.*img2_sum; 107 | img12_sq_sum_mul = img1_sum.*img1_sum + img2_sum.*img2_sum; 108 | numerator = 4*(N*img12_sum - img12_sum_mul).*img12_sum_mul; 109 | denominator1 = N*(img1_sq_sum + img2_sq_sum) - img12_sq_sum_mul; 110 | denominator = denominator1.*img12_sq_sum_mul; 111 | 112 | quality_map = ones(size(denominator)); 113 | index = (denominator1 == 0) & (img12_sq_sum_mul ~= 0); 114 | quality_map(index) = 2*img12_sum_mul(index)./img12_sq_sum_mul(index); 115 | index = (denominator ~= 0); 116 | quality_map(index) = numerator(index)./denominator(index); 117 | 118 | quality = mean2(quality_map); -------------------------------------------------------------------------------- /Objective_Evaluation/norm_blocco.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%% Q2n aux. function 2 | function [y,a,c] = norm_blocco(x) 3 | 4 | a=mean2(x); 5 | c=std2(x); 6 | 7 | if(c==0) 8 | c = eps; 9 | end 10 | 11 | y=((x-a)/c)+1; 12 | 13 | end -------------------------------------------------------------------------------- /Objective_Evaluation/odd_extension.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%% Q2n aux. function 2 | function ext = odd_extension(A,winx,winy) 3 | 4 | if errargn(mfilename,nargin,3,nargout,1), error('*'), end 5 | if errargt(mfilename,winx,'in0'), error('*'), end 6 | if errargt(mfilename,winy,'in0'), error('*'), end 7 | if (rem(winx,2) ~= 1 || rem(winy,2) ~= 1) 8 | disp(' ') 9 | disp('Errore: le dimensioni delle finestre devono essere entrambe dispari'); 10 | disp(' ') 11 | return 12 | end 13 | 14 | [dimy,dimx] = size(A); 15 | wx = (winx-1)/2; 16 | wy = (winy-1)/2; 17 | ext = zeros(dimy+winy-1,dimx+winx-1); 18 | ext(wy+1:wy+dimy,wx+1:wx+dimx) = A; 19 | 20 | for k = 1:wy 21 | ext(wy-k+1,wx+1:wx+dimx) = A(k+1,:); 22 | ext(wy+dimy+k,wx+1:wx+dimx) = A(dimy-k,:); 23 | end 24 | for k = 1:wx 25 | ext(:,wx-k+1) = ext(:,wx+k+1); 26 | ext(:,wx+dimx+k) = ext(:,dimx+wx-k); 27 | end 28 | 29 | end 30 | 31 | -------------------------------------------------------------------------------- /Objective_Evaluation/onion_mult.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%% Q2n aux. function 2 | function ris=onion_mult(onion1,onion2) 3 | 4 | N=length(onion1); 5 | 6 | if N>1 7 | 8 | L=N/2; 9 | 10 | a=onion1(1:L); 11 | b=onion1(L+1:end); 12 | b=[b(1),-b(2:end)]; 13 | c=onion2(1:L); 14 | d=onion2(L+1:end); 15 | d=[d(1),-d(2:end)]; 16 | 17 | 18 | if N==2 19 | ris=[a*c-d*b,a*d+c*b]; 20 | else 21 | ris1=onion_mult(a,c); 22 | ris2=onion_mult(d,[b(1),-b(2:end)]); %% 23 | ris3=onion_mult([a(1),-a(2:end)],d); %% 24 | ris4=onion_mult(c,b); 25 | 26 | aux1=ris1-ris2; 27 | aux2=ris3+ris4; 28 | 29 | ris=[aux1,aux2]; 30 | end 31 | 32 | else 33 | ris = onion1*onion2; 34 | end 35 | 36 | end -------------------------------------------------------------------------------- /Objective_Evaluation/onion_mult2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%% Q2n aux. function 2 | function ris = onion_mult2D(onion1,onion2) 3 | 4 | [~,~,N3]=size(onion1); 5 | 6 | if N3>1 7 | 8 | L=N3/2; 9 | 10 | a=onion1(:,:,1:L); 11 | b=onion1(:,:,L+1:end); 12 | b=cat(3,b(:,:,1),-b(:,:,2:end)); 13 | c=onion2(:,:,1:L); 14 | d=onion2(:,:,L+1:end); 15 | d=cat(3,d(:,:,1),-d(:,:,2:end)); 16 | 17 | 18 | if N3==2 19 | ris=cat(3,a.*c-d.*b,a.*d+c.*b); 20 | else 21 | ris1=onion_mult2D(a,c); 22 | ris2=onion_mult2D(d,cat(3,b(:,:,1),-b(:,:,2:end))); 23 | ris3=onion_mult2D(cat(3,a(:,:,1),-a(:,:,2:end)),d); 24 | ris4=onion_mult2D(c,b); 25 | 26 | aux1=ris1-ris2; 27 | aux2=ris3+ris4; 28 | 29 | ris=cat(3,aux1,aux2); 30 | end 31 | 32 | else 33 | ris = onion1.*onion2; 34 | end 35 | 36 | end -------------------------------------------------------------------------------- /Objective_Evaluation/onions_quality.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%% Q2n aux. function 2 | function q = onions_quality(dat1,dat2,size1) 3 | 4 | dat1=double(dat1); 5 | dat2=double(dat2); 6 | dat2=cat(3,dat2(:,:,1),-dat2(:,:,2:end)); 7 | [~,~,N3]=size(dat1); 8 | size2=size1; 9 | 10 | % Block normalization 11 | for i=1:N3 12 | [a1,s,t]=norm_blocco(squeeze(dat1(:,:,i))); 13 | dat1(:,:,i)=a1; 14 | clear a1 15 | if s==0 16 | if i==1 17 | dat2(:,:,i)=dat2(:,:,i)-s+1; 18 | else 19 | dat2(:,:,i)=-(-dat2(:,:,i)-s+1); 20 | end 21 | else 22 | if i==1 23 | dat2(:,:,i)=((dat2(:,:,i)-s)/t)+1; 24 | else 25 | dat2(:,:,i)=-(((-dat2(:,:,i)-s)/t)+1); 26 | end 27 | end 28 | end 29 | 30 | m1=zeros(1,N3); 31 | m2=zeros(1,N3); 32 | 33 | mod_q1m=0; 34 | mod_q2m=0; 35 | mod_q1=zeros(size1,size2); 36 | mod_q2=zeros(size1,size2); 37 | 38 | for i=1:N3 39 | m1(i)=mean2(squeeze(dat1(:,:,i))); 40 | m2(i)=mean2(squeeze(dat2(:,:,i))); 41 | mod_q1m=mod_q1m+(m1(i)^2); 42 | mod_q2m=mod_q2m+(m2(i)^2); 43 | mod_q1=mod_q1+((squeeze(dat1(:,:,i))).^2); 44 | mod_q2=mod_q2+((squeeze(dat2(:,:,i))).^2); 45 | end 46 | 47 | mod_q1m=sqrt(mod_q1m); 48 | mod_q2m=sqrt(mod_q2m); 49 | mod_q1=sqrt(mod_q1); 50 | mod_q2=sqrt(mod_q2); 51 | 52 | termine2 = (mod_q1m*mod_q2m); 53 | termine4 = ((mod_q1m^2)+(mod_q2m^2)); 54 | int1=(size1*size2)/((size1*size2)-1)*mean2(mod_q1.^2); 55 | int2=(size1*size2)/((size1*size2)-1)*mean2(mod_q2.^2); 56 | termine3=int1+int2-(size1*size2)/((size1*size2)-1)*((mod_q1m^2)+(mod_q2m^2)); 57 | 58 | mean_bias=2*termine2/termine4; 59 | if termine3==0 60 | q=zeros(1,1,N3); 61 | q(:,:,N3)=mean_bias; 62 | else 63 | cbm=2/termine3; 64 | qu=onion_mult2D(dat1,dat2); 65 | qm=onion_mult(m1,m2); 66 | qv=zeros(1,N3); 67 | for i=1:N3 68 | qv(i)=(size1*size2)/((size1*size2)-1)*mean2(squeeze(qu(:,:,i))); 69 | end 70 | q=qv-(size1*size2)/((size1*size2)-1)*qm; 71 | q=q*mean_bias*cbm; 72 | end 73 | 74 | end -------------------------------------------------------------------------------- /Objective_Evaluation/q2n.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArianAzg/Image-Fusion-with-PSO-Algorithm/cae732d40d2a5ea972402687345e31285baa07a5/Objective_Evaluation/q2n.m -------------------------------------------------------------------------------- /Objective_Evaluation/ssim.m: -------------------------------------------------------------------------------- 1 | function [mssim, ssim_map] = ssim(img1, img2, K, window, L) 2 | 3 | % ======================================================================== 4 | % SSIM Index with automatic downsampling, Version 1.0 5 | % Copyright(c) 2009 Zhou Wang 6 | % All Rights Reserved. 7 | % 8 | % ---------------------------------------------------------------------- 9 | % Permission to use, copy, or modify this software and its documentation 10 | % for educational and research purposes only and without fee is hereby 11 | % granted, provided that this copyright notice and the original authors' 12 | % names appear on all copies and supporting documentation. This program 13 | % shall not be used, rewritten, or adapted as the basis of a commercial 14 | % software or hardware product without first obtaining permission of the 15 | % authors. The authors make no representations about the suitability of 16 | % this software for any purpose. It is provided "as is" without express 17 | % or implied warranty. 18 | %---------------------------------------------------------------------- 19 | % 20 | % This is an implementation of the algorithm for calculating the 21 | % Structural SIMilarity (SSIM) index between two images 22 | % 23 | % Please refer to the following paper and the website with suggested usage 24 | % 25 | % Z. Wang, A. C. Bovik, H. R. Sheikh, and E. P. Simoncelli, "Image 26 | % quality assessment: From error visibility to structural similarity," 27 | % IEEE Transactios on Image Processing, vol. 13, no. 4, pp. 600-612, 28 | % Apr. 2004. 29 | % 30 | % http://www.ece.uwaterloo.ca/~z70wang/research/ssim/ 31 | % 32 | % Note: This program is different from ssim_index.m, where no automatic 33 | % downsampling is performed. (downsampling was done in the above paper 34 | % and was described as suggested usage in the above website.) 35 | % 36 | % Kindly report any suggestions or corrections to zhouwang@ieee.org 37 | % 38 | %---------------------------------------------------------------------- 39 | % 40 | %Input : (1) img1: the first image being compared 41 | % (2) img2: the second image being compared 42 | % (3) K: constants in the SSIM index formula (see the above 43 | % reference). defualt value: K = [0.01 0.03] 44 | % (4) window: local window for statistics (see the above 45 | % reference). default widnow is Gaussian given by 46 | % window = fspecial('gaussian', 11, 1.5); 47 | % (5) L: dynamic range of the images. default: L = 255 48 | % 49 | %Output: (1) mssim: the mean SSIM index value between 2 images. 50 | % If one of the images being compared is regarded as 51 | % perfect quality, then mssim can be considered as the 52 | % quality measure of the other image. 53 | % If img1 = img2, then mssim = 1. 54 | % (2) ssim_map: the SSIM index map of the test image. The map 55 | % has a smaller size than the input images. The actual size 56 | % depends on the window size and the downsampling factor. 57 | % 58 | %Basic Usage: 59 | % Given 2 test images img1 and img2, whose dynamic range is 0-255 60 | % 61 | % [mssim, ssim_map] = ssim(img1, img2); 62 | % 63 | %Advanced Usage: 64 | % User defined parameters. For example 65 | % 66 | % K = [0.05 0.05]; 67 | % window = ones(8); 68 | % L = 100; 69 | % [mssim, ssim_map] = ssim(img1, img2, K, window, L); 70 | % 71 | %Visualize the results: 72 | % 73 | % mssim %Gives the mssim value 74 | % imshow(max(0, ssim_map).^4) %Shows the SSIM index map 75 | %======================================================================== 76 | 77 | 78 | if (nargin < 2 || nargin > 5) 79 | mssim = -Inf; 80 | ssim_map = -Inf; 81 | return; 82 | end 83 | 84 | if (size(img1) ~= size(img2)) 85 | mssim = -Inf; 86 | ssim_map = -Inf; 87 | return; 88 | end 89 | 90 | [M N] = size(img1); 91 | 92 | if (nargin == 2) 93 | if ((M < 11) || (N < 11)) 94 | mssim = -Inf; 95 | ssim_map = -Inf; 96 | return 97 | end 98 | window = fspecial('gaussian', 11, 1.5); % 99 | K(1) = 0.01; % default settings 100 | K(2) = 0.03; % 101 | L = 255; % 102 | end 103 | 104 | if (nargin == 3) 105 | if ((M < 11) || (N < 11)) 106 | mssim = -Inf; 107 | ssim_map = -Inf; 108 | return 109 | end 110 | window = fspecial('gaussian', 11, 1.5); 111 | L = 255; 112 | if (length(K) == 2) 113 | if (K(1) < 0 || K(2) < 0) 114 | mssim = -Inf; 115 | ssim_map = -Inf; 116 | return; 117 | end 118 | else 119 | mssim = -Inf; 120 | ssim_map = -Inf; 121 | return; 122 | end 123 | end 124 | 125 | if (nargin == 4) 126 | [H W] = size(window); 127 | if ((H*W) < 4 || (H > M) || (W > N)) 128 | mssim = -Inf; 129 | ssim_map = -Inf; 130 | return 131 | end 132 | L = 255; 133 | if (length(K) == 2) 134 | if (K(1) < 0 || K(2) < 0) 135 | mssim = -Inf; 136 | ssim_map = -Inf; 137 | return; 138 | end 139 | else 140 | mssim = -Inf; 141 | ssim_map = -Inf; 142 | return; 143 | end 144 | end 145 | 146 | if (nargin == 5) 147 | [H W] = size(window); 148 | if ((H*W) < 4 || (H > M) || (W > N)) 149 | mssim = -Inf; 150 | ssim_map = -Inf; 151 | return 152 | end 153 | if (length(K) == 2) 154 | if (K(1) < 0 || K(2) < 0) 155 | mssim = -Inf; 156 | ssim_map = -Inf; 157 | return; 158 | end 159 | else 160 | mssim = -Inf; 161 | ssim_map = -Inf; 162 | return; 163 | end 164 | end 165 | 166 | 167 | img1 = double(img1); 168 | img2 = double(img2); 169 | 170 | % automatic downsampling 171 | f = max(1,round(min(M,N)/256)); 172 | %downsampling by f 173 | %use a simple low-pass filter 174 | if(f>1) 175 | lpf = ones(f,f); 176 | lpf = lpf/sum(lpf(:)); 177 | img1 = imfilter(img1,lpf,'symmetric','same'); 178 | img2 = imfilter(img2,lpf,'symmetric','same'); 179 | 180 | img1 = img1(1:f:end,1:f:end); 181 | img2 = img2(1:f:end,1:f:end); 182 | end 183 | 184 | C1 = (K(1)*L)^2; 185 | C2 = (K(2)*L)^2; 186 | window = window/sum(sum(window)); 187 | 188 | mu1 = filter2(window, img1, 'valid'); 189 | mu2 = filter2(window, img2, 'valid'); 190 | mu1_sq = mu1.*mu1; 191 | mu2_sq = mu2.*mu2; 192 | mu1_mu2 = mu1.*mu2; 193 | sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq; 194 | sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq; 195 | sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2; 196 | 197 | if (C1 > 0 && C2 > 0) 198 | ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2)); 199 | else 200 | numerator1 = 2*mu1_mu2 + C1; 201 | numerator2 = 2*sigma12 + C2; 202 | denominator1 = mu1_sq + mu2_sq + C1; 203 | denominator2 = sigma1_sq + sigma2_sq + C2; 204 | ssim_map = ones(size(mu1)); 205 | index = (denominator1.*denominator2 > 0); 206 | ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index)); 207 | index = (denominator1 ~= 0) & (denominator2 == 0); 208 | ssim_map(index) = numerator1(index)./denominator1(index); 209 | end 210 | 211 | mssim = mean2(ssim_map); 212 | 213 | return -------------------------------------------------------------------------------- /Objective_Evaluation/uqi.m: -------------------------------------------------------------------------------- 1 | function Q = uqi(x,y) 2 | x = double(x(:)); 3 | y = double(y(:)); 4 | mx = mean(x); 5 | my = mean(y); 6 | C = cov(x,y); 7 | Q = (4*C(1,2)*(mx)*(my))/((C(1,1)+C(2,2))*((mx)^2+(my)^2)); 8 | end -------------------------------------------------------------------------------- /QuickBird_Data/MS.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArianAzg/Image-Fusion-with-PSO-Algorithm/cae732d40d2a5ea972402687345e31285baa07a5/QuickBird_Data/MS.mat -------------------------------------------------------------------------------- /QuickBird_Data/PAN.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArianAzg/Image-Fusion-with-PSO-Algorithm/cae732d40d2a5ea972402687345e31285baa07a5/QuickBird_Data/PAN.mat -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multispectral Image Fusion with PSO Algorithm 2 | 3 | [An adaptive multispectral image fusion using particle swarm optimization 4 | ](https://ieeexplore.ieee.org/abstract/document/7985325) is the paper for this MATLAB code. 5 | 6 | 7 | Description 8 | ---------- 9 | This code provides the fusion of PANchromatic (PAN) and MultiSpectral (MS) images using the Particle Swarm Optimization (PSO) algorithm. The steps for fusion is as follows: 10 | 11 | 1) Loading the dataset from its path 12 | 13 | 2) Pre-processing steps including downsampling and normalization 14 | 15 | 3) Initialization of PSO algorithm 16 | 17 | 4) Obtaining the primitive detail map for each spectral band 18 | 19 | 5) Extracting the edge detectors for PAN and MS images 20 | 21 | 6) Fine-tuning the gains of edge detectors using PSO algorithm 22 | 23 | 24 | 25 | Loss Function 26 | -------------- 27 | For the purpose of optimizing the gains of edge detectors, the ERGAS metric is minimized. This metric is one of the widely used metrics for the objective evaluation of fusion results. 28 | 29 | Usage 30 | ------------ 31 | First you need to specify the path of your dataset. 32 | For example: 33 | 34 | addpath QuickBird_Data 35 | The Main_PSO.m is the main framework of the proposed fusion framework. The _**pre-processing**_ steps as well as the obtaining _**fusion outcome**_ is put into this M-file. The ERGAS_Index.m and ERGAS.m files are used for the purpose of optimization. The optimized gains of _**edge detectors**_ are computed as the output of of PSO algorithm. 36 | 37 | To _run_ the code, in the _command window_ use this: 38 | 39 | Main_PSO.m 40 | 41 | Objective Evaluation 42 | ---------- 43 | For objective assessment of the fusion result, first add the path of objective metric. For example: 44 | 45 | addpath Objective_Evaluation 46 | 47 | Sample Output 48 | ----------- 49 | 50 | The MS, PAN and pansharpened result of the QuickBird dataset from Sandarbans, Bangladesh. 51 | 52 | ![LRMS](https://user-images.githubusercontent.com/48659018/56171542-5284ec00-5fab-11e9-93fb-a973ba1e8014.png) 53 | ![PAN](https://user-images.githubusercontent.com/48659018/56171559-603a7180-5fab-11e9-8626-c1103ca22e6d.png) 54 | ![Pansharpened](https://user-images.githubusercontent.com/48659018/56171570-6892ac80-5fab-11e9-86be-8f86e797e974.png) 55 | 56 | Reference 57 | -------- 58 | If you find this code helpful, please cite this paper: 59 | 60 | A. Azarang and H. Ghassemian, "An adaptive multispectral image fusion using particle swarm optimization," in Proc. Iranian Conf. Elec. Eng. (ICEE), May 2017, pp. 1708-1712. 61 | 62 | Contact 63 | -------- 64 | If you have any question regarding the paper, codes and so on, do not hesitate to contact me. 65 | 66 | Arian Azarang azarang@utdallas.edu 67 | -------------------------------------------------------------------------------- /expEdge.m: -------------------------------------------------------------------------------- 1 | function [F]= expEdge(Pan, lamda,eps) 2 | [FX,FY] = gradient(Pan); 3 | u=((FX.*FX)+(FY.*FY)).^(1/2); 4 | %a = max(max(abs(u))) 5 | [m,n]=size(u); 6 | F= exp( -((lamda*(ones(m,n)))./((abs(u).*abs(u).*abs(u).*abs(u))+ eps))); -------------------------------------------------------------------------------- /impGradDes.m: -------------------------------------------------------------------------------- 1 | %% This code is used to estimate the weights of the MultiSpectral (MS) bands based on Adaptive IHS (AIHS) method. 2 | %% References 3 | % [1] S. Rahmani, M. Strait, D. Merkurjev, M. Moeller, and T. Wittman, 4 | % "An adaptive IHS pan-sharpening method," IEEE Geoscience and Remote Sensing Letters 7, no. 4, 746-750, 2010. 5 | % [2] A. Azarang, H. E. Manoochehri and N. Kehtarnavaz, 6 | % "Convolutional Autoencoder-Based Multispectral Image Fusion," in IEEE Access, vol. 7, pp. 35673-35683, 2019. 7 | %% This code need two inputs: 8 | % M - Low Resolution MS (LRMS) image to size of PANchromatic (PAN) image 9 | % P - Original PAN image 10 | %% In the outputs you can find the estimated weight for each MS band 11 | % findalph - Spectral weights 12 | 13 | 14 | function findalph = impGradDes(M, P) 15 | 16 | [n, m, d] = size(M); 17 | 18 | %% Initializing the optimal weight vector 19 | 20 | findalph = ones(d,1); 21 | %% Optimization process 22 | for i=1:d 23 | for j=1:d 24 | A(i,j) = sum(sum(M(:,:,i).*M(:,:,j))); 25 | end 26 | B(i,1) = sum(sum(P.*M(:,:,i))); 27 | end 28 | 29 | tau = 5; 30 | iter = 150000; 31 | gamma1 = 1/200000; 32 | gamma2 = 1; 33 | 34 | inv = (eye(d) + 2*tau*gamma1*A)^(-1); 35 | 36 | for i = 1:iter 37 | findalph = inv * (findalph+2*tau*max(-findalph,0)+2*tau*gamma1*B); 38 | end 39 | %% EOF --------------------------------------------------------------------------------