% Usage % This function can be used standalone using "Load stack" % Can also be run from a script with optional inputs % [stack_phase_corr mask] = findmask(stack_object) % Inputs % stack_object - Stack of complex valued projections % Outputs % stack_phase_corr - Stack of corrected complex valued projections % mask - Mask used for correction % Manuel Guizar, Cameron Kewish 2012-10-25 %*-----------------------------------------------------------------------* %|                                                                       | %|  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 % proper use and the correctness of the results. function varargout = findmask(varargin) % FINDMASK MATLAB code for findmask.fig % FINDMASK, by itself, creates a new FINDMASK or raises the existing % singleton*. % % H = FINDMASK returns the handle to a new FINDMASK or the handle to % the existing singleton*. % % FINDMASK('CALLBACK',hObject,eventData,handles,...) calls the local % function named CALLBACK in FINDMASK.M with the given input arguments. % % FINDMASK('Property','Value',...) creates a new FINDMASK or raises the % existing singleton*. Starting from the left, property value pairs are % applied to the GUI before findmask_OpeningFcn gets called. An % unrecognized property name or invalid value makes property application % stop. All inputs are passed to findmask_OpeningFcn via varargin. % % *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one % instance to run (singleton)". % % See also: GUIDE, GUIDATA, GUIHANDLES % Edit the above text to modify the response to help findmask % Last Modified by GUIDE v2.5 25-Oct-2012 15:54:12 % Begin initialization code - DO NOT EDIT gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @findmask_OpeningFcn, ... 'gui_OutputFcn', @findmask_OutputFcn, ... 'gui_LayoutFcn', [] , ... 'gui_Callback', []); if nargin && ischar(varargin{1}) gui_State.gui_Callback = str2func(varargin{1}); end if nargout [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); else gui_mainfcn(gui_State, varargin{:}); end % End initialization code - DO NOT EDIT % --- Executes just before findmask is made visible. function findmask_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % varargin command line arguments to findmask (see VARARGIN) % Choose default command line output for findmask handles.output = hObject; %%%% Initialization with variable %%% if nargin >= 4 handles.stack_object = varargin{1}; if numel(varargin)>1 handles.mask_ramp = varargin{2}; end if ~isfield(handles,'mask_ramp') handles.mask_ramp = logical(handles.stack_object*0); else if ~all(size(handles.stack_object) == size(handles.mask_ramp)) msgbox('Size of mask and projections does not match','Wrong mask','error') end end handles.corrected = ones(size(handles.stack_object,3),1); handles.see_mask_only = get(handles.checkbox_see_mask_only,'Value'); handles.projnum = 1; handles.linecut = round(size(handles.stack_object,1)/2); clear stack_object set(handles.edit_line,'String',num2str(handles.linecut)) handles.region_select = handles.stack_object(:,:,handles.projnum)*0; show_image(handles) %%% Make shape %%% set(handles.make_square,'Enable','on') set(handles.make_poly,'Enable','on') %%% Save %%% set(handles.save_stack,'Enable','on') set(handles.save_mask,'Enable','on') set(handles.return_to_script,'Enable','on') %%% Display %%% set(handles.edit1,'Enable','on') set(handles.prev_proj,'Enable','on') set(handles.stop_button,'Enable','on') set(handles.play,'Enable','on') set(handles.next_proj,'Enable','on') set(handles.edit_line,'Enable','on') set(handles.checkbox_see_mask_only,'Enable','on') end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Update handles structure guidata(hObject, handles); % UIWAIT makes findmask wait for user response (see UIRESUME) % uiwait(handles.figure1); % --- Outputs from this function are returned to the command line. function varargout = findmask_OutputFcn(hObject, eventdata, handles) % varargout cell array for returning output args (see VARARGOUT); % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Get default command line output from handles structure varargout{1} = handles.output; % --- Executes on button press in load_stack. function load_stack_Callback(hObject, eventdata, handles) % hObject handle to load_stack (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) [handles.stack_filename handles.stack_path Filterindex] = uigetfile('*.mat'); load([handles.stack_path handles.stack_filename]); handles.stack_object = stack_object; if ~exist('stack_object') msgbox('Variable stack_object does not exist in the file','Variable not found','error') end if ~isfield(handles,'mask_ramp') handles.mask_ramp = logical(stack_object*0); else if ~all(size(handles.stack_object) == size(handles.mask_ramp)) msgbox('Size of mask and projections does not match','Wrong mask','error') end end handles.corrected = ones(size(stack_object,3),1); handles.see_mask_only = get(handles.checkbox_see_mask_only,'Value'); handles.projnum = 1; handles.linecut = round(size(stack_object,1)/2); clear stack_object set(handles.edit_line,'String',num2str(handles.linecut)) handles.region_select = handles.stack_object(:,:,handles.projnum)*0; show_image(handles) %%% Make shape %%% set(handles.make_square,'Enable','on') set(handles.make_poly,'Enable','on') %%% Save %%% set(handles.save_stack,'Enable','on') set(handles.save_mask,'Enable','on') %%% Display %%% set(handles.edit1,'Enable','on') set(handles.prev_proj,'Enable','on') set(handles.stop_button,'Enable','on') set(handles.play,'Enable','on') set(handles.next_proj,'Enable','on') set(handles.edit_line,'Enable','on') set(handles.checkbox_see_mask_only,'Enable','on') %%%%%%%%%%%%%%% % save the changes to the structure guidata(hObject,handles) % --- Executes on button press in load_mask. function load_mask_Callback(hObject, eventdata, handles) % hObject handle to load_mask (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) [handles.mask_filename handles.mask_path Filterindex] = uigetfile('*.mat'); load([handles.mask_path handles.mask_filename]); if ~exist('mask') msgbox('Variable mask does not exist in the file','Variable not found','error') end handles.mask_ramp = mask; if isfield(handles,'stack_object') if ~all(size(handles.stack_object) == size(handles.mask_ramp)) msgbox('Size of mask and projections do not match','Wrong mask','error') end end handles.corrected = zeros(size(handles.mask_ramp,3),1); handles.projnum = 1; clear mask_ramp handles.region_select = handles.mask_ramp(:,:,handles.projnum)*0; if isfield(handles,'stack_object') show_image(handles) end enable_mask_panel(hObject, handles) enable_ramp_panel(hObject, handles) % save the changes to the structure guidata(hObject,handles) % --- Executes on button press in save_stack. function save_stack_Callback(hObject, eventdata, handles) % hObject handle to save_stack (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) if any(handles.corrected == 0) msgbox('Mask has not been applied to all projections. Not saving.','Current mask not applied yet','warn') else stack_object = handles.stack_object; if isfield(handles,'stack_path') uisave('stack_object',[handles.stack_path 'phase_corr_' handles.stack_filename]); else uisave('stack_object',['phase_corr_.mat']); end end % --- Executes on button press in save_mask. function save_mask_Callback(hObject, eventdata, handles) % hObject handle to save_mask (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) mask = handles.mask_ramp; if isfield(handles,'stack_path') uisave('mask',[handles.stack_path 'mask_' handles.stack_filename]); else uisave('mask',['mask_.mat']); end % --- Executes on button press in return_to_script. function varargout = return_to_script_Callback(hObject, eventdata, handles) % hObject handle to return_to_script (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) if any(handles.corrected == 0) msgbox('Mask has not been applied to all projections. Not ready to return to script.','Current mask not applied yet','warn') else msgbox('Load variable from script and close figure.','Exit to script','help') end %%%%%%%%%%%%%%%%%%% %%% Make mask %%% %%%%%%%%%%%%%%%%%%% % --- Executes on button press in make_square. function make_square_Callback(hObject, eventdata, handles) % hObject handle to make_square (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) set(handles.figure_text,'string','Click on two corners of the desired rectangle',... 'foregroundcolor',[0 0 1]) set(gcf,'CurrentAxes',handles.axes_phase) [x y] = ginput(2); hold on, plot([x(1) x(1)],[y(1) y(2)]) plot([x(2) x(2)],[y(1) y(2)]) plot([x(1) x(2)],[y(1) y(1)]) plot([x(1) x(2)],[y(2) y(2)]) hold off, x = round(x); y = round(y); handles.region_select = handles.region_select*0; handles.region_select(min(y):max(y),min(x):max(x)) = 1; set(handles.figure_text,'string','Choose to add or remove from mask',... 'foregroundcolor',[0 0 1]) enable_mask_panel(hObject, handles) enable_ramp_panel(hObject, handles) % save the changes to the structure guidata(hObject,handles) % --- Executes on button press in make_poly. function make_poly_Callback(hObject, eventdata, handles) % hObject handle to make_poly (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % h = msgbox(['Please click on the image to choose the corners ' ... % 'of the polygon ROI. When finished, double-click the last vertex to ' ... % 'close the polygon.'], 'Make Poly', 'help'); set(handles.figure_text,'string','Click closed polygon corners. Double-click when done',... 'foregroundcolor',[0 0 1]) set(gcf,'CurrentAxes',handles.axes_phase) [handles.region_select x y] = roipoly; % do we want to plot the roi border? hold on, plot(x,y) hold off, set(handles.figure_text,'string','Choose to add or remove from mask',... 'foregroundcolor',[0 0 1]) enable_mask_panel(hObject, handles) enable_ramp_panel(hObject, handles) % save the changes to the structure guidata(hObject,handles) % --- Executes on button press in next_proj. function next_proj_Callback(hObject, eventdata, handles) % hObject handle to next_proj (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.projnum = min(handles.projnum + 1,size(handles.stack_object,3)); show_image(handles); % save the changes to the structure guidata(hObject,handles); % --- Executes on button press in prev_proj. function prev_proj_Callback(hObject, eventdata, handles) % hObject handle to prev_proj (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.projnum = max(handles.projnum - 1,1); show_image(handles); % save the changes to the structure guidata(hObject,handles); function edit1_Callback(hObject, eventdata, handles) % hObject handle to edit1 (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of edit1 as text % str2double(get(hObject,'String')) returns contents of edit1 as a double handles.projnum = str2double(get(hObject,'String')); show_image(handles) % save the changes to the structure guidata(hObject,handles) % --- Executes during object creation, after setting all properties. function edit1_CreateFcn(hObject, eventdata, handles) % hObject handle to edit1 (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end % --- Executes on button press in play. function play_Callback(hObject, eventdata, handles) % hObject handle to play (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % persistent playmovie % playmovie = true; ii = handles.projnum; handles.playmovie = true; guidata(hObject,handles); % % while playmovie while handles.playmovie handles = guidata(hObject); % display(handles.playmovie) handles.projnum = ii; if ii == size(handles.stack_object,3) ii = 1; else ii = ii + 1; end show_image(handles); pause(0.2) end % save the changes to the structure guidata(hObject,handles); % --- Executes on button press in stop_button. function stop_button_Callback(hObject, eventdata, handles) % hObject handle to stop_button (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % persistent playmovie % playmovie = false; handles.playmovie = false; % display('Trying to stop movie') % save the changes to the structure guidata(hObject,handles) %%%%%%%%%%%%%%%%%%%%%%%%% %%% Mask Operations %%% %%%%%%%%%%%%%%%%%%%%%%%%% % --- Executes on button press in add_to_mask. function add_to_mask_Callback(hObject, eventdata, handles) % hObject handle to add_to_mask (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.mask_ramp(:,:,handles.projnum) = handles.mask_ramp(:,:,handles.projnum)|handles.region_select; handles.corrected(handles.projnum) = 0; show_image(handles) % save the changes to the structure guidata(hObject,handles) % --- Executes on button press in remove_from_mask. function remove_from_mask_Callback(hObject, eventdata, handles) % hObject handle to remove_from_mask (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.mask_ramp(:,:,handles.projnum) = handles.mask_ramp(:,:,handles.projnum)&(1-handles.region_select); handles.corrected(handles.projnum) = 0; show_image(handles) % save the changes to the structure guidata(hObject,handles) % --- Executes on button press in add_toall_masks. function add_toall_masks_Callback(hObject, eventdata, handles) % hObject handle to add_toall_masks (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) for ii = 1:size(handles.stack_object,3) handles.mask_ramp(:,:,ii) = handles.mask_ramp(:,:,ii)|handles.region_select; end handles.corrected = zeros(size(handles.stack_object,3),1); show_image(handles) % save the changes to the structure guidata(hObject,handles) % --- Executes on button press in remove_fromall_masks. function remove_fromall_masks_Callback(hObject, eventdata, handles) % hObject handle to remove_fromall_masks (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) for ii = 1:size(handles.stack_object,3) handles.mask_ramp(:,:,ii) = handles.mask_ramp(:,:,ii)&(1-handles.region_select); end handles.corrected = zeros(size(handles.stack_object,3),1); show_image(handles) % save the changes to the structure guidata(hObject,handles) %%%%%%%%%%%%%%%%%%%%%% %%% Ramp removal %%% %%%%%%%%%%%%%%%%%%%%%% % --- Executes on button press in apply_removal_current. function apply_removal_current_Callback(hObject, eventdata, handles) % hObject handle to apply_removal_current (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) set(handles.figure_text,'String',['Removing offset on projection ' ... num2str(handles.projnum) ' ...'],... 'foregroundcolor',[0 0 1]) upsamp = 100; % [handles.stack_object(:,:,handles.projnum) errorm] = utils.remove_linearphase(handles.stack_object(:,:,handles.projnum),handles.mask_ramp(:,:,handles.projnum),upsamp); [handles.stack_object(:,:,handles.projnum) errorm] = utils.remove_linearphase(exp(1i*angle(handles.stack_object(:,:,handles.projnum))),handles.mask_ramp(:,:,handles.projnum),upsamp); handles.corrected(handles.projnum) = 1; % save the changes to the structure guidata(hObject,handles) show_image(handles) % --- Executes on button press in apply_removal_all. function apply_removal_all_Callback(hObject, eventdata, handles) % hObject handle to apply_removal_all (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) upsamp = 100; hwait = waitbar(0,'Patience is a virtue'); tmp = handles.stack_object; tmpmask = handles.mask_ramp; % CMK: Added a parfor loop to save time here, but it broke the "Patience" waitbar... % if isempty(gcp('nocreate')) == 0 % parpool % end parfor ii = 1:size(tmp,3) [tmp(:,:,ii) errorm] = utils.remove_linearphase(tmp(:,:,ii),tmpmask(:,:,ii), upsamp); display(ii) end handles.stack_object = tmp; % for ii = 1:size(handles.stack_object,3) % set(handles.figure_text,'String',['Removing offset on projection ' ... % num2str(ii) ' ...'],... % 'foregroundcolor',[0 0 1]) % guidata(hObject,handles) % if ~handles.corrected(ii) % [handles.stack_object(:,:,ii) errorm] = utils.remove_linearphase(handles.stack_object(:,:,ii),handles.mask_ramp(:,:,ii),upsamp); % handles.corrected(ii) == 1; % end % waitbar(ii/size(handles.stack_object,3),hwait); % end close(hwait) handles.corrected = ones(size(handles.stack_object,3),1); show_image(handles) % save the changes to the structure guidata(hObject,handles) function edit_line_Callback(hObject, eventdata, handles) % hObject handle to edit_line (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of edit_line as text % str2double(get(hObject,'String')) returns contents of edit_line as a double handles.linecut = str2double(get(hObject,'String')); show_image(handles) % save the changes to the structure guidata(hObject,handles) % --- Executes during object creation, after setting all properties. function edit_line_CreateFcn(hObject, eventdata, handles) % hObject handle to edit_line (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end % --- Executes on button press in checkbox_see_mask_only. function checkbox_see_mask_only_Callback(hObject, eventdata, handles) % hObject handle to checkbox_see_mask_only (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) handles.see_mask_only = get(handles.checkbox_see_mask_only,'Value'); show_image(handles); % Hint: get(hObject,'Value') returns toggle state of checkbox_see_mask_only % save the changes to the structure guidata(hObject,handles) function enable_mask_panel(hObject, handles) set(handles.add_to_mask, 'Enable','on') set(handles.add_toall_masks, 'Enable','on') set(handles.remove_from_mask, 'Enable','on') set(handles.remove_fromall_masks,'Enable','on') % save the changes to the structure guidata(hObject,handles) function enable_ramp_panel(hObject, handles) set(handles.apply_removal_current,'Enable','on') set(handles.apply_removal_all, 'Enable','on') % save the changes to the structure guidata(hObject,handles) function show_image(handles) phase_plot = angle(handles.stack_object(:,:,handles.projnum)); min_phaseplot = min(phase_plot(:)); max_phaseplot = max(phase_plot(:)); phase_plot = phase_plot - min_phaseplot; phase_plot = phase_plot.*(handles.mask_ramp(:,:,handles.projnum) + ... 0.5*(~handles.mask_ramp(:,:,handles.projnum)))+min_phaseplot; % handles.axes_phase = imagesc(phase_plot); %%% set(gcf,'CurrentAxes',handles.axes_phase); if ~handles.see_mask_only imagesc(phase_plot); caxis([min_phaseplot max_phaseplot]); else imagesc(phase_plot.*handles.mask_ramp(:,:,handles.projnum)); end axis xy equal tight colormap bone %%% set(gcf,'CurrentAxes',handles.axes_linecut); plot(angle(handles.stack_object(handles.linecut,:,handles.projnum))); xlim([1 size(handles.stack_object,2)]); grid on %%% set(handles.figure_text,'String', ... ['Projection ' num2str(handles.projnum)],'foregroundcolor',[0 0 0]) %%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Auxiliary functions %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% function [output Greg] = dftregistration(buf1ft,buf2ft,usfac) % function [output Greg] = dftregistration(buf1ft,buf2ft,usfac); % Efficient subpixel image registration by crosscorrelation. This code % gives the same precision as the FFT upsampled cross correlation in a % small fraction of the computation time and with reduced memory % requirements. It obtains an initial estimate of the crosscorrelation peak % by an FFT and then refines the shift estimation by upsampling the DFT % only in a small neighborhood of that estimate by means of a % matrix-multiply DFT. With this procedure all the image points are used to % compute the upsampled crosscorrelation. % Manuel Guizar - Dec 13, 2007 % Portions of this code were taken from code written by Ann M. Kowalczyk % and James R. Fienup. % J.R. Fienup and A.M. Kowalczyk, "Phase retrieval for a complex-valued % object by using a low-resolution image," J. Opt. Soc. Am. A 7, 450-458 % (1990). % Citation for this algorithm: % Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup, % "Efficient subpixel image registration algorithms," Opt. Lett. 33, % 156-158 (2008). % Inputs % buf1ft Fourier transform of reference image, % DC in (1,1) [DO NOT FFTSHIFT] % buf2ft Fourier transform of image to register, % DC in (1,1) [DO NOT FFTSHIFT] % usfac Upsampling factor (integer). Images will be registered to % within 1/usfac of a pixel. For example usfac = 20 means the % images will be registered within 1/20 of a pixel. (default = 1) % Outputs % output = [error,diffphase,net_row_shift,net_col_shift] % error Translation invariant normalized RMS error between f and g % diffphase Global phase difference between the two images (should be % zero if images are non-negative). % net_row_shift net_col_shift Pixel shifts between images % Greg (Optional) Fourier transform of registered version of buf2ft, % the global phase difference is compensated for. % Default usfac to 1 if exist('usfac')~=1, usfac=1; end % Compute error for no pixel shift if usfac == 0, CCmax = sum(sum(buf1ft.*conj(buf2ft))); rfzero = sum(abs(buf1ft(:)).^2); rgzero = sum(abs(buf2ft(:)).^2); error = 1.0 - CCmax.*conj(CCmax)/(rgzero*rfzero); error = sqrt(abs(error)); diffphase=atan2(imag(CCmax),real(CCmax)); output=[error,diffphase]; % Whole-pixel shift - Compute crosscorrelation by an IFFT and locate the % peak elseif usfac == 1, [m,n]=size(buf1ft); CC = ifft2(buf1ft.*conj(buf2ft)); [max1,loc1] = max(CC); [max2,loc2] = max(max1); rloc=loc1(loc2); cloc=loc2; CCmax=CC(rloc,cloc); rfzero = sum(abs(buf1ft(:)).^2)/(m*n); rgzero = sum(abs(buf2ft(:)).^2)/(m*n); error = 1.0 - CCmax.*conj(CCmax)/(rgzero(1,1)*rfzero(1,1)); error = sqrt(abs(error)); diffphase=atan2(imag(CCmax),real(CCmax)); md2 = fix(m/2); nd2 = fix(n/2); if rloc > md2 row_shift = rloc - m - 1; else row_shift = rloc - 1; end if cloc > nd2 col_shift = cloc - n - 1; else col_shift = cloc - 1; end output=[error,diffphase,row_shift,col_shift]; % Partial-pixel shift else % First upsample by a factor of 2 to obtain initial estimate % Embed Fourier data in a 2x larger array [m,n]=size(buf1ft); mlarge=m*2; nlarge=n*2; CC=zeros(mlarge,nlarge); CC(m+1-fix(m/2):m+1+fix((m-1)/2),n+1-fix(n/2):n+1+fix((n-1)/2)) = ... fftshift(buf1ft).*conj(fftshift(buf2ft)); % Compute crosscorrelation and locate the peak CC = ifft2(ifftshift(CC)); % Calculate cross-correlation [max1,loc1] = max(CC); [max2,loc2] = max(max1); rloc=loc1(loc2);cloc=loc2; CCmax=CC(rloc,cloc); % Obtain shift in original pixel grid from the position of the % crosscorrelation peak [m,n] = size(CC); md2 = fix(m/2); nd2 = fix(n/2); if rloc > md2 row_shift = rloc - m - 1; else row_shift = rloc - 1; end if cloc > nd2 col_shift = cloc - n - 1; else col_shift = cloc - 1; end row_shift=row_shift/2; col_shift=col_shift/2; % If upsampling > 2, then refine estimate with matrix multiply DFT if usfac > 2, %%% DFT computation %%% % Initial shift estimate in upsampled grid row_shift = round(row_shift*usfac)/usfac; col_shift = round(col_shift*usfac)/usfac; dftshift = fix(ceil(usfac*1.5)/2); %% Center of output array at dftshift+1 % Matrix multiply DFT around the current shift estimate CC = conj(dftups(buf2ft.*conj(buf1ft),ceil(usfac*1.5),ceil(usfac*1.5),usfac,... dftshift-row_shift*usfac,dftshift-col_shift*usfac))/(md2*nd2*usfac^2); % Locate maximum and map back to original pixel grid [max1,loc1] = max(CC); [max2,loc2] = max(max1); rloc = loc1(loc2); cloc = loc2; CCmax = CC(rloc,cloc); rg00 = dftups(buf1ft.*conj(buf1ft),1,1,usfac)/(md2*nd2*usfac^2); rf00 = dftups(buf2ft.*conj(buf2ft),1,1,usfac)/(md2*nd2*usfac^2); rloc = rloc - dftshift - 1; cloc = cloc - dftshift - 1; row_shift = row_shift + rloc/usfac; col_shift = col_shift + cloc/usfac; % If upsampling = 2, no additional pixel shift refinement else rg00 = sum(sum( buf1ft.*conj(buf1ft) ))/m/n; rf00 = sum(sum( buf2ft.*conj(buf2ft) ))/m/n; end error = 1.0 - CCmax.*conj(CCmax)/(rg00*rf00); error = sqrt(abs(error)); diffphase=atan2(imag(CCmax),real(CCmax)); % If its only one row or column the shift along that dimension has no % effect. We set to zero. if md2 == 1, row_shift = 0; end if nd2 == 1, col_shift = 0; end output=[error,diffphase,row_shift,col_shift]; end % Compute registered version of buf2ft if (nargout > 1)&&(usfac > 0), [nr,nc]=size(buf2ft); Nr = ifftshift([-fix(nr/2):ceil(nr/2)-1]); Nc = ifftshift([-fix(nc/2):ceil(nc/2)-1]); [Nc,Nr] = meshgrid(Nc,Nr); Greg = buf2ft.*exp(i*2*pi*(-row_shift*Nr/nr-col_shift*Nc/nc)); Greg = Greg*exp(i*diffphase); elseif (nargout > 1)&&(usfac == 0) Greg = buf2ft*exp(i*diffphase); end return function out=dftups(in,nor,noc,usfac,roff,coff) % function out=dftups(in,nor,noc,usfac,roff,coff); % Upsampled DFT by matrix multiplies, can compute an upsampled DFT in just % a small region. % usfac Upsampling factor (default usfac = 1) % [nor,noc] Number of pixels in the output upsampled DFT, in % units of upsampled pixels (default = size(in)) % roff, coff Row and column offsets, allow to shift the output array to % a region of interest on the DFT (default = 0) % Recieves DC in upper left corner, image center must be in (1,1) % Manuel Guizar - Dec 13, 2007 % Modified from dftus, by J.R. Fienup 7/31/06 % This code is intended to provide the same result as if the following % operations were performed % - Embed the array "in" in an array that is usfac times larger in each % dimension. ifftshift to bring the center of the image to (1,1). % - Take the FFT of the larger array % - Extract an [nor, noc] region of the result. Starting with the % [roff+1 coff+1] element. % It achieves this result by computing the DFT in the output array without % the need to zeropad. Much faster and memory efficient than the % zero-padded FFT approach if [nor noc] are much smaller than [nr*usfac nc*usfac] [nr,nc]=size(in); % Set defaults if exist('roff')~=1, roff=0; end if exist('coff')~=1, coff=0; end if exist('usfac')~=1, usfac=1; end if exist('noc')~=1, noc=nc; end if exist('nor')~=1, nor=nr; end % Compute kernels and obtain DFT by matrix products kernc=exp((-i*2*pi/(nc*usfac))*( ifftshift([0:nc-1]).' - floor(nc/2) )*( [0:noc-1] - coff )); kernr=exp((-i*2*pi/(nr*usfac))*( [0:nor-1].' - roff )*( ifftshift([0:nr-1]) - floor(nr/2) )); out=kernr*in*kernc; return