├── EvalFusion.m ├── LICENSE ├── README.md ├── boxfilter.m ├── evaluation ├── metricChenBlum.m ├── metricXydeas.m ├── metricYang.m ├── metricZhao.m ├── myphasecong3.m └── using_FMI.m ├── figure └── gfdf.png ├── guidedfilter_LKH.m ├── images ├── 01clock1.bmp ├── 01clock2.bmp ├── 02lab1.bmp ├── 02lab2.bmp ├── 03desk1.bmp ├── 03desk2.bmp ├── 04pepsi1.bmp ├── 04pepsi2.bmp ├── 06book1.bmp ├── 06book2.bmp ├── lytro-01-A.jpg ├── lytro-01-B.jpg ├── lytro-03-A.jpg ├── lytro-03-B.jpg ├── lytro-05-A.jpg ├── lytro-05-B.jpg ├── toy1.bmp ├── toy2.bmp └── toy3.bmp └── main.m /EvalFusion.m: -------------------------------------------------------------------------------- 1 | function mValues=EvalFusion(A,B,F) 2 | if size(A,3)>1 3 | A=rgb2gray(A); 4 | B=rgb2gray(B); 5 | F=rgb2gray(F); 6 | end 7 | QG = metricXydeas(A,B,F);% Xydeas,2000 8 | QP = metricZhao(A,B,F);% ZhaoJiying,2007 9 | QY = metricYang(A,B,F);% YangCui,2008 10 | QCB = metricChenBlum(A,B,F);% ChenYin,2009 11 | QFMI = using_FMI(A,B,F,'gradient');% Haghighat,2014 12 | mValues = table(QG,QP,QY,QCB,QFMI); 13 | disp(['|QG=',num2str(QG,'%0.4f'), '|QP=',num2str(QP,'%0.4f')... 14 | '|QY=',num2str(QY,'%0.4f'),'|QCB=',num2str(QCB,'%0.4f'),'|QFMI=',num2str(QFMI,'%0.4f'),'|']) 15 | end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GFDF: Multi-Focus Images Fusion 2 | Multi-focus images fusion using Guided Filter and mean filter. This is the MATLAB code for "[Guided filter-based multi-focus image fusion through focus region detection](http://www.sciencedirect.com/science/article/pii/S0923596518302832)" in Signal Processing: Image Communication (SPIC) 2019. 3 | 4 | ## Fusion Architecture 5 | 6 | ![GFDF Fusion Architecture](/figure/gfdf.png) 7 | 8 | ## Citation 9 | If you use this code for your research, please cite our papers. 10 | ``` 11 | @article{QIU201935, 12 | title={Guided filter-based multi-focus image fusion through focus region detection}, 13 | author={Xiaohua Qiu,Min Li,Liqiong Zhang,Xianjie Yuan}, 14 | journal={Signal Processing: Image Communication}, 15 | year={2019}, 16 | publisher={Elsevier} 17 | } 18 | ``` 19 | ## Contact 20 | If you have any questions, please feel free to contact me. 21 | Xiaohua Qiu (qxh_1025@163.com) 22 | -------------------------------------------------------------------------------- /boxfilter.m: -------------------------------------------------------------------------------- 1 | function imDst = boxfilter(imSrc, r) 2 | 3 | %?? BOXFILTER?? O(1) time box filtering using cumulative sum 4 | % 5 | %?? - Definition imDst(x, y)=sum(sum(imSrc(x-r:x+r,y-r:y+r))); 6 | %?? - Running time independent of r; 7 | %?? - Equivalent to the function: colfilt(imSrc, [2*r+1, 2*r+1], 'sliding', @sum); 8 | %?? - But much faster. 9 | 10 | [hei, wid] = size(imSrc); 11 | imDst = zeros(size(imSrc)); 12 | 13 | %cumulative sum over Y axis 14 | imCum = cumsum(imSrc, 1); 15 | %difference over Y axis 16 | imDst(1:r+1, :) = imCum(1+r:2*r+1, :); 17 | imDst(r+2:hei-r, :) = imCum(2*r+2:hei, :) - imCum(1:hei-2*r-1, :); 18 | imDst(hei-r+1:hei, :) = repmat(imCum(hei, :), [r, 1]) - imCum(hei-2*r:hei-r-1, :); 19 | 20 | %cumulative sum over X axis 21 | imCum = cumsum(imDst, 2); 22 | %difference over Y axis 23 | imDst(:, 1:r+1) = imCum(:, 1+r:2*r+1); 24 | imDst(:, r+2:wid-r) = imCum(:, 2*r+2:wid) - imCum(:, 1:wid-2*r-1); 25 | imDst(:, wid-r+1:wid) = repmat(imCum(:, wid), [1, r]) - imCum(:, wid-2*r:wid-r-1); 26 | end -------------------------------------------------------------------------------- /evaluation/metricChenBlum.m: -------------------------------------------------------------------------------- 1 | function res=metricChenBlum(im1,im2,fim) 2 | 3 | % function res=metricChenBlum(im1,im2,fim) 4 | % 5 | % This function implements Yin Chen's algorithm for fusion metric. 6 | % im1, im2 -- input images; 7 | % fim -- fused image; 8 | % res -- metric value; 9 | % 10 | % IMPORTANT: The size of the images need to be 2X. 11 | % See also: evalu_fusion.m 12 | % 13 | % Z. Liu [July 2009] 14 | % 15 | 16 | % Ref: A new automated quality assessment algorithm for image fusion, Image and Vision Computing, 27 (2009) 1421-1432 17 | % By Yin Chen et al. 18 | % 19 | 20 | %% pre-processing 21 | %im1=double(im1); 22 | %im2=double(im2); 23 | %fim=double(fim); 24 | 25 | im1 = im2double(im1); 26 | im2 = im2double(im2); 27 | fim = im2double(fim); 28 | 29 | im1=normalize1(im1); 30 | im2=normalize1(im2); 31 | fim=normalize1(fim); 32 | 33 | 34 | %% set up some constant values for experiment 35 | 36 | f0=15.3870; 37 | f1=1.3456; 38 | a=0.7622; 39 | 40 | % parameters for local constrast computation 41 | k=1; 42 | h=1; 43 | p=3; %2.4; 44 | %p=2.4; 45 | q=2; 46 | Z=0.0001; 47 | sigma=2; 48 | %% caculate the quality Q 49 | 50 | [hang,lie]=size(im1); 51 | 52 | %DoG filter 53 | %DoG1 54 | %HH=hang/2; LL=lie/2; 55 | HH=hang/30; LL=lie/30; 56 | 57 | %DoG2 58 | %HH=hang/4; LL=lie/4; 59 | 60 | %DoG3 61 | %HH=hang/8; LL=lie/8; 62 | 63 | [u,v]=freqspace([hang,lie],'meshgrid'); 64 | u=LL*u; v=HH*v; 65 | r=sqrt(u.^2+v.^2); 66 | 67 | Sd=exp(-(r/f0).^2)-a*exp(-(r/f1).^2); 68 | 69 | % constrast sensitivity filtering 70 | fim1=ifft2(ifftshift(fftshift(fft2(im1)).*Sd)); 71 | fim2=ifft2(ifftshift(fftshift(fft2(im2)).*Sd)); 72 | ffim=ifft2(ifftshift(fftshift(fft2(fim)).*Sd)); 73 | 74 | %-------------------- 75 | %fim1=normalize1(fim1); 76 | %fim2=normalize1(fim2); 77 | %ffim=normalize1(ffim); 78 | 79 | % local contrast computation 80 | % one level of contrast 81 | G1=gaussian2d(hang,lie,2); 82 | G2=gaussian2d(hang,lie,4); 83 | 84 | 85 | % filtering in frequency domain 86 | C1=contrast(G1,G2,fim1); 87 | C1=abs(C1); % I add this. (see your notes) 88 | C1P=(k*(C1.^p))./(h*(C1.^q)+Z); 89 | 90 | C2=contrast(G1,G2,fim2); 91 | C2=abs(C2); % I add this. 92 | C2P=(k*(C2.^p))./(h*(C2.^q)+Z); 93 | 94 | Cf=contrast(G1,G2,ffim); 95 | Cf=abs(Cf); % I add this. 96 | CfP=(k*(Cf.^p))./(h*(Cf.^q)+Z); 97 | 98 | % contrast preservation calculation 99 | mask=(C1P y; lie (L) -> x 130 | 131 | H=floor((n1-1)/2); 132 | L=floor((n2-1)/2); 133 | 134 | 135 | [x,y]=meshgrid(-15:15,-15:15); 136 | G=exp(-(x.*x+y.*y)/(2*sigma*sigma))/(2*pi*sigma*sigma); 137 | 138 | %This is to normalize 139 | %G=G/sum(G(:)); 140 | res=G; 141 | 142 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 143 | function res=contrast(G1,G2,im) 144 | 145 | %[hang,lie]=size(im); 146 | 147 | %FG1=fft2(G1,hang,lie); 148 | %FG2=fft2(G2,hang,lie); 149 | %Fim=fft2(im); 150 | 151 | %buff=real(ifft2(FG1.*Fim)); 152 | %buff1=real(ifft2(FG2.*Fim)); 153 | 154 | buff=filter2(G1,im,'same'); 155 | buff1=filter2(G2,im,'same'); 156 | 157 | res=buff./buff1-1; 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /evaluation/metricXydeas.m: -------------------------------------------------------------------------------- 1 | function res=metricXydeas(img1,img2,fuse) 2 | 3 | % function res=metricXydeas(img1,img2,fuse) 4 | % 5 | % This function is used to evaluate the fusion algorithm. 6 | % im1, im2 -- input images; 7 | % fim -- fused image; 8 | % res -- metric value; 9 | % 10 | % Z. Liu @NRCC [3 Oct 2003] 11 | % 12 | 13 | % Ref: Objective Pixel-level Image Fusion Performance Measure, Proc. SPIE 4051, 89 (2000) 14 | % by C. Xydeas 15 | % 16 | 17 | 18 | flt1=[-1 0 1 ; -2 0 2 ; -1 0 1]; 19 | flt2=[-1 -2 -1; 0 0 0; 1 2 1]; 20 | 21 | % 1) get the map 22 | 23 | fuseX=filter2(flt1,fuse,'same'); 24 | fuseY=filter2(flt2,fuse,'same'); 25 | fuseG=sqrt(fuseX.*fuseX+fuseY.*fuseY); 26 | 27 | buffer=(fuseX==0); 28 | buffer=buffer*0.00001; 29 | fuseX=fuseX+buffer; 30 | fuseA=atan(fuseY./fuseX); 31 | 32 | img1X=filter2(flt1,img1,'same'); 33 | img1Y=filter2(flt2,img1,'same'); 34 | img1G=sqrt(img1X.*img1X+img1Y.*img1Y); 35 | buffer=(img1X==0); 36 | buffer=buffer*0.00001; 37 | img1X=img1X+buffer; 38 | img1A=atan(img1Y./img1X); 39 | 40 | img2X=filter2(flt1,img2,'same'); 41 | img2Y=filter2(flt2,img2,'same'); 42 | img2G=sqrt(img2X.*img2X+img2Y.*img2Y); 43 | buffer=(img2X==0); 44 | buffer=buffer*0.00001; 45 | img2X=img2X+buffer; 46 | img2A=atan(img2Y./img2X); 47 | 48 | % 2) edge preservation estimation 49 | 50 | bimap=img1G>fuseG; 51 | 52 | buffer=(img1G==0); buffer=buffer*0.00001; img1G=img1G+buffer; 53 | buffer1=fuseG./img1G; 54 | 55 | buffer=(fuseG==0); buffer=buffer*0.00001; fuseG=fuseG+buffer; 56 | buffer2=img1G./fuseG; 57 | 58 | Gaf=bimap.*buffer1+(1-bimap).*buffer2; 59 | Aaf=abs(abs(img1A-fuseA)-pi/2)*2/pi; 60 | 61 | %------------ 62 | 63 | bimap=img2G>fuseG; 64 | 65 | buffer=(img2G==0); buffer=buffer*0.00001; img2G=img2G+buffer; 66 | buffer1=fuseG./img2G; 67 | 68 | buffer=(fuseG==0); buffer=buffer*0.00001; fuseG=fuseG+buffer; 69 | buffer2=img2G./fuseG; 70 | 71 | Gbf=bimap.*buffer1+(1-bimap).*buffer2; 72 | Abf=abs(abs(img2A-fuseA)-pi/2)*2/pi; 73 | 74 | %some parameter 75 | gama1=1;gama2=1; 76 | k1=-10; k2=-20; 77 | delta1=0.5; delta2=0.75; 78 | 79 | Qg_AF=gama1./(1+exp(k1*(Gaf-delta1))); 80 | Qalpha_AF=gama2./(1+exp(k2*(Aaf-delta2))); 81 | Qaf=Qg_AF.*Qalpha_AF; 82 | 83 | Qg_BF=gama1./(1+exp(k1*(Gbf-delta1))); 84 | Qalpha_BF=gama2./(1+exp(k2*(Abf-delta2))); 85 | Qbf=Qg_BF.*Qalpha_BF; 86 | 87 | % 3) compute the weighting matrix 88 | L=1; 89 | 90 | Wa=img1G.^L; 91 | Wb=img2G.^L; 92 | 93 | %res=sum(sum(Qaf.*Wa+Qbf.*Wb))/sum(sum(Wa+Wb)); 94 | res=mean2((Qaf.*Wa+Qbf.*Wb)./(Wa+Wb)); -------------------------------------------------------------------------------- /evaluation/metricYang.m: -------------------------------------------------------------------------------- 1 | function res=metricYang(im1,im2,fim) 2 | 3 | % function res=metricYang(im1,im2,fim) 4 | % 5 | % This function implements Yang's algorithm for fusion metric. 6 | % im1, im2 -- input images; 7 | % fim -- fused image; 8 | % res -- metric value. 9 | % 10 | % Z. Liu [July 2009] 11 | % 12 | 13 | % Ref: A novel similarity based quality metric for image fusion, Information Fusion, Vol.9, pp156-160, 2008 14 | % by Cui Yang et al. 15 | % 16 | 17 | %% some pre-processing 18 | im1=double(im1); 19 | im2=double(im2); 20 | fim=double(fim); 21 | 22 | %% first call the SSIM 23 | [mssim1, ssim_map1, sigma1_sq1,sigma2_sq1] = ssim_yang(im1, im2); 24 | [mssim2, ssim_map2, sigma1_sq2,sigma2_sq2] = ssim_yang(im1, fim); 25 | [mssim3, ssim_map3, sigma1_sq3,sigma2_sq3] = ssim_yang(im2, fim); 26 | 27 | bin_map=ssim_map1>=0.75; 28 | ramda=sigma1_sq1./(sigma1_sq1+sigma2_sq1); 29 | 30 | Q1=(ramda.*ssim_map2+(1-ramda).*ssim_map3).*bin_map; 31 | 32 | Q2=(max(ssim_map2,ssim_map3)).*(~bin_map); 33 | 34 | Q=mean2(Q1+Q2); 35 | 36 | res=Q; 37 | 38 | 39 | %% 40 | function [mssim, ssim_map, sigma1_sq,sigma2_sq] = ssim_yang(img1, img2) 41 | 42 | %======================================================================== 43 | 44 | [M N] = size(img1); 45 | if ((M < 11) | (N < 11)) 46 | ssim_index = -Inf; 47 | ssim_map = -Inf; 48 | return 49 | end 50 | window = fspecial('gaussian', 7, 1.5); % 51 | 52 | L = 255; % 53 | 54 | C1 = 2e-16; 55 | C2 = 2e-16; 56 | 57 | window = window/sum(sum(window)); 58 | img1 = double(img1); 59 | img2 = double(img2); 60 | mu1 = filter2(window, img1, 'valid'); 61 | mu2 = filter2(window, img2, 'valid'); 62 | mu1_sq = mu1.*mu1; 63 | mu2_sq = mu2.*mu2; 64 | mu1_mu2 = mu1.*mu2; 65 | sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq; 66 | sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq; 67 | sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2; 68 | if (C1 > 0 & C2 > 0) 69 | ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2)); 70 | else 71 | numerator1 = 2*mu1_mu2 + C1; 72 | numerator2 = 2*sigma12 + C2; 73 | denominator1 = mu1_sq + mu2_sq + C1; 74 | denominator2 = sigma1_sq + sigma2_sq + C2; 75 | ssim_map = ones(size(mu1)); 76 | 77 | index = (denominator1.*denominator2 > 0); 78 | ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index)); 79 | index = (denominator1 ~= 0) & (denominator2 == 0); 80 | ssim_map(index) = numerator1(index)./denominator1(index); 81 | end 82 | 83 | mssim = mean2(ssim_map); 84 | 85 | 86 | return 87 | -------------------------------------------------------------------------------- /evaluation/metricZhao.m: -------------------------------------------------------------------------------- 1 | function res=metricZhao(im1,im2,fused) 2 | 3 | % function res=pc_assessFusion(im1,im2,fused) 4 | % 5 | % This function is to do the assessment for the fused image. 6 | % 7 | % im1 ---- the input image one 8 | % im2 ---- the input image two 9 | % fused ---- the fused image 10 | % res ==== the assessment result 11 | % 12 | % Z. Liu @NRCC 13 | 14 | % Ref: Performance assessment of combinative pixel-level image fusion based on an absolute feature measurement, International Journal of Innovative Computing, Information and Control, 3 (6A) 2007, pp.1433-1447 15 | % by J. Zhao et al. 16 | % 17 | 18 | % some global parameters 19 | 20 | fea_threshold=0.1; % threshold value for the feature 21 | 22 | % 1) first, calculate the PC 23 | 24 | im1=double(im1); 25 | im2=double(im2); 26 | 27 | 28 | [pc1,or1,M1,m1]=myphasecong3(im1); 29 | clear or1; 30 | 31 | [pc2,or2,M2,m2]=myphasecong3(im2); 32 | clear or2; 33 | 34 | [pcf,orf,Mf,mf]=myphasecong3(fused); 35 | clear orf; 36 | 37 | % 2) 38 | [hang,lie]=size(fused); 39 | 40 | mask=(pc1>pc2); 41 | pc_max=mask.*pc1+(~mask).*pc2; 42 | M_max=mask.*M1+(~mask).*M2; 43 | m_max=mask.*m1+(~mask).*m2; 44 | 45 | mask1=(pc1>fea_threshold); 46 | mask2=(pc2>fea_threshold); 47 | mask3=(pc_max>fea_threshold); 48 | 49 | 50 | % the PC component 51 | resultPC=correlation_coeffcient(pc1,pc2,pc_max,pcf,mask1,mask2,mask3); 52 | clear pc1; 53 | clear pc2; 54 | clear pc_max; 55 | clear pcf; 56 | 57 | resultM=correlation_coeffcient(M1,M2,M_max,Mf,mask1,mask2,mask3); 58 | clear M1; 59 | clear M2; 60 | clear M_max; 61 | clear Mf; 62 | 63 | resultm=correlation_coeffcient(m1,m2,m_max,mf,mask1,mask2,mask3); 64 | clear m1; 65 | clear m2; 66 | clear m_max; 67 | clear mf; 68 | 69 | [resultPC resultM resultm]'; 70 | 71 | res=resultPC*resultM*resultm; 72 | 73 | 74 | 75 | %================================================= 76 | % 77 | % This sub-function is to calculate the correlation coefficients 78 | % 79 | %================================================= 80 | 81 | function res=correlation_coeffcient(im1,im2,im_max,imf, mask1,mask2,mask3) 82 | 83 | % im1, im2, im_max, imf --- the input feature maps 84 | % mask1~3 --- the corresponding PC map mask for original image 1, 2, max. 85 | % 86 | % 87 | % 88 | 89 | % some local constant parameters 90 | window=fspecial('gaussian',11,1.5); 91 | window=window./(sum(window(:))); 92 | 93 | C1=0.0001; 94 | C2=0.0001; 95 | C3=0.0001; 96 | 97 | % 98 | im1=mask1.*im1; 99 | im2=mask2.*im2; 100 | im_max=mask3.*im_max; 101 | 102 | mu1=filter2(window,im1,'same'); 103 | mu2=filter2(window,im2,'same'); 104 | muf=filter2(window,imf,'same'); 105 | mu_max=filter2(window,im_max,'same'); 106 | 107 | mu1_sq=mu1.*mu1; 108 | mu2_sq=mu2.*mu2; 109 | muf_sq=muf.*muf; 110 | mu_max_sq=mu_max.*mu_max; 111 | 112 | mu1_muf=mu1.*muf; 113 | mu2_muf=mu2.*muf; 114 | mu_max_muf=mu_max.*muf; 115 | 116 | sigma1_sq=filter2(window,im1.*im1,'same')-mu1_sq; 117 | sigma2_sq=filter2(window,im2.*im2,'same')-mu2_sq; 118 | sigmaMax_sq=filter2(window,im_max.*im_max,'same')-mu_max_sq; 119 | sigmaf_sq=filter2(window,imf.*imf,'same')-muf_sq; 120 | 121 | sigma1f=filter2(window,im1.*imf,'same')-mu1_muf; 122 | sigma2f=filter2(window,im2.*imf,'same')-mu2_muf; 123 | sigmaMaxf=filter2(window,im_max.*imf,'same')-mu_max_muf; 124 | 125 | index1=find(mask1==1); 126 | index2=find(mask2==1); 127 | index3=find(mask3==1); 128 | 129 | res1=mu1.*0; 130 | res2=res1; 131 | res3=res1; 132 | 133 | res1(index1)=(sigma1f(index1)+C1)./(sqrt(abs(sigma1_sq(index1).*sigmaf_sq(index1)))+C1); 134 | res2(index2)=(sigma2f(index2)+C2)./(sqrt(abs(sigma2_sq(index2).*sigmaf_sq(index2)))+C2); 135 | res3(index3)=(sigmaMaxf(index3)+C3)./(sqrt(abs(sigmaMax_sq(index3).*sigmaf_sq(index3)))+C3); 136 | 137 | buffer(:,:,1)=res1; 138 | buffer(:,:,2)=res2; 139 | buffer(:,:,3)=res3; 140 | 141 | result=max(buffer,[],3); 142 | 143 | A1=sum(mask1(:)); 144 | A2=sum(mask2(:)); 145 | A3=sum(mask3(:)); 146 | 147 | res=sum(result(:))/A3; 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /evaluation/myphasecong3.m: -------------------------------------------------------------------------------- 1 | % function [phaseCongruency, or, M, m]=myphasecong3(varargin) 2 | % 3 | % This function is a revised version of Kovesi's phasecong3.m. 4 | % Please "type myphasecong3" for detailed information. 5 | % 6 | % 7 | % Z. Liu @NRCC[ July 31, 2006] 8 | 9 | % PHASECONG2 - Computes edge and corner phase congruency in an image. 10 | % 11 | % This function calculates the PC_2 measure of phase congruency. 12 | % This function supersedes PHASECONG 13 | % 14 | % There are potentially many arguments, here is the full usage: 15 | % 16 | % [M m or ft pc EO] = myphasecong3(im, nscale, norient, minWaveLength, ... 17 | % mult, sigmaOnf, dThetaOnSigma, k, cutOff, g) 18 | % 19 | % However, apart from the image, all parameters have defaults and the 20 | % usage can be as simple as: 21 | % 22 | % M = phasecong2(im); 23 | % 24 | % Arguments: 25 | % Default values Description 26 | % 27 | % nscale 4 - Number of wavelet scales, try values 3-6 28 | % norient 6 - Number of filter orientations. 29 | % minWaveLength 3 - Wavelength of smallest scale filter. 30 | % mult 2.1 - Scaling factor between successive filters. 31 | % sigmaOnf 0.55 - Ratio of the standard deviation of the Gaussian 32 | % describing the log Gabor filter's transfer function 33 | % in the frequency domain to the filter center frequency. 34 | % dThetaOnSigma 1.2 - Ratio of angular interval between filter orientations 35 | % and the standard deviation of the angular Gaussian 36 | % function used to construct filters in the 37 | % freq. plane. 38 | % k 2.0 - No of standard deviations of the noise energy beyond 39 | % the mean at which we set the noise threshold point. 40 | % You may want to vary this up to a value of 10 or 41 | % 20 for noisy images 42 | % cutOff 0.5 - The fractional measure of frequency spread 43 | % below which phase congruency values get penalized. 44 | % g 10 - Controls the sharpness of the transition in 45 | % the sigmoid function used to weight phase 46 | % congruency for frequency spread. 47 | % 48 | % Returned values: 49 | % M - Maximum moment of phase congruency covariance. 50 | % This is used as a indicator of edge strength. 51 | % m - Minimum moment of phase congruency covariance. 52 | % This is used as a indicator of corner strength. 53 | % or - Orientation image in integer degrees 0-180, 54 | % positive anticlockwise. 55 | % 0 corresponds to a vertical edge, 90 is horizontal. 56 | % ft - *Not correctly implemented at this stage* 57 | % A complex valued image giving the weighted mean 58 | % phase angle at every point in the image for each 59 | % orientation. 60 | % pc - Cell array of phase congruency images (values between 0 and 1) 61 | % for each orientation 62 | % EO - A 2D cell array of complex valued convolution results 63 | % 64 | % EO{s,o} = convolution result for scale s and orientation o. The real part 65 | % is the result of convolving with the even symmetric filter, the imaginary 66 | % part is the result from convolution with the odd symmetric filter. 67 | % 68 | % Hence: 69 | % abs(EO{s,o}) returns the magnitude of the convolution over the 70 | % image at scale s and orientation o. 71 | % angle(EO{s,o}) returns the phase angles. 72 | % 73 | % Notes on specifying parameters: 74 | % 75 | % The parameters can be specified as a full list eg. 76 | % >> [M m or ft pc EO] = phasecong2(im, 5, 6, 3, 2.5, 0.55, 1.2, 2.0, 0.4, 10); 77 | % 78 | % or as a partial list with unspecified parameters taking on default values 79 | % >> [M m or ft pc EO] = phasecong2(im, 5, 6, 3); 80 | % 81 | % or as a partial list of parameters followed by some parameters specified via a 82 | % keyword-value pair, remaining parameters are set to defaults, for example: 83 | % >> [M m or ft pc EO] = phasecong2(im, 5, 6, 3, 'cutOff', 0.3, 'k', 2.5); 84 | % 85 | % The convolutions are done via the FFT. Many of the parameters relate to the 86 | % specification of the filters in the frequency plane. The values do not seem 87 | % to be very critical and the defaults are usually fine. You may want to 88 | % experiment with the values of 'nscales' and 'k', the noise compensation factor. 89 | % 90 | % Notes on filter settings to obtain even coverage of the spectrum 91 | % dthetaOnSigma 1.2 norient 6 92 | % sigmaOnf .85 mult 1.3 93 | % sigmaOnf .75 mult 1.6 (filter bandwidth ~1 octave) 94 | % sigmaOnf .65 mult 2.1 95 | % sigmaOnf .55 mult 3 (filter bandwidth ~2 octaves) 96 | % 97 | % For maximum speed the input image should have dimensions that correspond to 98 | % powers of 2, but the code will operate on images of arbitrary size. 99 | % 100 | % See Also: PHASECONG, PHASESYM, GABORCONVOLVE, PLOTGABORFILTERS 101 | 102 | % References: 103 | % 104 | % Peter Kovesi, "Image Features From Phase Congruency". Videre: A 105 | % Journal of Computer Vision Research. MIT Press. Volume 1, Number 3, 106 | % Summer 1999 http://mitpress.mit.edu/e-journals/Videre/001/v13.html 107 | % 108 | % Peter Kovesi, "Phase Congruency Detects Corners and 109 | % Edges". Proceedings DICTA 2003, Sydney Dec 10-12 110 | 111 | % April 1996 Original Version written 112 | % August 1998 Noise compensation corrected. 113 | % October 1998 Noise compensation corrected. - Again!!! 114 | % September 1999 Modified to operate on non-square images of arbitrary size. 115 | % May 2001 Modified to return feature type image. 116 | % July 2003 Altered to calculate 'corner' points. 117 | % October 2003 Speed improvements and refinements. 118 | % July 2005 Better argument handling, changed order of return values 119 | % August 2005 Made Octave compatible 120 | 121 | % Copyright (c) 1996-2005 Peter Kovesi 122 | % School of Computer Science & Software Engineering 123 | % The University of Western Australia 124 | % http://www.csse.uwa.edu.au/ 125 | % 126 | % Permission is hereby granted, free of charge, to any person obtaining a copy 127 | % of this software and associated documentation files (the "Software"), to deal 128 | % in the Software without restriction, subject to the following conditions: 129 | % 130 | % The above copyright notice and this permission notice shall be included in all 131 | % copies or substantial portions of the Software. 132 | % 133 | % The software is provided "as is", without warranty of any kind. 134 | 135 | %function [phaseCongruency, M, m, or, featType, PC, EO]=myphasecong3(varargin) 136 | 137 | function [phaseCongruency, or, M, m]=myphasecong3(varargin) 138 | 139 | 140 | % Get arguments and/or default values 141 | [im, nscale, norient, minWaveLength, mult, sigmaOnf, ... 142 | dThetaOnSigma,k, cutOff, g] = checkargs(varargin(:)); 143 | 144 | v = version; Octave = v(1)<'5'; % Crude Octave test 145 | epsilon = .0001; % Used to prevent division by zero. 146 | 147 | thetaSigma = pi/norient/dThetaOnSigma; % Calculate the standard deviation of the 148 | % angular Gaussian function used to 149 | % construct filters in the freq. plane. 150 | 151 | [rows,cols] = size(im); 152 | imagefft = fft2(im); % Fourier transform of image 153 | 154 | zero = zeros(rows,cols); 155 | totalEnergy = zero; % Total weighted phase congruency values (energy). 156 | totalSumAn = zero; % Total filter response amplitude values. 157 | orientation = zero; % Matrix storing orientation with greatest 158 | % energy for each pixel. 159 | EO = cell(nscale, norient); % Array of convolution results. 160 | covx2 = zero; % Matrices for covariance data 161 | covy2 = zero; 162 | covxy = zero; 163 | 164 | estMeanE2n = []; 165 | ifftFilterArray = cell(1,nscale); % Array of inverse FFTs of filters 166 | 167 | % Pre-compute some stuff to speed up filter construction 168 | 169 | % Set up X and Y matrices with ranges normalised to +/- 0.5 170 | % The following code adjusts things appropriately for odd and even values 171 | % of rows and columns. 172 | if mod(cols,2) 173 | xrange = [-(cols-1)/2:(cols-1)/2]/(cols-1); 174 | else 175 | xrange = [-cols/2:(cols/2-1)]/cols; 176 | end 177 | 178 | if mod(rows,2) 179 | yrange = [-(rows-1)/2:(rows-1)/2]/(rows-1); 180 | else 181 | yrange = [-rows/2:(rows/2-1)]/rows; 182 | end 183 | 184 | [x,y] = meshgrid(xrange, yrange); 185 | 186 | radius = sqrt(x.^2 + y.^2); % Matrix values contain *normalised* radius from centre. 187 | %radius(rows/2+1, cols/2+1) = 1; % Get rid of the 0 radius value in the middle 188 | radius(floor(rows/2)+1,floor(cols/2)+1)=1; % so that taking the log of the radius will 189 | % I add the FLOOR here % not cause trouble. 190 | theta = atan2(-y,x); % Matrix values contain polar angle. 191 | % (note -ve y is used to give +ve 192 | % anti-clockwise angles) 193 | radius = ifftshift(radius); % Quadrant shift radius and theta so that filters 194 | theta = ifftshift(theta); % are constructed with 0 frequency at the corners. 195 | 196 | sintheta = sin(theta); 197 | costheta = cos(theta); 198 | clear x; clear y; clear theta; % save a little memory 199 | 200 | % Filters are constructed in terms of two components. 201 | % 1) The radial component, which controls the frequency band that the filter 202 | % responds to 203 | % 2) The angular component, which controls the orientation that the filter 204 | % responds to. 205 | % The two components are multiplied together to construct the overall filter. 206 | 207 | % Construct the radial filter components... 208 | 209 | % First construct a low-pass filter that is as large as possible, yet falls 210 | % away to zero at the boundaries. All log Gabor filters are multiplied by 211 | % this to ensure no extra frequencies at the 'corners' of the FFT are 212 | % incorporated as this seems to upset the normalisation process when 213 | % calculating phase congrunecy. 214 | lp = lowpassfilter([rows,cols],.45,15); % Radius .45, 'sharpness' 15 215 | 216 | logGabor = cell(1,nscale); 217 | 218 | for s = 1:nscale 219 | wavelength = minWaveLength*mult^(s-1); 220 | fo = 1.0/wavelength; % Centre frequency of filter. 221 | logGabor{s} = exp((-(log(radius/fo)).^2) / (2 * log(sigmaOnf)^2)); 222 | logGabor{s} = logGabor{s}.*lp; % Apply low-pass filter 223 | logGabor{s}(1,1) = 0; % Set the value at the 0 frequency point of the filter 224 | % back to zero (undo the radius fudge). 225 | end 226 | 227 | % Then construct the angular filter components... 228 | 229 | spread = cell(1,norient); 230 | 231 | for o = 1:norient 232 | angl = (o-1)*pi/norient; % Filter angle. 233 | 234 | % For each point in the filter matrix calculate the angular distance from 235 | % the specified filter orientation. To overcome the angular wrap-around 236 | % problem sine difference and cosine difference values are first computed 237 | % and then the atan2 function is used to determine angular distance. 238 | 239 | ds = sintheta * cos(angl) - costheta * sin(angl); % Difference in sine. 240 | dc = costheta * cos(angl) + sintheta * sin(angl); % Difference in cosine. 241 | dtheta = abs(atan2(ds,dc)); % Absolute angular distance. 242 | spread{o} = exp((-dtheta.^2) / (2 * thetaSigma^2)); % Calculate the 243 | % angular filter component. 244 | end 245 | 246 | % The main loop... 247 | 248 | for o = 1:norient % For each orientation. 249 | fprintf('Processing orientation %d\r',o); 250 | if Octave fflush(1); end 251 | 252 | angl = (o-1)*pi/norient; % Filter angle. 253 | sumE_ThisOrient = zero; % Initialize accumulator matrices. 254 | sumO_ThisOrient = zero; 255 | sumAn_ThisOrient = zero; 256 | Energy = zero; 257 | 258 | for s = 1:nscale, % For each scale. 259 | filter = logGabor{s} .* spread{o}; % Multiply radial and angular 260 | % components to get the filter. 261 | 262 | % if o == 1 % accumulate filter info for noise compensation (nominally the same 263 | % for all orientations, hence it is only done once) 264 | ifftFilt = real(ifft2(filter))*sqrt(rows*cols); % Note rescaling to match power 265 | ifftFilterArray{s} = ifftFilt; % record ifft2 of filter 266 | % end 267 | 268 | % Convolve image with even and odd filters returning the result in EO 269 | EO{s,o} = ifft2(imagefft .* filter); 270 | 271 | An = abs(EO{s,o}); % Amplitude of even & odd filter response. 272 | sumAn_ThisOrient = sumAn_ThisOrient + An; % Sum of amplitude responses. 273 | sumE_ThisOrient = sumE_ThisOrient + real(EO{s,o}); % Sum of even filter convolution results. 274 | sumO_ThisOrient = sumO_ThisOrient + imag(EO{s,o}); % Sum of odd filter convolution results. 275 | 276 | if s==1 % Record mean squared filter value at smallest 277 | EM_n = sum(sum(filter.^2)); % scale. This is used for noise estimation. 278 | maxAn = An; % Record the maximum An over all scales. 279 | else 280 | maxAn = max(maxAn, An); 281 | end 282 | 283 | end % ... and process the next scale 284 | 285 | % Get weighted mean filter response vector, this gives the weighted mean 286 | % phase angle. 287 | 288 | XEnergy = sqrt(sumE_ThisOrient.^2 + sumO_ThisOrient.^2) + epsilon; 289 | MeanE = sumE_ThisOrient ./ XEnergy; 290 | MeanO = sumO_ThisOrient ./ XEnergy; 291 | 292 | % Now calculate An(cos(phase_deviation) - | sin(phase_deviation)) | by 293 | % using dot and cross products between the weighted mean filter response 294 | % vector and the individual filter response vectors at each scale. This 295 | % quantity is phase congruency multiplied by An, which we call energy. 296 | 297 | for s = 1:nscale, 298 | E = real(EO{s,o}); O = imag(EO{s,o}); % Extract even and odd 299 | % convolution results. 300 | Energy = Energy + E.*MeanE + O.*MeanO - abs(E.*MeanO - O.*MeanE); 301 | end 302 | 303 | % Compensate for noise 304 | % We estimate the noise power from the energy squared response at the 305 | % smallest scale. If the noise is Gaussian the energy squared will have a 306 | % Chi-squared 2DOF pdf. We calculate the median energy squared response 307 | % as this is a robust statistic. From this we estimate the mean. 308 | % The estimate of noise power is obtained by dividing the mean squared 309 | % energy value by the mean squared filter value 310 | 311 | medianE2n = median(reshape(abs(EO{1,o}).^2,1,rows*cols)); 312 | meanE2n = -medianE2n/log(0.5); 313 | estMeanE2n(o) = meanE2n; 314 | 315 | noisePower = meanE2n/EM_n; % Estimate of noise power. 316 | 317 | % if o == 1 318 | % Now estimate the total energy^2 due to noise 319 | % Estimate for sum(An^2) + sum(Ai.*Aj.*(cphi.*cphj + sphi.*sphj)) 320 | 321 | EstSumAn2 = zero; 322 | for s = 1:nscale 323 | EstSumAn2 = EstSumAn2 + ifftFilterArray{s}.^2; 324 | end 325 | 326 | EstSumAiAj = zero; 327 | for si = 1:(nscale-1) 328 | for sj = (si+1):nscale 329 | EstSumAiAj = EstSumAiAj + ifftFilterArray{si}.*ifftFilterArray{sj}; 330 | end 331 | end 332 | sumEstSumAn2 = sum(sum(EstSumAn2)); 333 | sumEstSumAiAj = sum(sum(EstSumAiAj)); 334 | 335 | % end % if o == 1 336 | 337 | EstNoiseEnergy2 = 2*noisePower*sumEstSumAn2 + 4*noisePower*sumEstSumAiAj; 338 | 339 | tau = sqrt(EstNoiseEnergy2/2); % Rayleigh parameter 340 | EstNoiseEnergy = tau*sqrt(pi/2); % Expected value of noise energy 341 | EstNoiseEnergySigma = sqrt( (2-pi/2)*tau^2 ); 342 | 343 | T = EstNoiseEnergy + k*EstNoiseEnergySigma; % Noise threshold 344 | 345 | % The estimated noise effect calculated above is only valid for the PC_1 measure. 346 | % The PC_2 measure does not lend itself readily to the same analysis. However 347 | % empirically it seems that the noise effect is overestimated roughly by a factor 348 | % of 1.7 for the filter parameters used here. 349 | 350 | T = T/1.7; % Empirical rescaling of the estimated noise effect to 351 | % suit the PC_2 phase congruency measure 352 | 353 | Energy = max(Energy - T, zero); % Apply noise threshold 354 | 355 | % Form weighting that penalizes frequency distributions that are 356 | % particularly narrow. Calculate fractional 'width' of the frequencies 357 | % present by taking the sum of the filter response amplitudes and dividing 358 | % by the maximum amplitude at each point on the image. 359 | 360 | width = sumAn_ThisOrient ./ (maxAn + epsilon) / nscale; 361 | 362 | % Now calculate the sigmoidal weighting function for this orientation. 363 | 364 | weight = 1.0 ./ (1 + exp( (cutOff - width)*g)); 365 | 366 | 367 | %---------------------------------------------- 368 | Energy_ThisOrient=weight.*Energy; 369 | totalSumAn=totalSumAn+sumAn_ThisOrient; 370 | totalEnergy=totalEnergy+Energy_ThisOrient; 371 | 372 | if (o==1), 373 | maxEnergy=Energy_ThisOrient; 374 | else 375 | change=Energy_ThisOrient>maxEnergy; 376 | orientation=(o-1).*change+orientation.*(~change); 377 | maxEnergy=max(maxEnergy, Energy_ThisOrient); 378 | end 379 | %---------------------------------------------- 380 | 381 | 382 | 383 | % Apply weighting to energy and then calculate phase congruency 384 | 385 | PC{o} = weight.*Energy./sumAn_ThisOrient; % Phase congruency for this orientation 386 | featType{o} = E+i*O; 387 | 388 | % Build up covariance data for every point 389 | covx = PC{o}*cos(angl); 390 | covy = PC{o}*sin(angl); 391 | covx2 = covx2 + covx.^2; 392 | covy2 = covy2 + covy.^2; 393 | covxy = covxy + covx.*covy; 394 | 395 | end % For each orientation 396 | 397 | fprintf(' \r'); 398 | 399 | %------------------------------------------------------------ 400 | phaseCongruency=totalEnergy./(totalSumAn+epsilon); 401 | orientation=orientation*(180/norient); 402 | %------------------------------------------------------------ 403 | 404 | 405 | % Edge and Corner calculations 406 | 407 | % The following is optimised code to calculate principal vector 408 | % of the phase congruency covariance data and to calculate 409 | % the minimumum and maximum moments - these correspond to 410 | % the singular values. 411 | 412 | % First normalise covariance values by the number of orientations/2 413 | 414 | covx2 = covx2/(norient/2); 415 | covy2 = covy2/(norient/2); 416 | covxy = covxy/norient; % This gives us 2*covxy/(norient/2) 417 | 418 | denom = sqrt(covxy.^2 + (covx2-covy2).^2)+epsilon; 419 | sin2theta = covxy./denom; 420 | cos2theta = (covx2-covy2)./denom; 421 | or = atan2(sin2theta,cos2theta)/2; % Orientation perpendicular to edge. 422 | or = round(or*180/pi); % Return result rounded to integer 423 | % degrees. 424 | neg = or < 0; 425 | or = ~neg.*or + neg.*(or+180); % Adjust range from -90 to 90 426 | % to 0 to 180. 427 | 428 | M = (covy2+covx2 + denom)/2; % Maximum moment 429 | m = (covy2+covx2 - denom)/2; % ... and minimum moment 430 | 431 | 432 | 433 | 434 | 435 | %------------------------------------------------------------------ 436 | % CHECKARGS 437 | % 438 | % Function to process the arguments that have been supplied, assign 439 | % default values as needed and perform basic checks. 440 | 441 | function [im, nscale, norient, minWaveLength, mult, sigmaOnf, ... 442 | dThetaOnSigma,k, cutOff, g] = checkargs(arg); 443 | 444 | nargs = length(arg); 445 | 446 | if nargs < 1 447 | error('No image supplied as an argument'); 448 | end 449 | 450 | % Set up default values for all arguments and then overwrite them 451 | % with with any new values that may be supplied 452 | im = []; 453 | nscale = 4; % Number of wavelet scales. 454 | norient = 6; % Number of filter orientations. 455 | minWaveLength = 3; % Wavelength of smallest scale filter. 456 | mult = 2.1; % Scaling factor between successive filters. 457 | sigmaOnf = 0.55; % Ratio of the standard deviation of the 458 | % Gaussian describing the log Gabor filter's 459 | % transfer function in the frequency domain 460 | % to the filter center frequency. 461 | dThetaOnSigma = 1.2; % Ratio of angular interval between filter orientations 462 | % and the standard deviation of the angular Gaussian 463 | % function used to construct filters in the 464 | % freq. plane. 465 | k = 2.0; % No of standard deviations of the noise 466 | % energy beyond the mean at which we set the 467 | % noise threshold point. 468 | cutOff = 0.5; % The fractional measure of frequency spread 469 | % below which phase congruency values get penalized. 470 | g = 10; % Controls the sharpness of the transition in 471 | % the sigmoid function used to weight phase 472 | % congruency for frequency spread. 473 | 474 | % Allowed argument reading states 475 | allnumeric = 1; % Numeric argument values in predefined order 476 | keywordvalue = 2; % Arguments in the form of string keyword 477 | % followed by numeric value 478 | readstate = allnumeric; % Start in the allnumeric state 479 | 480 | if readstate == allnumeric 481 | for n = 1:nargs 482 | if isa(arg{n},'char') 483 | readstate = keywordvalue; 484 | break; 485 | else 486 | if n == 1, im = arg{n}; 487 | elseif n == 2, nscale = arg{n}; 488 | elseif n == 3, norient = arg{n}; 489 | elseif n == 4, minWaveLength = arg{n}; 490 | elseif n == 5, mult = arg{n}; 491 | elseif n == 6, sigmaOnf = arg{n}; 492 | elseif n == 7, dThetaOnSigma = arg{n}; 493 | elseif n == 8, k = arg{n}; 494 | elseif n == 9, cutOff = arg{n}; 495 | elseif n == 10,g = arg{n}; 496 | end 497 | end 498 | end 499 | end 500 | 501 | % Code to handle parameter name - value pairs 502 | if readstate == keywordvalue 503 | while n < nargs 504 | 505 | if ~isa(arg{n},'char') | ~isa(arg{n+1}, 'double') 506 | error('There should be a parameter name - value pair'); 507 | end 508 | 509 | if strncmpi(arg{n},'im' ,2), im = arg{n+1}; 510 | elseif strncmpi(arg{n},'nscale' ,2), nscale = arg{n+1}; 511 | elseif strncmpi(arg{n},'norient' ,2), norient = arg{n+1}; 512 | elseif strncmpi(arg{n},'minWaveLength',2), minWavelength = arg{n+1}; 513 | elseif strncmpi(arg{n},'mult' ,2), mult = arg{n+1}; 514 | elseif strncmpi(arg{n},'sigmaOnf',2), sigmaOnf = arg{n+1}; 515 | elseif strncmpi(arg{n},'dthetaOnSigma',2), dThetaOnSigma = arg{n+1}; 516 | elseif strncmpi(arg{n},'k' ,1), k = arg{n+1}; 517 | elseif strncmpi(arg{n},'cutOff' ,2), cutOff = arg{n+1}; 518 | elseif strncmpi(arg{n},'g' ,1), g = arg{n+1}; 519 | else error('Unrecognised parameter name'); 520 | end 521 | 522 | n = n+2; 523 | if n == nargs 524 | error('Unmatched parameter name - value pair'); 525 | end 526 | 527 | end 528 | end 529 | 530 | if isempty(im) 531 | error('No image argument supplied'); 532 | end 533 | 534 | if ~isa(im, 'double') 535 | im = double(im); 536 | end 537 | 538 | if nscale < 1 539 | error('nscale must be an integer >= 1'); 540 | end 541 | 542 | if norient < 1 543 | error('norient must be an integer >= 1'); 544 | end 545 | 546 | if minWaveLength < 2 547 | error('It makes little sense to have a wavelength < 2'); 548 | end 549 | 550 | if cutOff < 0 | cutOff > 1 551 | error('Cut off value must be between 0 and 1'); 552 | end 553 | 554 | 555 | 556 | %############################################################################# 557 | 558 | function f = lowpassfilter(sze, cutoff, n) 559 | 560 | if cutoff < 0 | cutoff > 0.5 561 | error('cutoff frequency must be between 0 and 0.5'); 562 | end 563 | 564 | if rem(n,1) ~= 0 | n < 1 565 | error('n must be an integer >= 1'); 566 | end 567 | 568 | rows = sze(1); cols = sze(2); 569 | 570 | % X and Y matrices with ranges normalised to +/- 0.5 571 | x = (ones(rows,1) * [1:cols] - (fix(cols/2)+1))/cols; 572 | y = ([1:rows]' * ones(1,cols) - (fix(rows/2)+1))/rows; 573 | 574 | radius = sqrt(x.^2 + y.^2); % A matrix with every pixel = radius relative to centre. 575 | 576 | f = fftshift( 1 ./ (1.0 + (radius ./ cutoff).^(2*n)) ); % The filter 577 | 578 | 579 | 580 | 581 | -------------------------------------------------------------------------------- /evaluation/using_FMI.m: -------------------------------------------------------------------------------- 1 | function nfmi = using_FMI(ima, imb, imf, feature, w) 2 | 3 | % FMI calculates the Feature Mutual Information (FMI), the non-reference 4 | % performance metric for fusion algorithms, proposed in: 5 | % 6 | % M.B.A. Haghighat, A. Aghagolzadeh, H. Seyedarabi, "A Non-Reference Image 7 | % Fusion Metric Based on Mutual Information of Image Features," Computers 8 | % and Electrical Engineering, vol. 37, no. 5, pp. 744-756, Sept. 2011. 9 | % http://dx.doi.org/10.1016/j.compeleceng.2011.07.012 10 | % 11 | % 12 | % This code is the implementation of FAST-FMI, presented in: 13 | % 14 | % M. Haghighat, M.A. Razian, "Fast-FMI: non-reference image fusion metric," 15 | % 8th International Conference on Application of Information and 16 | % Communication Technologies (AICT), pp. 1-3, 2014. 17 | % 18 | % 19 | % Inputs: 20 | % ima : First source image 21 | % imb : Second source image 22 | % imf : Fused image 23 | % feature : Feature extraction method: gradient, edge, dct, wavelet, none (raw pixels) (default: image with no feature extraction) 24 | % w : Sliding window size w by w (default: 3) 25 | % 26 | % Output: 27 | % nfmi : Normalized Feature Mutual Information 28 | % 29 | % 30 | % Sample use: 31 | % nfmi = fmi(ima,imb,imf,'none',3); 32 | % % Or simply: 33 | % nfmi = fmi(ima,imb,imf); 34 | % 35 | % 36 | % (C) Mohammad Haghighat, University of Miami 37 | % haghighat@ieee.org 38 | % IF YOU USE THIS CODE IN YOUR WORK, PLEASE CITE THE ABOVE PAPERS. 39 | 40 | 41 | 42 | if nargin < 3 % Check correct number of arguments 43 | error('There should be three input images (2 source images and 1 fused image)!'); 44 | end 45 | 46 | if size(ima) ~= size(imb) % Check if the source images are of the same size 47 | error('Size of the source images must be the same!'); 48 | end 49 | 50 | if size(ima) ~= size(imf) % Check if the source images are of the same size 51 | error('Size of the source and fused images must be the same!'); 52 | end 53 | 54 | if ~exist('feature', 'var') 55 | feature = 'edge'; % Default feature extraction 56 | end 57 | 58 | if ~exist('w', 'var') 59 | w = 3; % Default window size 60 | end 61 | 62 | ima = double(ima); 63 | imb = double(imb); 64 | imf = double(imf); 65 | 66 | 67 | % Feature Extraction 68 | 69 | switch feature 70 | 71 | case 'none' % Raw pixels (no feature extraction) 72 | aFeature = ima; 73 | bFeature = imb; 74 | fFeature = imf; 75 | 76 | case 'gradient' % Gradient 77 | aFeature = gradient(ima); 78 | bFeature = gradient(imb); 79 | fFeature = gradient(imf); 80 | 81 | case 'edge' % Edge 82 | aFeature = edge(ima); 83 | bFeature = edge(imb); 84 | fFeature = edge(imf); 85 | 86 | case 'dct' % DCT 87 | aFeature = dct2(ima); 88 | bFeature = dct2(imb); 89 | fFeature = dct2(imf); 90 | 91 | case 'wavelet' % Discrete Meyer wavelet 92 | [cA,cH,cV,cD] = dwt2(ima,'dmey'); 93 | aFeature = rerange([cA,cH;cV,cD]); 94 | [cA,cH,cV,cD] = dwt2(imb,'dmey'); 95 | bFeature = rerange([cA,cH;cV,cD]); 96 | [cA,cH,cV,cD] = dwt2(imf,'dmey'); 97 | fFeature = rerange([cA,cH;cV,cD]); 98 | 99 | otherwise 100 | error('Please specify a feature extraction method among ''gradient'', ''edge'', ''dct'', ''wavelet'', or ''none'' (raw pixels)!'); 101 | 102 | end 103 | 104 | 105 | % Sliding window 106 | 107 | [m,n] = size(aFeature); 108 | w = floor(w/2); 109 | fmi_map = ones(m-2*w, n-2*w); 110 | 111 | for p = w+1:m-w 112 | for q = w+1:n-w 113 | 114 | aSub = aFeature(p-w:p+w, q-w:q+w); 115 | bSub = bFeature(p-w:p+w, q-w:q+w); 116 | fSub = fFeature(p-w:p+w, q-w:q+w); 117 | 118 | l = round((2*w+1).^2); 119 | 120 | if aSub == fSub 121 | fmi_af = 1; 122 | else 123 | aMax = max(aSub(:)); 124 | aMin = min(aSub(:)); 125 | if aMax == aMin 126 | aSub = ones(2*w+1); 127 | else 128 | aSub = (aSub - aMin)/(aMax - aMin); 129 | end 130 | 131 | fMax = max(fSub(:)); 132 | fMin = min(fSub(:)); 133 | if fMax == fMin 134 | fSub = ones(2*w+1); 135 | else 136 | fSub = (fSub - fMin)/(fMax - fMin); 137 | end 138 | 139 | % Normalize the feature images to get the marginal PDFs 140 | aPdf = aSub(:)./(sum(sum(aSub))); 141 | fPdf = fSub(:)./(sum(sum(fSub))); 142 | 143 | % PDF to CDF tranformation 144 | aCdf = zeros(size(aPdf)); 145 | fCdf = zeros(size(fPdf)); 146 | aCdf(1) = aPdf(1); 147 | fCdf(1) = fPdf(1); 148 | for i = 2:l 149 | aCdf(i) = aPdf(i)+aCdf(i-1); 150 | fCdf(i) = fPdf(i)+fCdf(i-1); 151 | end 152 | 153 | % Pearson correlation between marginal PDFs 154 | aTemp = aPdf - mean(aPdf); 155 | fTemp = fPdf - mean(fPdf); 156 | if sum(aTemp.*fTemp) == 0 157 | c = 0; 158 | else 159 | c = sum(aTemp.*fTemp)/sqrt(sum(aTemp.*aTemp)*sum(fTemp.*fTemp)); 160 | end 161 | 162 | % Population standard deviations 163 | e_aPdf = 0; e2_aPdf = 0; e_fPdf = 0; e2_fPdf = 0; 164 | for i = 1:l 165 | e_aPdf = e_aPdf + i.*aPdf(i); % Expected value of aPdf 166 | e2_aPdf = e2_aPdf + (i.^2).*aPdf(i); % 2nd-order moment of aPdf 167 | e_fPdf = e_fPdf + i.*fPdf(i); % Expected value of fPdf 168 | e2_fPdf = e2_fPdf + (i.^2).*fPdf(i); % 2nd-order moment of fPdf 169 | end 170 | aSd = sqrt(e2_aPdf - e_aPdf.^2); % Population standard deviation of aPdf 171 | fSd = sqrt(e2_fPdf - e_fPdf.^2); % Population standard deviation of fPdf 172 | 173 | 174 | jointEntropy = 0; 175 | % Joint PDF calculation using simplified Nelsen method with joint entropy calculation 176 | if c >= 0 177 | 178 | if c == 0 || aSd == 0 || fSd == 0 179 | phi = 0; 180 | else 181 | covUp = 0; 182 | for i = 1:l 183 | for j = 1:l 184 | % Frechet's upper bound bivariate distributions between f & a 185 | covUp = covUp + 0.5*(fCdf(i)+aCdf(j)-abs(fCdf(i)-aCdf(j))) - fCdf(i).*aCdf(j); 186 | end 187 | end 188 | corrUp = covUp/(fSd*aSd); % Upper correlation between f & a 189 | phi = c/corrUp; 190 | end 191 | 192 | jpdfUp = 0.5*(fCdf(1)+aCdf(1)-abs(fCdf(1)-aCdf(1))); 193 | jpdf = phi.*jpdfUp + (1-phi).*fPdf(1).*aPdf(1); 194 | if jpdf~=0 195 | jointEntropy = real(-jpdf.*log2(jpdf)); % Joint entropy 196 | end 197 | 198 | % 1-D boundaries 199 | for i=2:l 200 | jpdfUp = 0.5*(fCdf(i)+aCdf(1)-abs(fCdf(i)-aCdf(1))) - ... 201 | 0.5*(fCdf(i-1)+aCdf(1)-abs(fCdf(i-1)-aCdf(1))); 202 | jpdf = phi.*jpdfUp + (1-phi).*fPdf(i).*aPdf(1); 203 | if jpdf~=0 204 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 205 | end 206 | end 207 | for j=2:l 208 | jpdfUp = 0.5*(fCdf(1)+aCdf(j)-abs(fCdf(1)-aCdf(j))) - ... 209 | 0.5*(fCdf(1)+aCdf(j-1)-abs(fCdf(1)-aCdf(j-1))); 210 | jpdf = phi.*jpdfUp + (1-phi).*fPdf(1).*aPdf(j); 211 | if jpdf~=0 212 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 213 | end 214 | end 215 | % 2-D walls 216 | for i=2:l 217 | for j=2:l 218 | jpdfUp = 0.5*(fCdf(i)+aCdf(j)-abs(fCdf(i)-aCdf(j))) - ... 219 | 0.5*(fCdf(i-1)+aCdf(j)-abs(fCdf(i-1)-aCdf(j))) - ... 220 | 0.5*(fCdf(i)+aCdf(j-1)-abs(fCdf(i)-aCdf(j-1))) + ... 221 | 0.5*(fCdf(i-1)+aCdf(j-1)-abs(fCdf(i-1)-aCdf(j-1))); 222 | jpdf = phi.*jpdfUp + (1-phi).*fPdf(i).*aPdf(j); 223 | if jpdf~=0 224 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 225 | end 226 | end 227 | end 228 | 229 | end 230 | 231 | if c < 0 232 | 233 | if aSd == 0 || fSd == 0 234 | theta = 0; 235 | else 236 | covLo = 0; 237 | for i = 1:l 238 | for j = 1:l 239 | % Frechet's lower bound bivariate distributions between f & a 240 | covLo = covLo + 0.5*(fCdf(i)+aCdf(j)-1+abs(fCdf(i)+aCdf(j)-1)) - fCdf(i).*aCdf(j); 241 | end 242 | end 243 | corrLo = covLo/(fSd*aSd); % Lower correlation between f & a 244 | theta = c/corrLo; 245 | end 246 | 247 | jpdfLo = 0.5*(fCdf(1)+aCdf(1)-1+abs(fCdf(1)+aCdf(1)-1)); 248 | jpdf = theta.*jpdfLo + (1-theta).*fPdf(1).*aPdf(1); 249 | if jpdf~=0 250 | jointEntropy = real(-jpdf.*log2(jpdf)); % Joint entropy 251 | end 252 | 253 | % 1-D boundaries 254 | for i=2:l 255 | jpdfLo = 0.5*(fCdf(i)+aCdf(1)-1+abs(fCdf(i)+aCdf(1)-1)) - ... 256 | 0.5*(fCdf(i-1)+aCdf(1)-1+abs(fCdf(i-1)+aCdf(1)-1)); 257 | jpdf = theta.*jpdfLo + (1-theta).*fPdf(i).*aPdf(1); 258 | if jpdf~=0 259 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 260 | end 261 | end 262 | for j=2:l 263 | jpdfLo = 0.5*(fCdf(1)+aCdf(j)-1+abs(fCdf(1)+aCdf(j)-1)) - ... 264 | 0.5*(fCdf(1)+aCdf(j-1)-1+abs(fCdf(1)+aCdf(j-1)-1)); 265 | jpdf = theta.*jpdfLo + (1-theta).*fPdf(1).*aPdf(j); 266 | if jpdf~=0 267 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 268 | end 269 | end 270 | % 2-D walls 271 | for i=2:l 272 | for j=2:l 273 | jpdfLo = 0.5*(fCdf(i)+aCdf(j)-1+abs(fCdf(i)+aCdf(j)-1)) - ... 274 | 0.5*(fCdf(i-1)+aCdf(j)-1+abs(fCdf(i-1)+aCdf(j)-1)) - ... 275 | 0.5*(fCdf(i)+aCdf(j-1)-1+abs(fCdf(i)+aCdf(j-1)-1)) + ... 276 | 0.5*(fCdf(i-1)+aCdf(j-1)-1+abs(fCdf(i-1)+aCdf(j-1)-1)); 277 | jpdf = theta.*jpdfLo + (1-theta).*fPdf(i).*aPdf(j); 278 | if jpdf~=0 279 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 280 | end 281 | end 282 | end 283 | 284 | end 285 | 286 | % Marginal entropies 287 | index = find(aPdf~=0); 288 | aEntropy = sum(-aPdf(index).*log2(aPdf(index))); 289 | index = find(fPdf~=0); 290 | fEntropy = sum(-fPdf(index).*log2(fPdf(index))); 291 | 292 | % Mutual information between a & f 293 | mi = aEntropy + fEntropy - jointEntropy; 294 | 295 | % Overall normalized mutual information 296 | if mi == 0 297 | fmi_af = 0; 298 | else 299 | fmi_af = 2.*mi./(aEntropy+fEntropy); 300 | end 301 | 302 | end 303 | 304 | if bSub == fSub 305 | fmi_bf = 1; 306 | else 307 | bMax = max(bSub(:)); 308 | bMin = min(bSub(:)); 309 | if bMax == bMin 310 | bSub = ones(2*w+1); 311 | else 312 | bSub = (bSub - bMin)/(bMax - bMin); 313 | end 314 | 315 | fMax = max(fSub(:)); 316 | fMin = min(fSub(:)); 317 | if fMax == fMin 318 | fSub = ones(2*w+1); 319 | else 320 | fSub = (fSub - fMin)/(fMax - fMin); 321 | end 322 | 323 | % PDF of the gradients of the images 324 | bPdf = bSub(:)./(sum(sum(bSub))); 325 | fPdf = fSub(:)./(sum(sum(fSub))); 326 | 327 | l = length(bPdf); 328 | 329 | % PDF to CDF tranformation 330 | bCdf = zeros(size(bPdf)); 331 | fCdf = zeros(size(fPdf)); 332 | bCdf(1) = bPdf(1); 333 | fCdf(1) = fPdf(1); 334 | for i=2:l 335 | bCdf(i) = bPdf(i)+bCdf(i-1); 336 | fCdf(i) = fPdf(i)+fCdf(i-1); 337 | end 338 | 339 | % Pearson correlation between marginal PDFs 340 | bTemp = bPdf - mean(bPdf); 341 | fTemp = fPdf - mean(fPdf); 342 | if sum(bTemp.*fTemp) == 0 343 | c = 0; 344 | else 345 | c = sum(bTemp.*fTemp)/sqrt(sum(bTemp.*bTemp)*sum(fTemp.*fTemp)); 346 | end 347 | 348 | % Population standard deviations 349 | e_bPdf = 0; e2_bPdf = 0; e_fPdf = 0; e2_fPdf = 0; 350 | for i = 1:l 351 | e_bPdf = e_bPdf + i.*bPdf(i); % Expected value of the aPdf 352 | e2_bPdf = e2_bPdf + (i.^2).*bPdf(i); % 2nd-order moment of the aPdf 353 | e_fPdf = e_fPdf + i.*fPdf(i); % Expected value of the bPdf 354 | e2_fPdf = e2_fPdf + (i.^2).*fPdf(i); % 2nd-order moment of the bPdf 355 | end 356 | bSd = sqrt(e2_bPdf - e_bPdf.^2); % Population standard deviation of the intensity 357 | fSd = sqrt(e2_fPdf - e_fPdf.^2); % Population standard deviation of the intensity 358 | 359 | 360 | jointEntropy = 0; 361 | % JPDF calculation using simplified Nelsen method with joint entropy calculation 362 | if c >= 0 363 | 364 | if c == 0 || bSd == 0 || fSd == 0 365 | phi = 0; 366 | else 367 | covUp = 0; 368 | for i = 1:l 369 | for j = 1:l 370 | % Frechet's upper bound bivariate distributions between f & b 371 | covUp = covUp + 0.5*(fCdf(i)+bCdf(j)-abs(fCdf(i)-bCdf(j))) - fCdf(i).*bCdf(j); 372 | end 373 | end 374 | corrUp = covUp/(fSd*bSd); % Upper correlation between f & b 375 | phi = c/corrUp; 376 | end 377 | 378 | jpdfUp = 0.5*(fCdf(1)+bCdf(1)-abs(fCdf(1)-bCdf(1))); 379 | jpdf = phi.*jpdfUp + (1-phi).*fPdf(1).*bPdf(1); 380 | if jpdf~=0 381 | jointEntropy = real(-jpdf.*log2(jpdf)); % Joint entropy 382 | end 383 | 384 | % 1-D boundaries 385 | for i=2:l 386 | jpdfUp = 0.5*(fCdf(i)+bCdf(1)-abs(fCdf(i)-bCdf(1))) - ... 387 | 0.5*(fCdf(i-1)+bCdf(1)-abs(fCdf(i-1)-bCdf(1))); 388 | jpdf = phi.*jpdfUp + (1-phi).*fPdf(i).*bPdf(1); 389 | if jpdf~=0 390 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 391 | end 392 | end 393 | for j=2:l 394 | jpdfUp = 0.5*(fCdf(1)+bCdf(j)-abs(fCdf(1)-bCdf(j))) - ... 395 | 0.5*(fCdf(1)+bCdf(j-1)-abs(fCdf(1)-bCdf(j-1))); 396 | jpdf = phi.*jpdfUp + (1-phi).*fPdf(1).*bPdf(j); 397 | if jpdf~=0 398 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 399 | end 400 | end 401 | % 2-D walls 402 | for i=2:l 403 | for j=2:l 404 | jpdfUp = 0.5*(fCdf(i)+bCdf(j)-abs(fCdf(i)-bCdf(j))) - ... 405 | 0.5*(fCdf(i-1)+bCdf(j)-abs(fCdf(i-1)-bCdf(j))) - ... 406 | 0.5*(fCdf(i)+bCdf(j-1)-abs(fCdf(i)-bCdf(j-1))) + ... 407 | 0.5*(fCdf(i-1)+bCdf(j-1)-abs(fCdf(i-1)-bCdf(j-1))); 408 | jpdf = phi.*jpdfUp + (1-phi).*fPdf(i).*bPdf(j); 409 | if jpdf~=0 410 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 411 | end 412 | end 413 | end 414 | 415 | end 416 | 417 | if c < 0 418 | 419 | if bSd == 0 || fSd == 0 420 | theta = 0; 421 | else 422 | covLo = 0; 423 | for i = 1:l 424 | for j = 1:l 425 | % Frechet's lower bound bivariate distributions between f & b 426 | covLo = covLo + 0.5*(fCdf(i)+bCdf(j)-1+abs(fCdf(i)+bCdf(j)-1)) - fCdf(i).*bCdf(j); 427 | end 428 | end 429 | corrLo = covLo/(fSd*bSd); % Lower correlation between f & b 430 | theta = c/corrLo; 431 | end 432 | 433 | jpdfLo = 0.5*(fCdf(1)+bCdf(1)-1+abs(fCdf(1)+bCdf(1)-1)); 434 | jpdf = theta.*jpdfLo + (1-theta).*fPdf(1).*bPdf(1); 435 | if jpdf~=0 436 | jointEntropy = real(-jpdf.*log2(jpdf)); % Joint entropy 437 | end 438 | 439 | % 1-D boundaries 440 | for i=2:l 441 | jpdfLo = 0.5*(fCdf(i)+bCdf(1)-1+abs(fCdf(i)+bCdf(1)-1)) - ... 442 | 0.5*(fCdf(i-1)+bCdf(1)-1+abs(fCdf(i-1)+bCdf(1)-1)); 443 | jpdf = theta.*jpdfLo + (1-theta).*fPdf(i).*bPdf(1); 444 | if jpdf~=0 445 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 446 | end 447 | end 448 | for j=2:l 449 | jpdfLo = 0.5*(fCdf(1)+bCdf(j)-1+abs(fCdf(1)+bCdf(j)-1)) - ... 450 | 0.5*(fCdf(1)+bCdf(j-1)-1+abs(fCdf(1)+bCdf(j-1)-1)); 451 | jpdf = theta.*jpdfLo + (1-theta).*fPdf(1).*bPdf(j); 452 | if jpdf~=0 453 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 454 | end 455 | end 456 | % 2-D walls 457 | for i=2:l 458 | for j=2:l 459 | jpdfLo = 0.5*(fCdf(i)+bCdf(j)-1+abs(fCdf(i)+bCdf(j)-1)) - ... 460 | 0.5*(fCdf(i-1)+bCdf(j)-1+abs(fCdf(i-1)+bCdf(j)-1)) - ... 461 | 0.5*(fCdf(i)+bCdf(j-1)-1+abs(fCdf(i)+bCdf(j-1)-1)) + ... 462 | 0.5*(fCdf(i-1)+bCdf(j-1)-1+abs(fCdf(i-1)+bCdf(j-1)-1)); 463 | jpdf = theta.*jpdfLo + (1-theta).*fPdf(i).*bPdf(j); 464 | if jpdf~=0 465 | jointEntropy = jointEntropy + real(-jpdf.*log2(jpdf)); % Joint entropy 466 | end 467 | end 468 | end 469 | 470 | end 471 | 472 | 473 | % Marginal entropies 474 | index = find(bPdf~=0); 475 | bEntropy = sum(-bPdf(index).*log2(bPdf(index))); 476 | index = find(fPdf~=0); 477 | fEntropy = sum(-fPdf(index).*log2(fPdf(index))); 478 | 479 | % Mutual information between b & f 480 | mi = bEntropy + fEntropy - jointEntropy; 481 | 482 | % Overall normalized mutual information 483 | if mi == 0 484 | fmi_bf = 0; 485 | else 486 | fmi_bf = 2.*mi./(bEntropy+fEntropy); 487 | end 488 | 489 | end 490 | 491 | fmi_map(p-w,q-w) = (fmi_af + fmi_bf)./2; 492 | 493 | end 494 | end 495 | 496 | nfmi = mean2(fmi_map); 497 | 498 | 499 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 500 | 501 | function imNorm = rerange(im) 502 | 503 | % RERANGE changes the range of images into interval [0,1] 504 | 505 | im = double(im); 506 | 507 | [m,n] = size(im); 508 | 509 | imMax = max(im(:)); 510 | imMin = min(im(:)); 511 | 512 | if imMax == imMin 513 | imNorm = ones(m,n); 514 | else 515 | imNorm = (im - imMin)/(imMax - imMin); 516 | end 517 | -------------------------------------------------------------------------------- /figure/gfdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/figure/gfdf.png -------------------------------------------------------------------------------- /guidedfilter_LKH.m: -------------------------------------------------------------------------------- 1 | function q = guidedfilter_LKH(I, p, r, eps) 2 | % GUIDEDFILTER O(1) time implementation of guided filter. 3 | % 4 | % - guidance image: I (should be a gray-scale/single channel image) 5 | % - filtering input image: p (should be a gray-scale/single channel image) 6 | % - local window radius: r 7 | % - regularization parameter: eps 8 | 9 | [hei, wid] = size(I); 10 | N = boxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels. 11 | 12 | mean_I = boxfilter(I, r) ./ N; 13 | mean_p = boxfilter(p, r) ./ N; 14 | mean_Ip = boxfilter(I.*p, r) ./ N; 15 | cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch. 16 | 17 | mean_II = boxfilter(I.*I, r) ./ N; 18 | var_I = mean_II - mean_I .* mean_I; 19 | 20 | a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper; 21 | b = mean_p - a .* mean_I; % Eqn. (6) in the paper; 22 | 23 | mean_a = boxfilter(a, r) ./ N; 24 | mean_b = boxfilter(b, r) ./ N; 25 | 26 | q = mean_a .* I + mean_b; % Eqn. (8) in the paper; 27 | end -------------------------------------------------------------------------------- /images/01clock1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/01clock1.bmp -------------------------------------------------------------------------------- /images/01clock2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/01clock2.bmp -------------------------------------------------------------------------------- /images/02lab1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/02lab1.bmp -------------------------------------------------------------------------------- /images/02lab2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/02lab2.bmp -------------------------------------------------------------------------------- /images/03desk1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/03desk1.bmp -------------------------------------------------------------------------------- /images/03desk2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/03desk2.bmp -------------------------------------------------------------------------------- /images/04pepsi1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/04pepsi1.bmp -------------------------------------------------------------------------------- /images/04pepsi2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/04pepsi2.bmp -------------------------------------------------------------------------------- /images/06book1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/06book1.bmp -------------------------------------------------------------------------------- /images/06book2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/06book2.bmp -------------------------------------------------------------------------------- /images/lytro-01-A.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/lytro-01-A.jpg -------------------------------------------------------------------------------- /images/lytro-01-B.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/lytro-01-B.jpg -------------------------------------------------------------------------------- /images/lytro-03-A.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/lytro-03-A.jpg -------------------------------------------------------------------------------- /images/lytro-03-B.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/lytro-03-B.jpg -------------------------------------------------------------------------------- /images/lytro-05-A.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/lytro-05-A.jpg -------------------------------------------------------------------------------- /images/lytro-05-B.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/lytro-05-B.jpg -------------------------------------------------------------------------------- /images/toy1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/toy1.bmp -------------------------------------------------------------------------------- /images/toy2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/toy2.bmp -------------------------------------------------------------------------------- /images/toy3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitname/Multi-focus-image-fusion-GFDF/40c2f2596149ede9ef3fab17e38c1174d1b001d9/images/toy3.bmp -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | clear 2 | close all 3 | 4 | %------read images--------- 5 | %[imagename1, imagepath1]=uigetfile('./images/*.jpg;*.bmp;*.png;*.tif;*.tiff;*.pgm;*.gif','Please choose the first input image'); 6 | %A=imread(strcat(imagepath1,imagename1)); 7 | %[imagename2, imagepath2]=uigetfile('./images/*.jpg;*.bmp;*.png;*.tif;*.tiff;*.pgm;*.gif','Please choose the second input image'); 8 | %B=imread(strcat(imagepath2,imagename2)); 9 | 10 | 11 | 12 | A = imread('lytro-03-A.jpg'); 13 | B = imread('lytro-03-B.jpg'); 14 | 15 | A = double(A)/255; 16 | B = double(B)/255; 17 | 18 | if size(A)~=size(B) 19 | error('two images are not the same size.'); 20 | end 21 | 22 | if size(A,3)>1 23 | A_gray=rgb2gray(A); 24 | B_gray=rgb2gray(B); 25 | else 26 | A_gray=A; 27 | B_gray=B; 28 | end 29 | %figure; imshow(A,[]); 30 | %figure; imshow(B,[]); 31 | 32 | %figure; imshow(A_gray,[]); 33 | %figure; imshow(B_gray,[]); 34 | 35 | 36 | [high, with] = size(A_gray); 37 | tic; 38 | % Parameters for Guided Filter 39 | r =5; eps = 0.3; 40 | w =7; 41 | 42 | h = fspecial('average', [w w]); 43 | averA = imfilter(A_gray,h,'replicate'); 44 | averB = imfilter(B_gray,h,'replicate'); 45 | %figure; imshow(averA,[]); 46 | %figure; imshow(averB,[]); 47 | 48 | 49 | smA = abs(A_gray - averA); 50 | smB = abs(B_gray - averB); 51 | figure; imshow(smA,[]); 52 | figure; imshow(smB,[]); 53 | 54 | 55 | gsmA = guidedfilter_LKH(A_gray,smA, r, eps); 56 | gsmB = guidedfilter_LKH(B_gray,smB, r, eps); 57 | figure; imshow(gsmA,[]); 58 | figure; imshow(gsmB,[]); 59 | 60 | 61 | wmap = double(gsmA > gsmB); 62 | figure; imshow(wmap,[]); 63 | 64 | ratio=0.01; 65 | area=ceil(ratio*high*with); 66 | tempMap1=bwareaopen(wmap,area); 67 | tempMap2=1-tempMap1; 68 | tempMap3=bwareaopen(tempMap2,area); 69 | wmap=1-tempMap3; 70 | 71 | mmap = wmap.*A_gray + (1-wmap).*B_gray; 72 | figure; imshow(wmap,[]); 73 | %figure; imshow(mmap,[]); 74 | 75 | gmap = guidedfilter_LKH(mmap,wmap, r, eps); 76 | figure; imshow(gmap,[]); 77 | 78 | % fuse image 79 | if size(A,3)>1 80 | wmap=repmat(wmap,[1 1 3]); 81 | gmap=repmat(gmap,[1 1 3]); 82 | end 83 | IF = A.*wmap + B.*(1-wmap);% Initial fused image 84 | figure; imshow(IF,[]); 85 | F_GF2 = A.*gmap + B.*(1-gmap); 86 | F_GF2 = uint8(F_GF2*255); 87 | t1=toc; 88 | 89 | A = uint8(A*255); 90 | B = uint8(B*255); 91 | 92 | 93 | figure; imshow(F_GF2); 94 | 95 | if size(A,3)>1 96 | F_GF2=rgb2gray(F_GF2); 97 | end 98 | A_gray = uint8(A_gray*255); 99 | B_gray = uint8(B_gray*255); 100 | Eval(1,:)=EvalFusion(A_gray,B_gray,F_GF2); 101 | --------------------------------------------------------------------------------