Files
fold_slice/tomo/utils/findmask.m
T
2026-08-07 15:56:42 +09:00

850 lines
32 KiB
Matlab
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
% 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