% FIND_SHIFT_FAST_1D uses cross-correlation to find shift between 1D patterns o1 and % o2, if the patterns are 2D, perform the search along the axis `ax` % % shift = find_shift_fast_1D(o1, o2, ax, sigma) % % Inputs: % **o1 - aligned array 1D/2D (will be aligned along 1st axis) % **o2 - template for alignment 1D or 2D % **ax - perform search along this axis % *optional* % **sigma - filtering intensity [0-1 range], sigma <= 0 no filtering, recommended sigma < 0.05 % **padding - pading [in pixels] the provided array by zeros, prevent circular boundary condition in FFT, default = 0 % *returns* % ++shift - (vector) displacement of the 1D/2D arrays %*-----------------------------------------------------------------------* %|                                                                       | %|  Except where otherwise noted, this work is licensed under a          | %|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            | %|  International (CC BY-NC-SA 4.0) license.                             | %|                                                                       | %|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    | %|                                                                       | %|      Author: CXS group, PSI  | %*-----------------------------------------------------------------------* % You may use this code with the following provisions: % % If the code is fully or partially redistributed, or rewritten in another % computing language this notice should be included in the redistribution. % % If this code, or subfunctions or parts of it, is used for research in a % publication or if it is fully or partially rewritten for another % computing language the authors and institution should be acknowledged % in written form in the publication: “Data processing was carried out % using the “cSAXS matlab package” developed by the CXS group, % Paul Scherrer Institut, Switzerland.” % Variations on the latter text can be incorporated upon discussion with % the CXS group if needed to more specifically reflect the use of the package % for the published work. % % A publication that focuses on describing features, or parameters, that % are already existing in the code should be first discussed with the % authors. % % This code and subroutines are part of a continuous development, they % are provided “as they are” without guarantees or liability on part % of PSI or the authors. It is the user responsibility to ensure its % function shift = find_shift_fast_1D(o1, o2, ax, sigma, padding) if nargin < 3 ax = 2; end if nargin < 4 sigma = 0; end if nargin < 5 padding = 0; else padding = ceil(padding/2)*2; end max_shift = size(o1,ax)/3; % avoid too large corrections !!! Ndims = ndims(o1); if ax ~= 1 error('FIXME: Not tested axis') end %% symmetrize before spectral filtering !! o1 = cat(ax, o1, flipud(o1)); o2 = cat(ax, o2, flipud(o2)); Npix = size(o1); shape = ones(1,Ndims); shape(ax) = Npix(ax); if sigma > 0 %% high pass filter o1 = fft(o1, [],ax); o2 = fft(o2, [],ax); x = reshape((-Npix(ax)/2+1:Npix(ax)/2)/Npix(ax), shape); spectral_filter = fftshift(exp(1./(-(x.^2)/(sigma^2)))); spectral_filter(floor(end/2+[-3:3])) = 0; %% remove some strange artefacts o1 = bsxfun(@times, o1, spectral_filter); o2 = bsxfun(@times, o2, spectral_filter); o1 = ifft(o1, [],ax); o2 = ifft(o2, [],ax); end % remove symetrization !! o1 = o1(1:end/2,:); o2 = o2(1:end/2,:); o1 = padarray(o1, padding/2, 'both'); o2 = padarray(o2, padding/2, 'both'); Npix = size(o1); shape = ones(1,Ndims); shape(ax) = Npix(ax); %% remove edge issues (after symetrized filtering ) spatial_filter = reshape(tukeywin(prod(shape)), shape); o1 = bsxfun(@times, o1, spatial_filter); o2 = bsxfun(@times, o2, spatial_filter); o1 = fft(o1, [],ax); o2 = fft(o2, [],ax); %% cross-correlation xcorrmat = abs(ifft(o1.*conj(o2),[],ax)); %% 1D fftshift xcorrmat = circshift(xcorrmat, floor(Npix(ax)/2), ax); if ax == 2; error('FIXME: Not tested axis'); end % choose only optimim withing reduced range xcorrmat([1:ceil(end/2-max_shift), ceil(end/2+max_shift):end],:) = 0; %% take only small region around maximum WIN = 10; kernel_size = [1,1]; kernel_size(ax) = WIN; mask = conv2(single(bsxfun(@eq, xcorrmat, max(xcorrmat,[],ax))), ones(kernel_size), 'same'); xcorrmat(~mask) = nan; xcorrmat = max(0, bsxfun(@minus, xcorrmat, min(xcorrmat,[],ax))); xcorrmat(~mask) = 0; xcorrmat = bsxfun(@times, xcorrmat, 1./max(xcorrmat,[],ax)).^4; %% find center of mass MASS = sum(xcorrmat,ax); grid = reshape(1:Npix(ax),shape); shift = sum(bsxfun(@times, xcorrmat, grid),ax) ./ MASS - floor(Npix(ax)/2)-1; end