initial commit

This commit is contained in:
2026-08-07 15:56:42 +09:00
commit 91ad25aca9
1012 changed files with 159314 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
% multislice_dof_summary.m
% summarize depth of focus reported in x-ray multislice ptycho literature
addpath(fullfile(pwd,'utils'))
dof = [];
pixel_size = [];
thickness = [];
dz = [];
Nlayer = [];
label = {};
alpha = 4; % additional scaling coefficient
%% 1.1 Multislice ptychography enables highresolution measurements in extended chemical reactors
% https://doi.org/10.1038/s41598-020-80926-6
energy = 9.1; %kev
det_pixel = 75e-6; %detector pixel size (m)
det_N = 512; % number of pixels in the detector
distance = 4.16; % # sample to detector distance (m)
[dof(1),pixel_size(1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(1) = 100e-6;
dz(1) = 100e-6; % layer distance used in multi-slice reconstruction
Nlayer(1) = 2; % number of layers used in multi-slice reconstruction
label{1} = 'PETRA III-polyimide foil';
%% 1.2 Multislice ptychography enables highresolution measurements in extended chemical reactors
% https://doi.org/10.1038/s41598-020-80926-6
energy = 15.25; %kev
det_pixel = 75e-6; %detector pixel size (m)
det_N = 512; % number of pixels in the detector
distance = 3.435; % # sample to detector distance (m)
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 650e-6;
dz(end+1) = 650e-6; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 2; % number of layers used in multi-slice reconstruction
label{end+1} = 'PETRA III-chemical reactor';
%% 2. Multi-slice ptychography with large numerical aperture multilayer Laue lenses
% https://doi.org/10.1364/OPTICA.5.000601
energy = 12; %kev
det_pixel = 55e-6; %detector pixel size (m)
det_N = 128; % number of pixels in the detector
distance = 0.5; % # sample to detector distance (m)
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 10e-6;
dz(end+1) = 10e-6; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 2; % number of layers used in multi-slice reconstruction
label{end+1} = 'BNL';
%% 3.1 X-ray ptychography with extended depth of field - real data
% https://doi.org/10.1364/OE.24.029089
energy = 6.2; %kev
det_pixel = 172e-6; %detector pixel size (m)
det_N = 192; % number of pixels in the detector
distance = 7.2; % # sample to detector distance (m)
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 200e-6;
dz(end+1) = 200e-6; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 2; % number of layers used in multi-slice reconstruction
label{end+1} = 'PSI';
%% 3.2 X-ray ptychography with extended depth of field - simulation
% https://doi.org/10.1364/OE.24.029089
energy = 6.2; %kev
det_pixel = 172e-6; %detector pixel size (m)
det_N = 512; % number of pixels in the detector
distance = 7.2; % # sample to detector distance (m)
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = [40e-6];
dz(end+1) = [20e-6]; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 3; % number of layers used in multi-slice reconstruction
label{end+1} = 'PSI-sim';
%% 4. High-Resolution Multislice X-Ray Ptychography of Extended Thick Objects
% https://doi.org/10.1103/PhysRevLett.112.053903
energy = 7; %kev
dx = 20e-9;
det_pixel = 75e-6; %detector pixel size (m). Not given in the paper
det_N = 606; % number of pixels in the detector
distance = dx*det_pixel*det_N/(1.23984193e-9/energy); % # sample to detector distance (m)
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 105e-6;
dz(end+1) = 1e-9; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 1; % number of layers used in multi-slice reconstruction
label{end+1} = 'SPring 8';
%% 5. Resolving 500 nm axial separation by multi-slice X-ray ptychography
% https://doi.org/10.1107/S2053273318017229
energy = 12; %kev
det_pixel = 55e-6; %detector pixel size (m)
det_N = 300; % number of pixels in the detector
distance = 0.35; % # sample to detector distance (m)
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 500e-9;
dz(end+1:end+1) = 500e-9; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 2; % number of layers used in multi-slice reconstruction
label{end+1} = 'BNL-XRF';
%% 6. 3D x-ray imaging of continuous objects beyond the depth of focus limit - simulation, tomography
% https://doi.org/10.1364/OE.24.029089
energy = 5; %kev
dx = 1e-9;
det_pixel = 75e-6; %detector pixel size (m). Not given in the paper
det_N = 72; % number of pixels in the detector
distance = dx*det_pixel*det_N/(1.23984193e-9/energy); % # sample to detector distance (m)
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 160e-9;
dz(end+1:end+1) = 1e-9; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 1; % number of layers used in multi-slice reconstruction
label{end+1} = 'sim-tomo';
%% 7. Adorym: A multi-platform generic x-ray image reconstruction framework based on automatic differentiation
%%%%%%% I'm not sure if they really used multi-slice...
%{
% https://arxiv.org/abs/2012.12686
energy = 5.5; %kev
det_pixel = 172e-6; %detector pixel size (m). Not given in the paper
det_N = 64; % number of pixels in the detector
distance = 2; % # sample to detector distance (m)
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 8e-6;
dz(end+1:end+1) = 1e-9; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 1; % number of layers used in multi-slice reconstruction
label{end+1} = 'APS-bnp-algae???';
%}
%% LCO
%
energy = 9.3; %kev
det_pixel = 75e-6; %detector pixel size (m)
det_N = 64; % number of pixels in the detector
distance = 1.92; % # sample to detector distance (m)
alpha = 4; % additional scaling coefficient
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 25e-6;
dz(end+1) = 8e-6; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 5; % number of layers used in multi-slice reconstruction
label{end+1} = 'APS-velo-LCO';
%% IC Pillar
%
energy = 8.8; %kev
det_pixel = 75e-6; %detector pixel size (m)
det_N = 64; % number of pixels in the detector
distance = 1.92; % # sample to detector distance (m)
alpha = 4; % additional scaling coefficient
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 20e-6;
dz(end+1) = 8e-6; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 5; % number of layers used in multi-slice reconstruction
label{end+1} = 'APS-velo-IC-pillar';
%% CIGS
%
energy = 9.3; %kev
det_pixel = 75e-6; %detector pixel size (m)
det_N = 64; % number of pixels in the detector
distance = 1.92; % # sample to detector distance (m)
alpha = 4; % additional scaling coefficient
[dof(end+1),pixel_size(end+1)] = DOF_calculator(energy, det_pixel, det_N, distance, alpha);
thickness(end+1) = 30e-6;
dz(end+1) = 8e-6; % layer distance used in multi-slice reconstruction
Nlayer(end+1) = 5; % number of layers used in multi-slice reconstruction
label{end+1} = 'APS-velo-CIGS';
%%
close all
figure1 = figure;
% Create axes
axes1 = axes('Parent',figure1);
hold(axes1,'on');
for i=1:length(thickness)
plot(i,thickness(i)./dof(i),'.','MarkerSize',15, 'DisplayName',label{i})
end
%hold on
line([1 length(dof)],[1 1],'LineWidth',1,'LineStyle','--','Color','r', 'DisplayName', 'DOF')
legend
set(axes1,'YMinorTick','on','YScale','log');
+17
View File
@@ -0,0 +1,17 @@
function [dof,pixel_size] = DOF_calculator(energy, det_pixel, det_N, distance, alpha)
%Calculate theoreical depth of focus for X-ray ptychography
% Inputs:
% **energy beam energy (keV)
% **det_pixel detector pixel size (m)
% **det_N # of pixels in the detector
% **distance # sample to detector distance (m)
% **alpha additional scaling coefficient
% *returns*:
% ++dof depth of focus for ptychography
lambda = 1.23984193e-9/energy; % wavelength (m)
pixel_size = lambda*distance/(det_pixel)/det_N; %pixel size in ptycho reconstruction (m)
dof = alpha * pixel_size^2/lambda;
end
+125
View File
@@ -0,0 +1,125 @@
% FUNCTION IM = C2IMAGE(A)
%
% Returns a RGB image of complex array A where
% the phase is mapped to hue, and the amplitude
% is mapped to brightness.
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  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 im = c2image(a, varargin)
if ismatrix(a)
absa = abs(a);
phasea = angle(a);
% (optional second argument can switch between various plotting modes)
abs_range = [];
if nargin==2
m = varargin{1};
elseif nargin==3
m = varargin{1};
abs_range = varargin{2};
else
m = 1;
end
if isempty(abs_range)
nabsa = absa/max(max(absa));
else
nabsa = (absa - abs_range(1))/(abs_range(2) - abs_range(1));
nabsa(nabsa < 0) = 0;
nabsa(nabsa > 1) = 1;
end
switch m
case 1
im_hsv = zeros([size(a) 3]);
im_hsv(:,:,1) = mod(phasea,2*pi)/(2*pi);
im_hsv(:,:,2) = 1;
im_hsv(:,:,3) = nabsa;
im = hsv2rgb(im_hsv);
case 2
im_hsv = ones([size(a) 3]);
im_hsv(:,:,1) = mod(phasea,2*pi)/(2*pi);
im_hsv(:,:,2) = nabsa;
im = hsv2rgb(im_hsv);
end
elseif ndims(a)==3
sz = size(a);
im_hsv = zeros([sz 3]);
im = zeros([sz 3]);
for ii=1:sz(3)
absa = abs(a(:,:,ii));
phasea = angle(a(:,:,ii));
% (optional second argument can switch between various plotting modes)
abs_range = [];
if nargin==2
m = varargin{1};
elseif nargin==3
m = varargin{1};
abs_range = varargin{2};
else
m = 1;
end
if isempty(abs_range)
nabsa = absa/max(max(absa));
else
nabsa = (absa - abs_range(1))/(abs_range(2) - abs_range(1));
nabsa(nabsa < 0) = 0;
nabsa(nabsa > 1) = 1;
end
switch m
case 1
im_hsv(:,:,ii,1) = mod(phasea,2*pi)/(2*pi);
im_hsv(:,:,ii,2) = 1;
im_hsv(:,:,ii,3) = nabsa;
case 2
im_hsv(:,:,ii,1) = mod(phasea,2*pi)/(2*pi);
im_hsv(:,:,ii,2) = nabsa;
end
im(:,:,ii,:) = hsv2rgb(squeeze(im_hsv(:,:,ii,:)));
end
end
end
@@ -0,0 +1,2 @@
%check_ptycho_recon.m
%Examine ML reconstructionsml
+30
View File
@@ -0,0 +1,30 @@
function [rgb_data] = convert_to_rgb(data)
%Convert complex data into rgb image showing both magnitude and phase
% Detailed explanation goes here
[W,H] = size(data);
adata = abs(data);
alpha = 1e-3;
tmp= sort(adata(:));
MAX = tmp(ceil(end*(1-alpha)));
ind = adata > MAX;
data(ind) = MAX * data(ind) ./ abs(data(ind));
adata = abs(data);
range = sp_quantile(adata(:), [1e-2, 1-1e-2],10);
adata = (adata - range(1) ) ./ ( range(2) - range(1) );
ang_data = angle(data);
hue = mod(ang_data+2.5*pi, 2*pi)/(2*pi);
hsv_data = [ hue(:) , ones(W*H,1), adata(:) ];
hsv_data = min(max(0, hsv_data),1);
rgb_data = hsv2rgb(hsv_data);
rgb_data = reshape(rgb_data, W,H,3);
rgb_data = min(1,rgb_data);
end
@@ -0,0 +1,49 @@
% FIND_RECONSTRUCTION_ROI_EXTERNAL precalculate the reconstruction regions
% Modified by YJ for external use outside the GPU engines
% ROI is consistent with "obj_proj" in LSQML.m
%
% [oROI, oROI_vec, sub_px_shift] = find_reconstruction_ROI2( positions,Np_o, Np_p )
%
% ** positions Npox*2 vector of scanning positions
% ** Np_o object size
% ** Np_p probe size
%
% returns:
% ++ oROI cell array contaning range for each view
% ++ oROI_vec cell array contaning range for each view in vector shape
% ++ sub_px_shift subpixel rounding errors, used for subpixel shift
%
function [oROI, oROI_vec, sub_px_shift] = find_reconstruction_ROI_external( positions,Np_o, Np_p )
positions = positions(:,[2,1]);
positions = positions + ceil(Np_o/2-Np_p/2);
sub_px_shift = positions - round(positions);
sub_px_shift = sub_px_shift(:,[2,1]); % return to the original XY coordinates
positions = round(positions);
range = [min(positions), max(positions)+ Np_p];
if any(range(1:2) < 0) || any(range(3:4) > Np_o)
error('Object size is too small, not enough space for probes !! \nposition range: %i %i %i %i, \nobject size: %i %i ', range(1), range(2), range(3), range(4), Np_o(1), Np_o(2))
end
oROI = cell(2,1);
for dim = 1:2
oROI{dim} = [positions(:,dim),positions(:,dim)+ Np_p(dim)-1];
oROI{dim} = uint32(oROI{dim});
end
if nargout > 1
Npos = length(positions);
oROI_vec = cell(Npos,2);
for ii = 1:Npos
for i = 1:2
oROI_vec{ii,i} = (oROI{i}(ii,1)):(oROI{i}(ii,2));
end
end
end
end
+523
View File
@@ -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
+201
View File
@@ -0,0 +1,201 @@
% IMAGESC_HSV for plotting complex valued arrays , similar to imagesc3D but with more options
% imagesc_hsv(varargin)
%
% ** varargin see the code
%
% Academic License Agreement
%
% Source Code
%
% Introduction
% This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
%
% Terms and Conditions of the LICENSE
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
% hereinafter set out and until termination of this license as set forth below.
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
% LICENSEEs responsibility to ensure its proper use and the correctness of the results.
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
% in the commercial use, application or exploitation of works similar to the PROGRAM.
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
% another computing language:
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
% Scherrer Institut, Switzerland."
%
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379382 (2008).
% (doi: 10.1126/science.1158573),
% for mixed coherent modes:
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 6871 (2013). (doi: 10.1038/nature11806),
% for LSQ-ML method
% M. Odstrcil, A. Menzel, M.G. Sicairos, Iterative least-squares solver for generalized maximum-likelihood ptychography, Optics Express, 2018
% for OPRP method
% M. Odstrcil, P. Baksh, S. A. Boden, R. Card, J. E. Chad, J. G. Frey, W. S. Brocklesby, "Ptychographic coherent diffractive imaging with orthogonal probe relaxation." Optics express 24.8 (2016): 8360-8369
% and/or for multislice:
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 2908929108 (2016).
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
% the courts of Zürich, Switzerland.
function imagesc_hsv(varargin)
import utils.*
import math.*
par = inputParser;
par.addOptional('data', [])
par.addParameter('scale', nan , @isnumeric )
par.addParameter('clim', [] , @isnumeric )
par.addParameter('inverse', false , @islogical ) % use white background
par.addParameter('show_ROI', false , @islogical ) % show only intersting area
par.addParameter('points', [] , @isnumeric ) % plot dots
par.addParameter('enhance_contrast', false , @islogical ) % plot dots
par.addParameter('axis', [] , @isnumeric ) % plot dots
par.addParameter('stabilize_phase', true , @islogical ) % plot dots
par.addParameter('show', true , @islogical ) % plot dots
par.parse(varargin{:})
r = par.Results;
data = r.data;
clim = r.clim;
if all(data(:) == 0)
warning('Empty data to plot')
return
end
[W,H] = size(data);
if ~isempty(r.axis)
X = linspace(r.axis(1),r.axis(2),W)*1e6;
Y = linspace(r.axis(3),r.axis(4),H)*1e6;
else
if ~isnan(r.scale)
scale = ones(2,1).*r.scale(:);
X = [-W/2:W/2-1]* scale(1)*1e6;
Y = [-H/2:H/2-1]* scale(2)*1e6;
else
X = 1:W; Y = 1:H;
end
end
if r.show_ROI
asum = abs(sum(data,3));
try
T1 = (graythresh_new((sum(asum,1))));
T2 = (graythresh_new((sum(asum,2))));
asum(:,sum(asum,1) < T1) = 0;
asum(sum(asum,2) < T2,:) = 0;
[ROI] = get_ROI(asum > 0.01*quantile(asum(:), 0.99), 0);
data = data(ROI{:});
X = X(ROI{1});
Y = Y(ROI{2});
catch
warning('ROI estimation failed')
end
end
[W,H] = size(data);
if ~isempty(clim)
ind_min = abs(data) < clim(1);
ind_max = abs(data) > clim(2);
data(ind_min) = data(ind_min) ./ abs(data(ind_min)) * clim(1);
data(ind_max) = data(ind_max) ./ abs(data(ind_max)) * clim(2);
end
adata = abs(data);
alpha = 1e-3;
tmp= sort(adata(:));
MAX = tmp(ceil(end*(1-alpha)));
ind = adata > MAX;
data(ind) = MAX * data(ind) ./ abs(data(ind));
if r.enhance_contrast
data = data ./ sqrt(alpha+abs(data));
clim = sqrt(clim);
end
if r.stabilize_phase
data = stabilize_phase(data, abs(data), abs(data), 'remove_ramp', false);
end
adata = abs(data);
if isempty(clim)
range = sp_quantile(adata(:), [1e-2, 1-1e-2],10);
else
range = clim;
end
%clim
adata = (adata - range(1) ) ./ ( range(2) - range(1) );
ang_data = angle(data);
if r.enhance_contrast && r.stabilize_phase
ang_range = max(abs(sp_quantile(ang_data(:), [1e-2, 1-1e-2],10)));
ang_range = max(1e-3, ang_range);
ang_data = 2*pi*ang_data ./ (2* ang_range);
end
if r.inverse
hue = mod(ang_data+1.5*pi, 2*pi)/(2*pi);
hsv_data = [ hue(:) , adata(:), ones(W*H,1) ];
else
hue = mod(ang_data+2.5*pi, 2*pi)/(2*pi);
hsv_data = [ hue(:) , ones(W*H,1), adata(:) ];
end
hsv_data = min(max(0, hsv_data),1);
rgb_data = hsv2rgb(hsv_data);
rgb_data = reshape(rgb_data, W,H,3);
rgb_data = min(1,rgb_data);
if r.show
hh = imagesc(Y,X, rgb_data );
axis image
end
if r.show
% Get the parent Axes of the image
axis image
if ~isempty(r.points) && ~any(isnan(r.scale))
hold on
points = r.scale.*1e6.*r.points;
plot( points(:,1),points(:,2), '.w')
hold off
end
end
end
+50
View File
@@ -0,0 +1,50 @@
% ISINT returns true if all values of X are integers, but class can be arbitrary
% numerical array
%
% Inputs:
% **x - checked array
% *optional*
% **prec - precision threshold used to decide whether the number is still integer, default = 0.01
% *returns*:
% is_integer - scalar bool
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  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 is_integer = isint(x, prec)
if nargin < 2
prec = 1e-2;
end
is_integer = all(abs(round(x(:)) - x(:)) < prec);
end
@@ -0,0 +1,63 @@
% FUNCTION [u_1, H, h, dH] = near_field_evolution(u_0, z, lambda, extent, use_ASM_only)
% Description: nearfield evolution function, it automatically swithch
% between ASM and Fraunhofer propagation
function [u_1, H, h, dH] = near_field_evolution(u_0, z, lambda, extent, use_ASM_only)
H = [];
h = [];
u_1 = [];
dH = [];
if nargin < 5
use_ASM_only = false;
end
extent = extent(:)' .* ones(1,2);
if z == 0
H = 1;
u_1 = u_0;
return
end
if z == inf
return
end
Npix = size(u_0);
xgrid = (0.5+(-Npix(1)/2:Npix(1)/2-1))/Npix(1);
ygrid = (0.5+(-Npix(2)/2:Npix(2)/2-1))/Npix(2);
k = 2 * pi / lambda(1);
% Undesamplling parameter
F = mean( extent.^2 ./ (lambda(1) .* z .* Npix ));
if abs(F) < 1 && ~use_ASM_only
% farfield propagation
warning('Farfield regime, F/Npix=%g', F )
Xrange = xgrid*extent(1);
Yrange = ygrid*extent(2);
[X,Y] = meshgrid(Xrange, Yrange);
h = exp(1i*k*z +1i*k/(2*z) * (X'.^2 + Y'.^2));
% this serves as low pass filter for the far nearfield
H = ifftshift(fft2(fftshift(h)));
H = H / abs(H(end/2+1, end/2+1)); % renormalize to conserve flux in image
else
% standard ASM
kx = 2 * pi .*xgrid / extent(1) * Npix(1);
ky = 2 * pi .*ygrid / extent(2) * Npix(2);
[Kx, Ky] = meshgrid(kx, ky);
dH = ( -1i*(Kx'.^2+Ky'.^2)/(2*k) );
H = exp( 1i*z*sqrt( k^2 - Kx'.^2-Ky'.^2)); % it make it a bit more sensitive to z distance
h = [];
end
u_1 = ifft2( bsxfun(@times, ifftshift(H), fft2(u_0)));
end
+99
View File
@@ -0,0 +1,99 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Unwrapping phase based on Ghiglia and Romero (1994) based on weighted and unweighted least-square method
% URL: https://doi.org/10.1364/JOSAA.11.000107
% Inputs:
% * psi: wrapped phase from -pi to pi
% * weight: weight of the phase (optional, default: all ones)
% Output:
% * phi: unwrapped phase from the weighted (or unweighted) least-square phase unwrapping
% Author: Muhammad F. Kasim (University of Oxford, 2016)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function phi = phase_unwrap(psi, weight)
if (nargin < 2) % unweighted phase unwrap
% get the wrapped differences of the wrapped values
dx = [zeros([size(psi,1),1]), wrapToPi(diff(psi, 1, 2)), zeros([size(psi,1),1])];
dy = [zeros([1,size(psi,2)]); wrapToPi(diff(psi, 1, 1)); zeros([1,size(psi,2)])];
rho = diff(dx, 1, 2) + diff(dy, 1, 1);
% get the result by solving the poisson equation
phi = solvePoisson(rho);
else % weighted phase unwrap
% check if the weight has the same size as psi
if (~all(size(weight) == size(psi)))
error('Argument error: Size of the weight must be the same as size of the wrapped phase');
end
% vector b in the paper (eq 15) is dx and dy
dx = [wrapToPi(diff(psi, 1, 2)), zeros([size(psi,1),1])];
dy = [wrapToPi(diff(psi, 1, 1)); zeros([1,size(psi,2)])];
% multiply the vector b by weight square (W^T * W)
WW = weight .* weight;
WWdx = WW .* dx;
WWdy = WW .* dy;
% applying A^T to WWdx and WWdy is like obtaining rho in the unweighted case
WWdx2 = [zeros([size(psi,1),1]), WWdx];
WWdy2 = [zeros([1,size(psi,2)]); WWdy];
rk = diff(WWdx2, 1, 2) + diff(WWdy2, 1, 1);
normR0 = norm(rk(:));
% start the iteration
eps = 1e-6;
k = 0;
phi = zeros(size(psi));
while (~all(rk == 0))
zk = solvePoisson(rk);
k = k + 1;
if (k == 1) pk = zk;
else
betak = sum(sum(rk .* zk)) / sum(sum(rkprev .* zkprev));
pk = zk + betak * pk;
end
% save the current value as the previous values
rkprev = rk;
zkprev = zk;
% perform one scalar and two vectors update
Qpk = applyQ(pk, WW);
alphak = sum(sum(rk .* zk)) / sum(sum(pk .* Qpk));
phi = phi + alphak * pk;
rk = rk - alphak * Qpk;
% check the stopping conditions
if ((k >= numel(psi)) || (norm(rk(:)) < eps * normR0)) break; end;
end
end
end
function phi = solvePoisson(rho)
% solve the poisson equation using dct
dctRho = dct2(rho);
[N, M] = size(rho);
[I, J] = meshgrid([0:M-1], [0:N-1]);
dctPhi = dctRho ./ 2 ./ (cos(pi*I/M) + cos(pi*J/N) - 2);
dctPhi(1,1) = 0; % handling the inf/nan value
% now invert to get the result
phi = idct2(dctPhi);
end
% apply the transformation (A^T)(W^T)(W)(A) to 2D matrix
function Qp = applyQ(p, WW)
% apply (A)
dx = [diff(p, 1, 2), zeros([size(p,1),1])];
dy = [diff(p, 1, 1); zeros([1,size(p,2)])];
% apply (W^T)(W)
WWdx = WW .* dx;
WWdy = WW .* dy;
% apply (A^T)
WWdx2 = [zeros([size(p,1),1]), WWdx];
WWdy2 = [zeros([1,size(p,2)]); WWdy];
Qp = diff(WWdx2,1,2) + diff(WWdy2,1,1);
end
+51
View File
@@ -0,0 +1,51 @@
% SP_QUANTILE sparse quantile, just make a fast guess of the quantile value
% on a downsampled array. Useful for estimation of the optimal imagesc
% limits
%
% Qval = sp_quantile(array,quantile,reduce)
%
% Inputs:
% **array - inputs ndim array
% **quantile - number or vector from 0 to 1 denoting quantiles
% **reduce - use every n-th element for calculation
% *returns*:
% ++Q - scalar or vector of quantiles of the reduced array
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  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 Qval = sp_quantile(x,q,reduce)
x = x(1:reduce:end);
Qval = quantile(x,q);
end
@@ -0,0 +1,10 @@
%view_arbitrary_path_fly_positions.m
%show scan positions in arbitrary-path fly-scan reconstruction
%% load a matlab recon file
figure
hold on
for i=1:size(outputs.probe_positions,3)
scatter(outputs.probe_positions(:,1,i)*p.dx_spec(1),outputs.probe_positions(:,2,i)*p.dx_spec(1),'.','DisplayName',num2str(i)); axis image
end
legend
@@ -0,0 +1,23 @@
%view_grid_artifact_removal.m
%% Show phase image and its Fourier magnitude to inspect the effect of grid artifact removal
close all
object_roi_ph = angle(object(p.object_ROI{:}));
%object_roi_ph = angle(object_roi); %old output file
figure
imagesc(object_roi_ph); axis image; colormap gray
figure
imagesc(abs(fftshift(fft2(object_roi_ph))).^0.2); axis image;
%% Quick way to see the scan step size
%load scan positions
ppY = h5read('data_roi0_Ndp128_para.hdf5','/ppY');
ppX = h5read('data_roi0_Ndp128_para.hdf5','/ppX');
figure
subplot(1,2,1)
plot(diff(ppY),'.')
title('Vertical')
subplot(1,2,2)
plot(diff(ppX),'.')
title('Horizontal')
+27
View File
@@ -0,0 +1,27 @@
%view_multi_slice_recon.m
addpath(fullfile(pwd,'utils'))
%load a matlab recon file
%% View object phase
object_roi = object(p.object_ROI{:},:);
object_roi_unwrapped = object_roi;
for i=1:size(object_roi,3)
object_roi_unwrapped(:,:,i) = phase_unwrap(angle(object_roi(:,:,i)));
end
imagesc3D(object_roi_unwrapped)
colormap gray
axis image
%% View probe propagation
% calculate propagator
Np_p = size(probe(:,:,1,1));
[~,H,~,~] = near_field_evolution(ones(Np_p), p.multi_slice_param.z_distance(1), p.lambda, p.dx_spec.*Np_p, true );
H = ifftshift(H);
Nlayer = length(p.multi_slice_param.z_distance)-1;
psi_s = zeros(Np_p(1),Np_p(2),Nlayer);
psi_s(:,:,1) = probe(:,:,1,1);
for k=2:Nlayer
psi_s(:,:,k) = ifft2(bsxfun(@times, H, fft2(psi_s(:,:,k-1))));
end
@@ -0,0 +1,35 @@
close all
addpath(fullfile(pwd,'utils'))
%% load a reconstruction
disp('extracting sub-regions...')
[oROI, oROI_vec, sub_px_shift] = find_reconstruction_ROI_external( outputs.probe_positions, size(object), size(probe(:,:,1,1)) );
object_sub_regions = zeros(size(probe,1),size(probe,2),size(outputs.probe_positions,1));
for i=1:size(object_sub_regions,3)
object_sub_regions(:,:,i) = object(oROI_vec{i,:});
end
disp('extracting sub-regions...done')
%% show in sub regions of object phase
imagesc3D(angle(object_sub_regions))
colormap gray
axis image
%% save sub regions
disp('saving sub regions...')
saveName = 'Niter1000_sub_regions_ph.hdf5';
N = size(object_sub_regions,1);
h5create(saveName, '/sub_recons_phase', size(object_sub_regions),'ChunkSize',[N N, 1],'Deflate',4)
h5write(saveName, '/sub_recons_phase', angle(object_sub_regions))
saveName = 'Niter1000_sub_regions_mag.hdf5';
h5create(saveName, '/sub_recons_mag', size(object_sub_regions),'ChunkSize',[N N, 1],'Deflate',4)
h5write(saveName, '/sub_recons_mag', abs(object_sub_regions))
disp('saving sub regions...done')
%%
saveName = 'Niter1000_positions.hdf5';
ppX = outputs.probe_positions(:,1)*p.dx_spec(1);
ppY = outputs.probe_positions(:,2)*p.dx_spec(1);
hdf5write(saveName, '/ppX', ppX)
hdf5write(saveName, '/ppY', ppY,'WriteMode','append')
hdf5write(saveName, '/dx', p.dx_spec(1),'WriteMode','append')
+109
View File
@@ -0,0 +1,109 @@
%view_probe_variation.m
close all
clear
addpath(strcat(pwd,'/utils/'))
% load a .mat reconstruction file w. probe variation correction
%% calculate probes at each scan positions
Np_p = [size(probe,1),size(probe,2)];
probes = reshape(probe(:,:,1,:),prod(Np_p),[]);
probes = reshape(probes * outputs.probe_evolution', Np_p(1), Np_p(2), []);
%% generate a movie to show scan positions and probes
disp('Generating movie frames')
figure1 = figure('Color',[1 1 1],'OuterPosition',[100 100 1800 600]);
clear M
object_roi = object(p.object_ROI{:},:);
N_sample = 1;
N_frames = 120;
%N_frames = floor(size(outputs.probe_positions(:,1),1)/N_sample);
%scale = p.dx_spec*1e6; % x-ray
%unit_label = '\mum'; % x-ray
scale = p.dx_spec; % electron
unit_label = 'A';
for i=1:N_frames
clf()
subplot(1,2,1)
aobject = angle(object);
range = sp_quantile(angle(object_roi), [1e-3, 1-1e-3],10);
aobject = (aobject - range(1)) / (range(2) - range(1));
Np_o = size(object);
grids = {(-ceil(Np_o(2)/2):ceil(Np_o(2)/2)-1)*scale(2), ...
(-ceil(Np_o(1)/2):ceil(Np_o(1)/2)-1)*scale(1)};
imagesc(grids{:}, aobject, [-2, 1]); % reduce contrast
colormap bone
axis xy
hold on
pos = outputs.probe_positions;
pos_0 = outputs.probe_positions_0;
pos_scales = pos .* scale([2,1]);
pos_scales_0 = pos_0 .* scale([2,1]);
scatter( pos_scales(:,1), pos_scales(:,2),'.r')
scatter( pos_scales_0(:,1), pos_scales_0(:,2),10, '.','MarkerEdgeColor','b')
scatter( pos_scales(1+(i-1)*N_sample,1), pos_scales(1+(i-1)*N_sample,2),50,'ok','filled')
axis equal xy tight
range = [min(pos_scales(:,1)), max(pos_scales(:,1)), min(pos_scales(:,2)), max(pos_scales(:,2))];
axis(range)
title(['\fontsize{12}{\color{blue}initial positions, '...
'\color{red}refined positions, \color{black}current probe position}'])
ylabel(['Position [', unit_label, ']'])
subplot(1,2,2)
imagesc_hsv(probes(:,:,1+(i-1)*N_sample),'stabilize_phase',false)
axis off
title('primary probe mode')
drawnow;
M(i) = getframe(gcf);
end
disp('Done')
%% save movie
disp('Saving movie...')
movieName = strcat('probes_selected.avi');
v= VideoWriter(movieName);
v.FrameRate= 5;
open(v)
writeVideo(v,M);
close(v)
disp('Done')
%% plot OPR modes (U)
N_vp = size(probe,4)-1;
figure
ax(1)=subplot(2,1+N_vp,1);
imagesc_hsv(probe(:,:,1,1),'stabilize_phase',false)
axis xy off
title('Constant mode')
for ii = 2:N_vp+1
ax(ii)=subplot(2,1+N_vp,ii);
imagesc_hsv(probe(:,:,1,ii),'stabilize_phase',false)
axis xy off
title(sprintf('Variable mode %i', ii-1))
end
for ii = 1:N_vp+1
ax(ii+1+N_vp)=subplot(2,1+N_vp,1+N_vp+ii);
scatter(outputs.probe_positions(:,1)*p.dx_spec(1),outputs.probe_positions(:,2)*p.dx_spec(1),[],outputs.probe_evolution(:,ii));
%axis xy off
title(strcat('Average weights:', num2str(mean(outputs.probe_evolution(:,ii)))))
%title(strcat(num2str(mean(outputs.probe_evolution(:,ii)))))
end
%% save probes as a tiff stack
Np_p = [size(probe,1),size(probe,2)];
probes = reshape(probe(:,:,1,:),prod(Np_p),[]);
probes = reshape(probes * outputs.probe_evolution', Np_p(1), Np_p(2), []);
resampleFactor = round(size(probes,3)/200); %only save ~100 images
probes_temp = probes(:,:,1:resampleFactor:end);
saveName = strcat(reconDir,'probes_Niter',num2str(Niter),'.tiff');
imwrite(convert_to_rgb(probes_temp(:,:,1)), saveName,'tiff')
for i=2:size(probes_temp,3)
imwrite(convert_to_rgb(probes_temp(:,:,i)), saveName,'tiff', 'WriteMode','append')
end
+81
View File
@@ -0,0 +1,81 @@
close all
addpath(fullfile(pwd,'utils'))
%%
figure1 = figure('Color',[1 1 1],'OuterPosition',[100 100 1800 600]);
%set(gcf,'Outerposition',[100 100 1800 600])
clf()
%set(gca,'color','white')
scale = p.dx_spec;
%object_roi = object(p.object_ROI{:},:);
aobject = angle(object);
range = sp_quantile(angle(object_roi), [1e-3, 1-1e-3],10);
aobject = (aobject - range(1)) / (range(2) - range(1));
Np_o = size(object);
grids = {(-ceil(Np_o(2)/2):ceil(Np_o(2)/2)-1)*scale(2), ...
(-ceil(Np_o(1)/2):ceil(Np_o(1)/2)-1)*scale(1)};
imagesc(grids{:}, aobject, [-2, 1]); % reduce contrast
colormap bone
axis xy
hold on
pos = outputs.probe_positions;
pos_0 = outputs.probe_positions_0;
%pos = pos + Np_o([2,1])/2;
%pos_scales = (pos-Np_o([2,1])/2) .* scale([2,1]);
pos_scales = pos .* scale([2,1]);
pos_scales_0 = pos_0 .* scale([2,1]);
%mean_err = mean(std(pos_err));
%range = max(pos) - min(pos);
%up = 0.02 * min(range) / mean_err;
%rounding_order = 10^floor(log10(up));
%up = ceil(up / rounding_order)*rounding_order;
scatter( pos_scales(:,1), pos_scales(:,2),'.r')
scatter( pos_scales_0(:,1), pos_scales_0(:,2),10, '.','MarkerEdgeColor','b')
%hold off
axis equal xy tight
range = [min(pos_scales(:,1)), max(pos_scales(:,1)), min(pos_scales(:,2)), max(pos_scales(:,2))];
axis(range)
title(['\fontsize{16}{\color{blue}initial positions, '...
'\color{red}refined positions}'])
%title('Initial positions: blue. Refined positions: red. Current probe position: Black')
%ylabel('Position [\mum]') %for x-ray
%xlabel('Position [\mum]')
ylabel('Position [A]') %for electron
xlabel('Position [A]')
%%
close all
figure
subplot(2,2,1)
plot(outputs.relative_pixel_scale,'.','MarkerSize',4)
axis tight
ylabel('Relative pixel scaling correction [-]')
xlabel('Iteration')
title('Scales')
hold off
grid on
subplot(2,2,2)
plot(outputs.asymmetry*100,'.','MarkerSize',4)
axis tight
ylabel('Asymmetry [%]')
xlabel('Iteration')
title('Asymmetry')
grid on
subplot(2,2,3)
plot(outputs.rotation,'.','MarkerSize',4)
axis tight
ylabel('Rotation [deg]')
xlabel('Iteration')
title('Rotation')
grid on
subplot(2,2,4)
plot(outputs.shear,'.','MarkerSize',4)
axis tight
ylabel('Shear [deg]')
xlabel('Iteration')
title('Shear')
grid on