% [img_out, gamma,gamma_x, gamma_y, c_offset] = stabilize_phase(img, varargin) % Description: adjust phase of the object to be mostly around zero or close % to the provided reference image img_ref and remove linear ramp, phase % offset and if normalize_amplitude==true normalize amplitude to be around 1 % % Method: % 1) if fourier_guess == true and remove_ramp == true, get rough estiamte of the center of FFT and % use it to subtract phase ramp, IT CAN FAIL IF SAMPLE HAS STRONG % AMPLITUDE AND PHASE VARIATION, IT IS NOT ABLE TO USE THE WEIGHTS % 2) if remove_ramp == true, accuratelly refine the phase ramp by weighted % LSQ method, regions were W is small have small importance in the phase % ramp estiamtion. SECOND STEP ASSUMES THAT THE PHASE RAMP IN IMAGE IS % SMALLER THAN 2PI ACROSS THE IMAGE % % Inputs: % **img_orig - complex image to stabilize % **img_ref - complex images used as reference, if empty ones is used % *optional*: % **weights - (array) 0 1 % speed up calculation and make more robust by binning img = utils.binning_2D(img, binning); if ~isscalar(img_ref) || isempty(img_ref) img_ref= utils.binning_2D(img_ref, binning); end if ~isscalar(weights) || isempty(weights) weights= utils.binning_2D(weights, binning); end end %% calculate complex phase difference phase_diff = img_ref .* conj(img); [M,N,~] = size(img); xramp = pi*(linspace(-1,1,M))'; yramp = pi*(linspace(-1,1,N)); if r.fourier_guess && r.remove_ramp %% initial guess based on position of maximum in Fourier domain xcorrmat = ifftshift_2D(abs(ifft2_partial((phase_diff), r.split))).^2; % center of mass seems to be more accurate if the phase FFT has bimodal distribution, now I % take center of mass of regions > 0.5 of xcorr maximum [y,x] = center(max(0,xcorrmat-max(max(xcorrmat))/2), false); x=x-ceil(M/2)-1; y=y-ceil(N/2)-1; c_offset = xramp.*x + yramp.*y; phase_diff = phase_diff.*exp(1i*c_offset); end %% calculate the optimal phase shift gamma = mean2(phase_diff .*weights) ./ mean2(weights); gamma = gamma./abs(gamma); if any(isnan(gamma)); gamma = 1; end if r.remove_ramp phase_diff = phase_diff .* conj(gamma); %% linear refinement phase_diff= angle(phase_diff).*weights; % linearize the problem gamma_x=mean2(phase_diff.*xramp) ./ mean2(weights.*abs(xramp).^2); gamma_y=mean2(phase_diff.*yramp) ./ mean2(weights.*abs(yramp).^2); if r.fourier_guess %% get total correction gamma_x = gamma_x - x; gamma_y = gamma_y - y; end % export dimensionless gamma_x = gamma_x / M; gamma_y = gamma_y / N; %% correct output image xramp = pi*(linspace(-1,1,M0))'; yramp = pi*(linspace(-1,1,N0)); if isa(img_orig, 'gpuArray') xramp = gpuArray(xramp); yramp = gpuArray(yramp); [img_out,c_offset] = arrayfun(@remove_phase,img_orig, xramp, yramp, gamma, gamma_x*M0/binning, gamma_y*N0/binning); else [img_out,c_offset] = remove_phase(img_orig, xramp, yramp, gamma, gamma_x*M0/binning, gamma_y*N0/binning); end else img_out = img_orig .* gamma; c_offset = angle(gamma); end if r.normalize_amplitude mean_amplitude = mean2(weights .* img_out) ./ mean2(weights); img_out = img_out ./ mean_amplitude; end end % auxiliar function for GPU processing (kernel merging) function [img_out,c_offset] = remove_phase(img_orig, xramp, yramp, gamma, gamma_x, gamma_y) %% correct output image c_offset = angle(gamma) + xramp.*gamma_x + yramp.*gamma_y; img_out = img_orig.*exp(1i*c_offset); end