mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-17 22:59:07 +09:00
initial commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
% CROP_PAD adjusts the size by zero padding or cropping
|
||||
% Inputs:
|
||||
% **img input image
|
||||
% **outsize size of final image
|
||||
% *optional:*
|
||||
% **fill value to fill padded regions
|
||||
% returns:
|
||||
% ++imout cropped image
|
||||
|
||||
|
||||
function [ imout ] = crop_pad( img, outsize, fill)
|
||||
|
||||
if nargin < 1
|
||||
fprintf('CROP_PAD: adjusts the size by zero padding or cropping\n');
|
||||
fprintf('crop_pad(img, outsize)\n');
|
||||
return
|
||||
end
|
||||
|
||||
Nin = size(img);
|
||||
|
||||
if isempty(outsize) || all(outsize(1:2) == Nin(1:2))
|
||||
imout = img; % if outsize == [], return the same image without changes
|
||||
return
|
||||
end
|
||||
|
||||
Nout = outsize(1:2);
|
||||
|
||||
if nargin < 3
|
||||
fill = 0;
|
||||
end
|
||||
|
||||
|
||||
|
||||
center = floor(Nin(1:2)/2)+1;
|
||||
|
||||
imout = zeros([Nout,Nin(3:end)],'like',img);
|
||||
|
||||
if fill ~= 0
|
||||
imout = imout + fill;
|
||||
end
|
||||
|
||||
centerout = floor(Nout/2)+1;
|
||||
|
||||
cenout_cen = centerout - center;
|
||||
imout(max(cenout_cen(1)+1,1):min(cenout_cen(1)+Nin(1),Nout(1)),max(cenout_cen(2)+1,1):min(cenout_cen(2)+Nin(2),Nout(2)),:,:) ...
|
||||
= img(max(-cenout_cen(1)+1,1):min(-cenout_cen(1)+Nout(1),Nin(1)),max(-cenout_cen(2)+1,1):min(-cenout_cen(2)+Nout(2),Nin(2)),:,:);
|
||||
|
||||
if ~isreal(img)
|
||||
imout = complex(imout);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
function [wav,wavA] = electronwavelength(kev)
|
||||
%wavelength in a0
|
||||
a0 = 0.52917720859;
|
||||
wav = 12.3986./sqrt((2*511.0+kev).*kev)/a0;
|
||||
wavA = wav*a0;
|
||||
end
|
||||
@@ -0,0 +1,523 @@
|
||||
%IMAGESC3D 3D wrapper for imagesc
|
||||
% imagesc3D supports the same parameters as Matlab's imagesc. In addition, the following
|
||||
% parameters can be set
|
||||
%
|
||||
% init_frame... starting frame number (default 1)
|
||||
% slider_axis... axis along which you want to use imagesc (default 3)
|
||||
% fps... frames per second (default 25); will be adjusted by a factor of 1.2 to account for internal overhead
|
||||
% title_list... individual title for each frame (default {})
|
||||
% loop... run in a loop (default false)
|
||||
% reset_frame... stop resets frame to init_frame (default false)
|
||||
% autoplay... stark movie automatically (default false)
|
||||
% slider_position... slider position [left bottom width height] (default center of axis)
|
||||
% play_position... play button position [left bottom width height]
|
||||
% edit_position... edit box position [left bottom width height]
|
||||
% show_play_button... show/hide button; needs to be visible if loop=true; (default true)
|
||||
% show_edit_box... show/hide box
|
||||
% fnct... data processing function
|
||||
% order... change slice order in stack
|
||||
% save_movie... specify filename if a movie shall be written
|
||||
% movie_quality... image quality of the saved movie
|
||||
%
|
||||
% Complex images will be converted to RGB using c2image.
|
||||
%
|
||||
% If you are not using 'autplay', you can also set a global title instead
|
||||
% of a title list (similar to imagesc) and use '%d' to get the slice number
|
||||
% title('Random block - slice %d')
|
||||
%
|
||||
%
|
||||
% EXAMPLES:
|
||||
% imagesc3D(rand(256, 256, 100), 'fps', 10, 'loop', true)
|
||||
% imagesc3D(rand(256, 256)*1j)
|
||||
% imagesc3D(rand(20, 256, 256), 'slider_axis', 1);
|
||||
%
|
||||
%
|
||||
% Additionally, you can use imagesc/imagesc3D routines and trigger the movie by
|
||||
% calling the play method of a specified axis:
|
||||
%
|
||||
% figure(1);
|
||||
% imagesc3D(rand(256, 256, 100), 'fps', 20);
|
||||
% title('Random block - slice %d');
|
||||
% colorbar();
|
||||
% ax = gca;
|
||||
% ax.play();
|
||||
%
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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 imagesc3D(varargin)
|
||||
%import math.isint
|
||||
%import plotting.c2image
|
||||
|
||||
ax_img = {};
|
||||
if nargin == 1
|
||||
img = varargin{1};
|
||||
vararg = {};
|
||||
elseif nargin == 3 && isnumeric(varargin{1}) && isnumeric(varargin{2}) && (islogical(varargin{3}) || isnumeric(varargin{3}))
|
||||
img = varargin{3};
|
||||
ax_img = varargin(1:2);
|
||||
vararg = {};
|
||||
elseif (islogical(varargin{1}) || isnumeric(varargin{1})) && ischar(varargin{2})
|
||||
% assume that first argument is images, and next are
|
||||
% string+arguments
|
||||
img = varargin{1};
|
||||
vararg = varargin(2:end);
|
||||
elseif isnumeric(varargin{1}) && isnumeric(varargin{2}) && (islogical(varargin{3}) || isnumeric(varargin{3}))
|
||||
% assume that first two arguments are axis,and third is images, and next are
|
||||
% string+arguments
|
||||
ax_img = varargin(1:2);
|
||||
img = varargin{3};
|
||||
vararg = varargin(4:end);
|
||||
else
|
||||
error('Unknown combination of parameters')
|
||||
end
|
||||
|
||||
ax = gca;
|
||||
pos = ax.Position;
|
||||
slider_default = [pos(1)+pos(3)/2-0.06 pos(2)-0.1 0.14 0.05];
|
||||
play_default = [slider_default(1)-0.1 pos(2)-0.1 0.08 0.05];
|
||||
edit_default = [slider_default(1)+slider_default(3)+0.01 slider_default(2) 0.08 0.05];
|
||||
|
||||
par = inputParser;
|
||||
par.addParameter('fps', 25, @isnumeric) % maximal frame rate
|
||||
par.addParameter('init_frame', 1, @isnumeric) % starting frame number
|
||||
par.addParameter('title_list', {}, @iscell) % list of titles for each frame
|
||||
par.addParameter('slider_axis',3, @isnumeric) % array axis
|
||||
par.addParameter('loop', false, @islogical) % loop
|
||||
par.addParameter('reset_frame', false, @islogical) % stop resets frame to init_frame
|
||||
par.addParameter('autoplay', false, @islogical) % start loop automatically
|
||||
par.addParameter('slider_position',slider_default, @isnumeric) % slider position; [left bottom width height]
|
||||
par.addParameter('play_position',play_default, @isnumeric) % slider position; [left bottom width height]
|
||||
par.addParameter('edit_position', edit_default, @isnumeric) % edit position; [left bottom width height]
|
||||
par.addParameter('show_play_button',true, @islogical) % array axis
|
||||
par.addParameter('show_edit_box', true, @islogical) % edit box
|
||||
par.addParameter('fnct', @(x)x) % data processing function
|
||||
par.addParameter('order', 1:size(img,3), @isnumeric) % change slice order in stack
|
||||
par.addParameter('plot_residua', false, @islogical) % plot residua in the image
|
||||
par.addParameter('save_movie', '', @ischar) % specify filename if a movie shall be written
|
||||
par.addParameter('movie_quality', 80, @isnumeric) % movie quality
|
||||
|
||||
|
||||
par.parse(vararg{:})
|
||||
vars = par.Results;
|
||||
|
||||
vars.fps = vars.fps *1.2; % correct for overhead
|
||||
|
||||
% permute the array to slide along diferent axis
|
||||
switch vars.slider_axis
|
||||
case 1
|
||||
img = rot90(permute(img,[2,3,1]));
|
||||
case 2
|
||||
img = rot90(permute(img,[1,3,2]));
|
||||
end
|
||||
if any(cellfun(@(x)(strcmpi(x, 'order')), par.UsingDefaults))
|
||||
% redefine the order just in case that the axis were swapped, but only
|
||||
% if there is not use preference
|
||||
vars.order = 1:size(img,3);
|
||||
end
|
||||
|
||||
|
||||
if ~isempty(vars.title_list)
|
||||
assert(length(vars.title_list) == size(img,3), 'Number of titles has to correspond to number of frames')
|
||||
end
|
||||
|
||||
sz = size(img,3);
|
||||
|
||||
im = imhandles(gcf);
|
||||
ax = gca;
|
||||
if ~isprop(ax, 'index')
|
||||
ax.addprop('index');
|
||||
ax.index = length(im)+1;
|
||||
else
|
||||
if isprop(ax, 'play_handle')
|
||||
delete(ax.play_handle);
|
||||
end
|
||||
if isprop(ax, 'slider_handle')
|
||||
delete(ax.slider_handle);
|
||||
end
|
||||
if isprop(ax, 'edit_handle')
|
||||
delete(ax.edit_handle);
|
||||
end
|
||||
if isprop(ax, 'vars')
|
||||
ax.vars = [];
|
||||
end
|
||||
end
|
||||
|
||||
if sz>1
|
||||
% checks
|
||||
vars.init_frame = round(vars.init_frame);
|
||||
|
||||
if vars.init_frame > sz || vars.init_frame < 1
|
||||
warning('Initial frame exceeds stack size.')
|
||||
vars.init_frame = 1;
|
||||
end
|
||||
|
||||
vars.vargin = ax_img;
|
||||
|
||||
if ~ax.isprop('img')
|
||||
ax.addprop('img');
|
||||
end
|
||||
|
||||
ax.img = img;
|
||||
|
||||
if ~ax.isprop('play')
|
||||
ax.addprop('play');
|
||||
end
|
||||
ax.play = @(x)play(x);
|
||||
|
||||
if ~ax.isprop('stop')
|
||||
ax.addprop('stop');
|
||||
end
|
||||
ax.stop = @(x)stop(x);
|
||||
|
||||
if ~ax.isprop('update_fig')
|
||||
ax.addprop('update_fig');
|
||||
end
|
||||
ax.update_fig = @(x)update_fig(x);
|
||||
|
||||
|
||||
%%% set handles
|
||||
|
||||
% slider
|
||||
slider_handle=uicontrol(gcf,'Style','slider','Max',sz,'Min',1,...
|
||||
'Value',vars.init_frame,'SliderStep',[1/(sz-1) 10/(sz-1)],...
|
||||
'Units','normalized','Position',vars.slider_position);
|
||||
if ~isprop(slider_handle, 'ax_index')
|
||||
slider_handle.addprop('ax_index');
|
||||
slider_handle.ax_index = ax.index;
|
||||
end
|
||||
if ~ax.isprop('slider_handle')
|
||||
ax.addprop('slider_handle');
|
||||
ax.slider_handle = slider_handle;
|
||||
elseif ax.isprop('slider_handle') && ~ax.slider_handle.isvalid
|
||||
ax.slider_handle = slider_handle;
|
||||
end
|
||||
|
||||
% play button
|
||||
if vars.show_play_button
|
||||
visible_button = 'on';
|
||||
else
|
||||
visible_button = 'off';
|
||||
if vars.loop
|
||||
warning('Loop can not be aborted without buttons. Setting ''loop'' back to ''false''.');
|
||||
vars.loop = false;
|
||||
end
|
||||
end
|
||||
|
||||
play_handle=uicontrol(gcf,'Style','pushbutton','string','Play',...
|
||||
'Units','normalized','Position',vars.play_position, 'Visible', visible_button);
|
||||
if ~isprop(play_handle, 'ax_index')
|
||||
play_handle.addprop('ax_index');
|
||||
play_handle.ax_index = ax.index;
|
||||
end
|
||||
if ~ax.isprop('play_handle')
|
||||
ax.addprop('play_handle');
|
||||
ax.play_handle = play_handle;
|
||||
elseif ax.isprop('play_handle') && ~ax.play_handle.isvalid
|
||||
ax.play_handle = play_handle;
|
||||
end
|
||||
if ~ax.isprop('vars')
|
||||
ax.addprop('vars');
|
||||
ax.vars = vars;
|
||||
else
|
||||
ax.vars = vars;
|
||||
end
|
||||
set(play_handle,'Callback',{@play_callback,ax});
|
||||
|
||||
|
||||
% text edit
|
||||
if vars.show_edit_box
|
||||
visible_box = 'on';
|
||||
else
|
||||
visible_box = 'off';
|
||||
end
|
||||
edit_handle = uicontrol('style','edit','units','normalized', 'Position', vars.edit_position, 'Visible', visible_box);
|
||||
set(edit_handle, 'Callback', {@edit_callback, ax});
|
||||
if ~ax.isprop('edit_handle')
|
||||
ax.addprop('edit_handle');
|
||||
ax.edit_handle = edit_handle;
|
||||
elseif ax.isprop('edit_handle') && ~ax.edit_handle.isvalid
|
||||
ax.edit_handle = edit_handle;
|
||||
end
|
||||
if ~isprop(edit_handle, 'ax_index')
|
||||
edit_handle.addprop('ax_index');
|
||||
edit_handle.ax_index = ax.index;
|
||||
end
|
||||
|
||||
|
||||
% set callback functions
|
||||
set(slider_handle,'Callback',{@slider_callback,ax});
|
||||
set(edit_handle, 'String', num2str(get(ax.slider_handle,'Value')));
|
||||
|
||||
|
||||
if vars.autoplay
|
||||
play_callback(ax, ax, ax);
|
||||
end
|
||||
|
||||
update_fig(ax)
|
||||
|
||||
else
|
||||
% standard imagesc should be enough
|
||||
if ax.isprop('update_title') || ax.isprop('play_handle') || ax.isprop('vars')
|
||||
if ax.isprop('vars') && isfield(ax.vars, 'slider_handle')
|
||||
ax.vars = rmfield(ax.vars, 'slider_handle');
|
||||
end
|
||||
if ax.isprop('play_handle')
|
||||
delete(ax.play_handle);
|
||||
end
|
||||
cla(ax);
|
||||
end
|
||||
|
||||
img = gather(vars.fnct(img));
|
||||
|
||||
if ~isreal(img)
|
||||
img = c2image(img);
|
||||
end
|
||||
if ~isempty(ax_img)
|
||||
imagesc(ax_img{:}, img);
|
||||
else
|
||||
imagesc(img);
|
||||
end
|
||||
if ~isempty(vars.title_list)
|
||||
title(ax, vars.title_list{1}, 'Interpreter', 'none')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
% plotting function
|
||||
function update_fig(ax)
|
||||
%import math.isint
|
||||
%import plotting.c2image
|
||||
|
||||
% im = imhandles(gcf);
|
||||
vars = ax.vars;
|
||||
slice = round(get(ax.slider_handle,'Value'));
|
||||
slice = max(1, min(length(vars.order), slice));
|
||||
|
||||
% FIXME: everything works better without following lines
|
||||
% sl = gcbo();
|
||||
% if ~isempty(sl)
|
||||
% ax = findobj('index', sl.ax_index);
|
||||
% end
|
||||
|
||||
img = gather(vars.fnct(squeeze(ax.img(:,:,vars.order(slice),:))));
|
||||
|
||||
if ~isreal(img)
|
||||
img = c2image(img);
|
||||
end
|
||||
if vars.plot_residua
|
||||
[residua{2},residua{1}] = find(abs(utils.findresidues(img))>0.1);
|
||||
|
||||
end
|
||||
|
||||
% if the current axis is empty, use imagesc with remaining arguments
|
||||
if ~ax.isprop('update_title')
|
||||
ax.addprop('update_title');
|
||||
ax.addprop('user_title');
|
||||
ax.update_title = true;
|
||||
if ~isempty(vars.vargin)
|
||||
imagesc(vars.vargin{:}, img);
|
||||
else
|
||||
imagesc(img);
|
||||
end
|
||||
hold all
|
||||
if vars.plot_residua && ~isempty(residua{1})
|
||||
plot(residua{:},'or')
|
||||
elseif vars.plot_residua
|
||||
plot(0,0,'or')
|
||||
end
|
||||
hold off
|
||||
addlistener(ax.Title, 'String', 'PostSet', @(gt, event)callback_title_post(ax, ax));
|
||||
else
|
||||
% if we just need to update the figure, only update the data
|
||||
ax_data = ax.findobj('Type', 'Image');
|
||||
ax_data.CData = img;
|
||||
if vars.plot_residua
|
||||
ax_data = ax.findobj('Type', 'Line');
|
||||
ax_data(1).XData = residua{1};
|
||||
ax_data(1).YData = residua{2};
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
% write title
|
||||
if isempty(vars.title_list)
|
||||
ax.update_title = false;
|
||||
if ~isempty(ax.user_title)
|
||||
title_text = sprintf(ax.user_title, vars.order(slice));
|
||||
title(ax, title_text, 'Interpreter', 'none');
|
||||
end
|
||||
ax.update_title = true;
|
||||
else
|
||||
if ~isempty(vars.title_list)
|
||||
title(ax, vars.title_list{vars.order(slice)}, 'Interpreter', 'none')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% Callback subfunctions %%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
function slider_callback(~,~,ax)
|
||||
% ob = gco;
|
||||
% vars.ax_index = ob.ax_index;
|
||||
if ax.isprop('edit_handle')
|
||||
set(ax.edit_handle, 'string', num2str(round(get(ax.slider_handle,'Value'))));
|
||||
end
|
||||
update_fig(ax)
|
||||
drawnow()
|
||||
|
||||
end
|
||||
|
||||
|
||||
function callback_title_post(ax, ~, ~)
|
||||
if ax.update_title
|
||||
ax.user_title = ax.Title.String;
|
||||
try
|
||||
ax.Title.String = sprintf(ax.user_title, get(ax.slider_handle,'Value'));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function play_callback(~,~,ax)
|
||||
% ax = findobj('index', ax.slider_handle.ax_index);
|
||||
vars = ax.vars;
|
||||
if ax.isprop('slider_handle') && ax.slider_handle.isvalid
|
||||
update_slider = true;
|
||||
else
|
||||
update_slider = false;
|
||||
end
|
||||
if ax.isprop('edit_handle') && ax.edit_handle.isvalid
|
||||
update_edit = true;
|
||||
else
|
||||
update_edit = false;
|
||||
end
|
||||
try
|
||||
switch get(ax.play_handle,'string')
|
||||
case 'Play'
|
||||
if ~isempty(vars.save_movie)
|
||||
disp(['Saving movie to ' vars.save_movie]);
|
||||
writeobj = VideoWriter(vars.save_movie);
|
||||
writeobj.Quality=vars.movie_quality;
|
||||
writeobj.FrameRate=vars.fps;
|
||||
|
||||
open(writeobj);
|
||||
vars.writeobj = writeobj;
|
||||
end
|
||||
set(ax.play_handle,'string','Stop')
|
||||
sz = size(ax.img,3);
|
||||
pos = round(get(ax.slider_handle,'Value'));
|
||||
if pos == sz
|
||||
set(ax.slider_handle,'Value',1);
|
||||
pos = 1;
|
||||
end
|
||||
while pos <=sz
|
||||
|
||||
if strcmp(get(ax.play_handle,'string'), 'Play')
|
||||
break
|
||||
end
|
||||
if update_slider
|
||||
set(ax.slider_handle,'Value',pos)
|
||||
end
|
||||
if update_edit
|
||||
set(ax.edit_handle, 'String', num2str(pos));
|
||||
end
|
||||
|
||||
update_fig(ax)
|
||||
pause(1/vars.fps)
|
||||
if vars.loop && pos == sz
|
||||
pos = 1;
|
||||
else
|
||||
pos = pos+1;
|
||||
end
|
||||
if vars.save_movie
|
||||
currFrame = getframe;
|
||||
writeVideo(vars.writeobj,currFrame);
|
||||
end
|
||||
|
||||
end
|
||||
set(ax.play_handle,'string','Play')
|
||||
if vars.reset_frame
|
||||
set(ax.slider_handle,'Value',vars.init_frame)
|
||||
end
|
||||
if vars.save_movie
|
||||
close(vars.writeobj);
|
||||
end
|
||||
case 'Stop'
|
||||
set(ax.play_handle,'string','Play')
|
||||
if vars.save_movie
|
||||
close(vars.writeobj);
|
||||
end
|
||||
end
|
||||
catch
|
||||
if ~ax.isprop('play_handle')
|
||||
fprintf('Lost connection to figure instance.\n')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function edit_callback(~,~, ax)
|
||||
str=get(ax.edit_handle,'String');
|
||||
|
||||
if isempty(str2num(str))
|
||||
warndlg('Input must be numerical');
|
||||
set(ax.edit_handle, 'string', num2str(round(get(ax.slider_handle,'Value'))));
|
||||
else
|
||||
set(ax.slider_handle,'Value',str2num(str))
|
||||
update_fig(ax)
|
||||
drawnow()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function play(ax)
|
||||
play_callback(ax.vars, ax.vars, ax);
|
||||
end
|
||||
|
||||
function stop(ax)
|
||||
set(ax.play_handle,'string','Play')
|
||||
set(ax.slider_handle,'Value',ax.vars.init_frame)
|
||||
end
|
||||
@@ -0,0 +1,109 @@
|
||||
% IMSHIFT_LINEAR will apply shift that can be different for
|
||||
% each frame.
|
||||
% + compared to imshift_fft, it does not have periodic boundary
|
||||
% + it is based on linear interpolation, so it can be run fast on GPU
|
||||
% + integer shift is equivalent to imshift_fft (up to the boundary condition)
|
||||
% - it needs for-loop for each frame -> it gets slow on GPU for
|
||||
% shifting my small images. In that case imshift_fft can be faster.
|
||||
%
|
||||
% img = imshift_linear(img, x,y, method)
|
||||
%
|
||||
% Inputs:
|
||||
% **img input image / stack of images
|
||||
% **x applied shift or vector of shifts for each frame
|
||||
% **y applied shift or vector of shifts for each frame
|
||||
% **method choose interpolation method: nearest, {linear}, cubic , circ
|
||||
%
|
||||
% *returns*:
|
||||
% ++img shifted image / stack of images
|
||||
%
|
||||
% see also: utils.imshift_fast, utils.imshift_fft
|
||||
|
||||
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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 img = imshift_linear(img, x,y, method)
|
||||
|
||||
|
||||
if nargin < 3
|
||||
y = x(:,2);
|
||||
x = x(:,1);
|
||||
end
|
||||
if nargin < 4
|
||||
method = 'linear';
|
||||
end
|
||||
|
||||
if all(x==0) && all(y==0)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
real_img = isreal(img);
|
||||
[Nx, Ny,Nlayers] = size(img);
|
||||
|
||||
if isscalar(x)
|
||||
x = ones(Nlayers,1) * x;
|
||||
end
|
||||
if isscalar(y)
|
||||
y = ones(Nlayers,1) * y;
|
||||
end
|
||||
|
||||
if strcmpi(method, 'circ')
|
||||
% perform fast shift with circular boundary condition
|
||||
X = 1:Nx;
|
||||
Y = 1:Ny;
|
||||
for ii = 1:Nlayers
|
||||
img(:,:,ii) = img(circshift(X,round(y(ii))), ...
|
||||
circshift(Y,round(x(ii))),ii);
|
||||
end
|
||||
else
|
||||
|
||||
for ii = 1:Nlayers
|
||||
%x(ii)
|
||||
%y(ii)
|
||||
img(:,:,ii) = interp2(single(img(:,:,ii)), single(-x(ii)+(1:Ny)),single(-y(ii)+(1:Nx)'), method,0);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,102 @@
|
||||
function [probe, mask] = make_tem_probe(dx, N, param)
|
||||
%MAKE_TEM_PROBE Generate probe functions produced by object lens in
|
||||
% transmission electron microscope.
|
||||
% Written by Yi Jiang based on Eq.(2.10) in Advanced Computing in Electron
|
||||
% Microscopy (2nd edition) by Dr.Kirkland
|
||||
%
|
||||
% Outputs:
|
||||
% probe: complex probe functions
|
||||
% mask: 2D Fourier mask function determined by alpha_max
|
||||
%
|
||||
% Inputs:
|
||||
% dx: pixel size in angstrom
|
||||
% N: number of pixels in each side of the 2D probe
|
||||
% param: probe parameters and other settings
|
||||
|
||||
% parse inputs
|
||||
parse_param = inputParser;
|
||||
parse_param.KeepUnmatched = true;
|
||||
parse_param.addParameter('df', 0, @isnumeric) %first-order aberration (defocus) in angstrom
|
||||
parse_param.addParameter('C3', 0, @isnumeric) %third-order spherical aberration in angstrom
|
||||
parse_param.addParameter('C5', 0, @isnumeric) %fifth-order spherical aberration in angstrom
|
||||
parse_param.addParameter('C7', 0, @isnumeric) %seventh-order spherical aberration in angstrom
|
||||
parse_param.addParameter('f_a2', 0, @isnumeric) %twofold astigmatism in angstrom
|
||||
parse_param.addParameter('theta_a2', 0, @isnumeric) %azimuthal orientation in radian
|
||||
parse_param.addParameter('f_a3', 0, @isnumeric) %threefold astigmatism in angstrom
|
||||
parse_param.addParameter('theta_a3', 0, @isnumeric) %azimuthal orientation in radian
|
||||
parse_param.addParameter('f_c3', 0, @isnumeric) %coma in angstrom
|
||||
parse_param.addParameter('theta_c3', 0, @isnumeric) %azimuthal orientation in radian
|
||||
|
||||
parse_param.addParameter('shifts', [0,0], @isnumeric) %shift probe center in angstrom
|
||||
parse_param.addParameter('N_z', 1, @isnumeric) %number of focal planes
|
||||
parse_param.addParameter('voltage', 300, @isnumeric) %beam voltage
|
||||
parse_param.addParameter('alpha_max', 30, @isnumeric) %semi-convergence angle
|
||||
parse_param.addParameter('plotting', 0, @islogical) %plot probes
|
||||
|
||||
parse_param.parse(param)
|
||||
p = parse_param.Results;
|
||||
|
||||
lambda = 12.398/sqrt((2*511.0+p.voltage).*p.voltage); %angstrom
|
||||
|
||||
amax = p.alpha_max*1e-3; %in rad
|
||||
amin = 0;
|
||||
|
||||
klimitmax = amax/lambda;
|
||||
klimitmin = amin/lambda;
|
||||
dk = 1/(dx*N);
|
||||
|
||||
if p.N_z==1
|
||||
dff = p.df;
|
||||
else
|
||||
dff = linspace(-floor(p.N_z/2),ceil(p.N_z/2)-1,p.N_z)*p.df; %angstrom
|
||||
end
|
||||
|
||||
kx = linspace(-floor(N/2),ceil(N/2)-1,N);
|
||||
[kX,kY] = meshgrid(kx,kx);
|
||||
|
||||
kX = kX.*dk;
|
||||
kY = kY.*dk;
|
||||
kR = sqrt(kX.^2+kY.^2);
|
||||
theta = atan2(kY,kX);
|
||||
chi = zeros(N,N,p.N_z);
|
||||
probe = zeros(N,N,p.N_z);
|
||||
|
||||
mask = single(kR<=klimitmax).*single(kR>=klimitmin);
|
||||
for i= 1:p.N_z
|
||||
chi(:,:,i) = -pi*lambda*kR.^2*dff(i);
|
||||
if p.C3~=0; chi(:,:,i) = chi(:,:,i) + pi/2*p.C3*lambda^3*kR.^4; end
|
||||
if p.C5~=0; chi(:,:,i) = chi(:,:,i) + pi/3*p.C5*lambda^5*kR.^6; end
|
||||
if p.C7~=0; chi(:,:,i) = chi(:,:,i) + pi/4*p.C7*lambda^7*kR.^8; end
|
||||
if p.f_a2~=0; chi(:,:,i) = chi(:,:,i) + pi*p.f_a2*lambda*kR.^2*sin(2*(theta-p.theta_a2)); end
|
||||
if p.f_a3~=0; chi(:,:,i) = chi(:,:,i) + 2*pi/3*p.f_a3*lambda^2*kR.^3*sin(3*(theta-p.theta_a3)); end
|
||||
if p.f_c3~=0; chi(:,:,i) = chi(:,:,i) + 2*pi/3*p.f_c3*lambda^2*kR.^3*sin(theta-p.theta_c3); end
|
||||
|
||||
phase = exp(-1i.*chi(:,:,i)).*exp(-2*pi*1i*p.shifts(1).*kX).*exp(-2*pi*1i*p.shifts(2).*kY);
|
||||
probe(:,:,i) = mask.*phase;
|
||||
probe(:,:,i) = fftshift(ifft2(ifftshift(probe(:,:,i))));
|
||||
probe(:,:,i) = probe(:,:,i)/sum(sum(abs(probe(:,:,i))));
|
||||
end
|
||||
|
||||
if p.plotting
|
||||
figure
|
||||
subplot(1,2,1)
|
||||
imagesc(abs(mask))
|
||||
axis image
|
||||
title('Fourier mask magnitude')
|
||||
|
||||
subplot(1,2,2)
|
||||
colormap parula
|
||||
iaxis{1} = ([1 N]-floor(N/2)+1)*dx/10;
|
||||
iaxis{2} = ([1 N]-floor(N/2)+1)*dx/10;
|
||||
imagesc3D(iaxis{1},iaxis{2},abs(probe))
|
||||
xlabel('nm')
|
||||
ylabel('nm')
|
||||
axis image
|
||||
|
||||
title('Probe magnitude')
|
||||
end
|
||||
|
||||
%probe = probe/(L/N)^2; %normalize the probe. Because in reciprocal space
|
||||
%the zero frequency amplitute is 1, so, the summation is also one.
|
||||
end
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
function [ppX_rot,ppY_rot]=scan_position_rot(N_scan_x,N_scan_y,scanStepSize_x,scanStepSize_y,rot_ang)
|
||||
% scan positions after rotation
|
||||
ppx = linspace(-floor(N_scan_x/2),ceil(N_scan_x/2)-1,N_scan_x)*scanStepSize_x;
|
||||
ppy = linspace(-floor(N_scan_y/2),ceil(N_scan_y/2)-1,N_scan_y)*scanStepSize_y;
|
||||
[ppX,ppY] = meshgrid(ppx,ppy);
|
||||
|
||||
ppY_rot = ppX*(-sind(rot_ang)) + ppY*cosd(rot_ang);
|
||||
ppX_rot = ppX*cosd(rot_ang) + ppY*sind(rot_ang);
|
||||
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
function [ output] = shift( input,dx_x,dx_y,px,py )
|
||||
%UNTITLED Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
|
||||
Ny = size(input,1);
|
||||
Nx = size(input,2);
|
||||
|
||||
dk_y = 1/(dx_y*Ny);
|
||||
dk_x = 1/(dx_x*Nx);
|
||||
|
||||
ky = linspace(-floor(Ny/2),ceil(Ny/2)-1,Ny);
|
||||
kx = linspace(-floor(Nx/2),ceil(Nx/2)-1,Nx);
|
||||
|
||||
[kX,kY] = meshgrid(kx,ky);
|
||||
kX = kX.*dk_x;
|
||||
kY = kY.*dk_y;
|
||||
|
||||
f = fftshift(fft2(ifftshift(input)));
|
||||
f = f.*exp(-2*pi*1i*px*kX).*exp(-2*pi*1i*py*kY);
|
||||
output = fftshift(ifft2(ifftshift(f)));
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user