1 function [x,y,verbose] = siepcm(a,b,verbose,threshold,radius)
2 % SIEPCM - estimation of sub-pixel shifts between images using
3 % SVD of phase correlation
6 % a, b - input image data, in Fourier domain with DC centered
7 % verbose - if non-zero, display debug plots and images
8 % thrshold - a percentage of maximum value, used to set initial mask
9 % radius - the width of data to use for LMS fit of phase slopes (<=0.25)
11 if nargin < 3, verbose = 0; end; % plot intermediate images
12 if nargin < 4, threshold = 0.0015; end; % a percentage of max to set mask
13 if nargin < 5, radius = 0.25; end; % size of post-mask radius (<= 0.25)
18 s = abs( a .* conj(b) ); s( s == 0 ) = 1;
19 c = (a .* conj(b)) ./ s; % abs( a .* conj(a) + 1e-10 );
22 s( abs(c) ~= 0 ) = abs(c( abs(c) ~= 0 ));
25 %%%% apply pre-masking here.
27 if exist('radius'), r=radius(1); else, r = 0.3; end;
29 mask = zeros(size(c));
30 t = max(abs(a(:))).*threshold;
32 mask( abs(a) > t ) = 1;
33 mask = medfilt2( mask, [10 10] ); % 2D median filter, from image
35 if (sum(mask(:)) == 0);
36 error(sprintf([' mask in empty. Need to lower the threshold (currently=' ...
40 [u d v]=svds(mask.*c,1);
44 % solve an LMS fit to the angles of the rank one matrix components...
47 %% apply post-masking:
48 t_n = ceil( (0.5-r2)*length(v) ):floor( (0.5+r2)*length(v) );
50 tmp = unwrap( angle(v(t_n)) ); A = [ (t_n-1)' ones(length(t_n),1) ];
52 y = sys_y(1) * n / (2*pi);
53 fullphz1 = unwrap(angle(v));
54 fullphz1 = fullphz1 - fullphz1(floor(n2/2)) + ([floor(n2/2)-1 1]*sys_y);
55 pltcmd1 = '1:length(v), fullphz1, t_n, [ unwrap( angle(v(t_n)) ) ( sys_y(1) * (t_n-1)'' + sys_y(2) ) ]';
57 pltcmd1 = ' 0,0 '; sys_y = [ 0 0]; y = 0;
63 %% apply post-masking:
64 t_m = ceil( (0.5-r2)*length(u) ):floor( (0.5+r2)*length(u) );
66 tmp = unwrap( angle(u(t_m)) ); A = [ (t_m-1)' ones(length(t_m),1) ];
68 x = sys_x(1) * m / (2*pi);
69 fullphz2 = unwrap(angle(u));
70 fullphz2 = fullphz2 - fullphz2(floor(m2/2)) + ([floor(m2/2)-1 1]*sys_x);
71 pltcmd2 = '1:length(u), fullphz2, t_m, [ unwrap( angle(u(t_m)) ) ( sys_x(1) * (t_m-1)'' + sys_x(2) ) ]';
73 pltcmd2 = ' 0, 0 '; sys_x = [ 0 0]; x = 0;
76 % if verbose mode is on, show the estimation quality images
79 disp([ 'plot( ' pltcmd1 ', ''o-'', ' pltcmd2 ', ''*-'');' ]);
80 eval([ 'plot( ' pltcmd1 ', ''o-'', ' pltcmd2 ', ''*-'');' ]);
81 title(' plot of least squares linear fit ');
84 Q = exp( j*2*pi* x * [0:m-1]'/m ) * exp( -j*2*pi* y * [0:n-1]/n );
87 % phase align each of these beasts so that the abs( c - Q ) looks good.
88 mc = floor(m/2); nc = floor(n/2);
89 Q = Q * exp(angle(Q(mc,nc)'*c(mc,nc))*j);
90 q = q * exp(angle(q(mc,nc)'*c(mc,nc))*j);
92 imagesc( angle([ c mask.*c; u*v' Q ]) ); colormap('hsv');
93 title('[ Q | mask \circ Q ; u v^H | est of (u v^H) ]');
95 disp([ ' x_0: ' num2str(x) ' y_0: ' num2str(y) ]);
99 % Copyright 2002-2005 W. Scott Hoge (wsh032580 at proton dot me)
101 % Licensed under the terms of the MIT License
102 % (https://opensource.org/licenses/MIT)