mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-17 19:39:08 +09:00
initial commit
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
% [rec, rec_blocks] = FBP_deform(sinogram, cfg, vectors, varargin)
|
||||
% FUNCTION filtered back projection
|
||||
% Inputs:
|
||||
% sino - sinogram (Nlayers x width x Nangles)
|
||||
% cfg - config struct from ASTRA_initialize
|
||||
% vectors - vectors of projection rotation generated by ASTRA_initialize
|
||||
% varargin - see the code
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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 [rec, rec_blocks] = FBP_deform(sinogram, cfg, vectors, block_size, inv_deform_tensors, varargin )
|
||||
|
||||
par = inputParser;
|
||||
par.KeepUnmatched = true;
|
||||
par.addOptional('valid_angles', [], @isnumeric)
|
||||
par.addOptional('verbose', 1) % verbose = 0 : quiet, verbose : standard info , verbose = 2: debug
|
||||
|
||||
par.parse(varargin{:})
|
||||
r = par.Results;
|
||||
|
||||
Nblocks = length(inv_deform_tensors);
|
||||
Nangles = cfg.iProjAngles;
|
||||
|
||||
if isempty(r.valid_angles)
|
||||
r.valid_angles = 1:Nangles;
|
||||
end
|
||||
|
||||
rec = 0;
|
||||
for ll = 1:Nblocks
|
||||
if r.verbose ; utils.progressbar(ll, Nblocks); end
|
||||
|
||||
ids = 1+(ll-1)*block_size:min(Nangles, ll*block_size);
|
||||
if ~isempty(r.valid_angles)
|
||||
ids = intersect(ids, r.valid_angles);
|
||||
end
|
||||
if isempty(ids)
|
||||
continue
|
||||
end
|
||||
if isempty(inv_deform_tensors{ll})
|
||||
warning('Empty inv_deform_tensors, skipping %i projections', length(ids))
|
||||
end
|
||||
rec_blocks{ll} = tomo.FBP(sinogram, cfg, vectors,'deformation_fields',inv_deform_tensors{ll}, varargin{:}, 'valid_angles', ids, 'verbose', 0);
|
||||
rec = rec + rec_blocks{ll} * length(ids) / length(r.valid_angles);
|
||||
if nargout == 1
|
||||
rec_blocks{ll} = []; % save memory
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
% [U,S,V,rec_all] = SART_SVD(sinogram, theta, Npix, blocks, par)
|
||||
% perform temporal SVD analysis and SART based reconstruction to
|
||||
% estimate changes of the sample during reconstruction
|
||||
% Inputs:
|
||||
% **sinogram unwrapped sinogram
|
||||
% **theta tomography angles
|
||||
% **Npix size of the reconstructed volume
|
||||
% **blocks cell list containing indices for each subtomogram
|
||||
% Outputs:
|
||||
% ++U,S,V singular vectors
|
||||
% ++rec_all SVD filterd reconstruction for each subtomogram
|
||||
% Example of use:
|
||||
% subtomo_ind = [1, find(abs(diff(theta))> 170), length(theta)];
|
||||
% for ii = 1:length(subtomo_ind)-1
|
||||
% ind{ii} = subtomo_ind(ii):subtomo_ind(ii+1);
|
||||
% end
|
||||
% [U,S,V] = nonrigid.SART_SVD(sinogram, theta, Npix, ind);
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [U,S,V,rec_all] = SART_SVD(sinogram, theta, Npix, blocks, varargin)
|
||||
|
||||
|
||||
p = inputParser;
|
||||
p.addOptional('split', 1)
|
||||
p.addParameter('valid_angles', [])
|
||||
p.addParameter('SART_grouping', 25 ) % size of blocks in SART, ART=1, SIRT=Nangles
|
||||
p.addParameter('GPU', []) % list of GPUs to be used in reconstruction
|
||||
p.addParameter('verbose', 1) % verbose = 0 : quiet, verbose : standard info , verbose = 2: debug
|
||||
p.addParameter('N_SVD_modes', 2) % number of recovered SVD modes, 2 is usually enough
|
||||
p.addParameter('Niter_SVD', 3) % number of iter of the SVD SART
|
||||
p.addParameter('Niter_SART', 5) % number of internal iterations in each SART loops
|
||||
p.addParameter('output_folder', '') % path where the results should be stored
|
||||
p.addParameter('mask', []) % mask applied on the reconstruction
|
||||
|
||||
|
||||
|
||||
p.parse(varargin{:})
|
||||
res = p.Results;
|
||||
|
||||
|
||||
utils.verbose(1,'Using FBP for initial guess')
|
||||
|
||||
Nblocks = length(blocks);
|
||||
|
||||
tomogram = cell(Nblocks,1);
|
||||
for ii = 1:Nblocks
|
||||
utils.progressbar(ii,Nblocks)
|
||||
|
||||
% choose projections to process
|
||||
rec_ind = setdiff(blocks{ii}, res.valid_angles);
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
[Nlayers,width_sinogram,~] = size(sinogram);
|
||||
[cfg, vectors] = astra.ASTRA_initialize([Npix,Npix, Nlayers],[Nlayers,width_sinogram],theta);
|
||||
% find optimal split of the dataset for given GPU
|
||||
split = astra.ASTRA_find_optimal_split(cfg, length(res.GPU), 1);
|
||||
|
||||
% new FBP code
|
||||
subtomogram = tomo.FBP_zsplit(sinogram, cfg, vectors, split,'valid_angles',rec_ind,...
|
||||
'determine_weights', true, ...
|
||||
'GPU', res.GPU ,'filter','ram-lak', 'filter_value',1, 'verbose',-1);
|
||||
|
||||
num_proj_all(ii) = length(rec_ind);
|
||||
|
||||
% get full reconstruction (for FBP is sum already final tomogram)
|
||||
% calculate complex refractive index
|
||||
tomogram{ii} = gather(subtomogram);
|
||||
|
||||
end
|
||||
|
||||
|
||||
if isempty(res.mask)
|
||||
constraint_fnct= @(x)x;
|
||||
else
|
||||
constraint_fnct = @(x)(abs(x).*res.mask);
|
||||
end
|
||||
|
||||
|
||||
for ii = 1:Nblocks
|
||||
tomogram{ii} = constraint_fnct(tomogram{ii});
|
||||
end
|
||||
|
||||
gpu = gpuDevice;
|
||||
|
||||
for iter = 1:res.Niter_SVD
|
||||
utils.verbose(1,' ====== Iteration %i/%i ==== ', iter,res.Niter_SVD)
|
||||
rec_all = cat(4, tomogram{:});
|
||||
|
||||
utils.verbose(2,'Available GPU memory = %3.1fGB', gpu.AvailableMemory/1e9)
|
||||
|
||||
rec_all = reshape(rec_all, [], Nblocks);
|
||||
|
||||
%% %%%%%%%%%%%%%%%%%% APPLY SVD CONSTRAINT %%%%%
|
||||
utils.verbose(0,'Calculating SVD ... ')
|
||||
Nmodes = min(iter, res.N_SVD_modes);
|
||||
[U,S,V] = math.fsvd(rec_all, Nmodes);
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
if Nmodes == res.N_SVD_modes
|
||||
err_total(iter,:) = gather(sqrt(sum((U*S*V'-rec_all).^2)));
|
||||
|
||||
%% plot convergence progress
|
||||
plotting.smart_figure(3)
|
||||
loglog(mean(err_total'))
|
||||
axis tight
|
||||
grid on
|
||||
title('SVD SART - Convergence evolution')
|
||||
xlabel('Iteration')
|
||||
ylabel('Residuum between SVD model and reconstruction')
|
||||
drawnow
|
||||
|
||||
end
|
||||
|
||||
|
||||
utils.verbose(0,'Calculating SART ... ')
|
||||
|
||||
% apply SART refinement
|
||||
for ii = 1:Nblocks
|
||||
utils.progressbar(ii,Nblocks)
|
||||
|
||||
|
||||
% choose projections to process
|
||||
rec_ind = setdiff(blocks{ii}, res.valid_angles);
|
||||
|
||||
if isempty(rec_ind); continue; end
|
||||
|
||||
[cache_SART,cfg_SART] = tomo.SART_prepare(cfg, vectors(rec_ind,:), res.SART_grouping, 'keep_on_GPU', true, 'verbose', 0);
|
||||
|
||||
rec = U*S*V(ii,:)';
|
||||
rec = reshape(rec,size(tomogram{1}));
|
||||
|
||||
% get full reconstruction (for FBP is sum already final tomogram)
|
||||
% calculate complex refractive index
|
||||
|
||||
rec = utils.Garray(rec);
|
||||
sino = utils.Garray(sinogram(:,:,rec_ind));
|
||||
clear err
|
||||
|
||||
for jj = 1:res.Niter_SART
|
||||
[rec,err(jj,:)] = tomo.SART(rec, sino, cfg_SART, ...
|
||||
vectors(rec_ind,:),cache_SART, 'relax', 0, 'constraint', constraint_fnct, 'verbose', 0);
|
||||
end
|
||||
% apply some weak total variation to help againts undersampling
|
||||
% artefacts
|
||||
%rec = regularization.local_TV3D_chambolle(rec, 1e-6, 10);
|
||||
|
||||
tomogram{ii} = gather(rec);
|
||||
|
||||
end
|
||||
clear rec sino cache_SART
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
%% plot SVD evolution
|
||||
|
||||
rec_all = reshape(U*S*V', Npix, Npix,size(sinogram,1), Nblocks);
|
||||
rec_all = reshape(rec_all, [size(tomogram{1}), Nblocks]);
|
||||
|
||||
V_sign = sign(mean(V));
|
||||
|
||||
U(:,1) = U(:,1).*V_sign(1);
|
||||
V(:,1) = V(:,1).*V_sign(1);
|
||||
|
||||
screensize = get( 0, 'Screensize' );
|
||||
|
||||
|
||||
plotting.smart_figure(11)
|
||||
subplot(1,2,1)
|
||||
plotting.imagesc3D(squeeze(rec_all(:,:,ceil(end/2),:)))
|
||||
axis image off
|
||||
colormap bone
|
||||
caxis(gather(math.sp_quantile(rec_all, [0.001, 0.995], 10)));
|
||||
plotting.suptitle('Tomogram evolution in each subtomogram (central slice)')
|
||||
subplot(1,2,2)
|
||||
plot(V, '-o')
|
||||
title('Principal components evolution')
|
||||
axis tight
|
||||
grid on
|
||||
xlabel('Block')
|
||||
ylabel('S*V''')
|
||||
Energy = diag(S);
|
||||
Energy = Energy / sum(Energy);
|
||||
for kk = 1:res.N_SVD_modes
|
||||
legend_txt{kk} = sprintf('E=%3.2g%%', Energy(kk)*100);
|
||||
end
|
||||
legend(legend_txt ,'location','best')
|
||||
set(gcf,'Outerposition',[1 screensize(4)-500 800 500]);
|
||||
|
||||
if ~isempty(res.output_folder) && ~debug()
|
||||
try
|
||||
savefig(fullfile(res.output_folder, 'SVD_filtered_evolution.fig'))
|
||||
catch err
|
||||
warning('Saving of SVD_filtered_evolution failed with error: %s', err.message)
|
||||
end
|
||||
end
|
||||
|
||||
U = reshape(U, [size(tomogram{1}), res.N_SVD_modes]);
|
||||
|
||||
U_plot = U(:,:,2:end-1,:); % it seems that first and last layer are not well estimated
|
||||
U_plot = U_plot - median(quantile(min(U_plot,[],1),0.01,2),3);
|
||||
U_plot = U_plot ./ median(quantile(max(U_plot,[],1),0.99,2),3);
|
||||
|
||||
%
|
||||
U_plot = cat(2, U_plot(:,:,:,1), U_plot(:,:,:,2));
|
||||
|
||||
|
||||
|
||||
plotting.smart_figure(10)
|
||||
subplot(2,1,1)
|
||||
plotting.imagesc3D(U_plot, 'init_frame', size(U_plot,3)/2)
|
||||
axis image off
|
||||
colormap bone
|
||||
caxis(gather(math.sp_quantile(U_plot, [0.001, 0.995], 10)));
|
||||
title('Principal components (left is 1th PC , right is 2nd PC)')
|
||||
subplot(2,1,2)
|
||||
plotting.imagesc3D(U_plot, 'init_frame', size(U_plot,1)/2, 'slider_axis',1)
|
||||
axis image off
|
||||
colormap bone
|
||||
title('Principal components (left is 1th PC , right is 2nd PC)')
|
||||
caxis(gather(math.sp_quantile(U_plot, [0.001, 0.995], 10)));
|
||||
|
||||
%%%suptitle('Principal vectors showing tomogram evolution (slide to see layers of the sample)')
|
||||
set(gcf,'Outerposition',[1 screensize(4)-1250 1200 700]);
|
||||
if ~isempty(res.output_folder) && ~debug()
|
||||
print('-f10','-dpng','-r300',[res.output_folder, '/SVD_modes_scaled.png']);
|
||||
end
|
||||
|
||||
|
||||
|
||||
%% get reconstructions to RAM
|
||||
U = gather(U);
|
||||
S = gather(S);
|
||||
V = gather(V);
|
||||
rec_all = gather(rec_all);
|
||||
|
||||
U = reshape(U, [Npix, Npix,size(sinogram,1),res.N_SVD_modes]);
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,72 @@
|
||||
% SVD_regularize_3D_fields - use SVD to constraint the reconstructed DVF
|
||||
% and enforce smoothness in the DVF reconstruction
|
||||
%
|
||||
% shift_3D_total = SVD_regularize_3D_fields(shift_3D_total, Nsvd, SVD_smoothing)
|
||||
%
|
||||
% Inputs:
|
||||
% **shift_3D_total - (cell of 3D arrays) recovered deformation field
|
||||
% **Nsvd - (int), maximal number of SVD modes to be recovered (should be less than number of subtomos)
|
||||
% **SVD_smoothing - (scalar), smoothing constant between 0 to 0.25
|
||||
% returns:
|
||||
% ++shift_3D_total - (cell of 3D arrays) regularized deformation field
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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 shift_3D_total = SVD_regularize_3D_fields(shift_3D_total, Nsvd, SVD_smoothing)
|
||||
|
||||
% SVD regularization
|
||||
Nblocks= length(shift_3D_total);
|
||||
Nps = size(shift_3D_total{1}{1});
|
||||
for kk = 1:3
|
||||
for ll = 1:Nblocks
|
||||
shift_3D_mat(:,:,:,kk,ll) = shift_3D_total{ll}{kk};
|
||||
end
|
||||
end
|
||||
shift_3D_mat = reshape(shift_3D_mat,[],Nblocks);
|
||||
[U,S,V] = fsvd(shift_3D_mat, min(Nsvd, Nblocks));
|
||||
%% apply a bit of smoothness
|
||||
kernel = [SVD_smoothing, 1-2*SVD_smoothing, SVD_smoothing]';
|
||||
V = conv2(V, kernel, 'same') ./ conv2(ones(Nblocks,min(Nsvd, Nblocks)), kernel, 'same') ;
|
||||
shift_3D_mat = U*S*V';
|
||||
shift_3D_mat = reshape(shift_3D_mat, [Nps,3,Nblocks]);
|
||||
for kk = 1:3
|
||||
for ll = 1:Nblocks
|
||||
shift_3D_total{ll}{kk} = shift_3D_mat(:,:,:,kk,ll);
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,152 @@
|
||||
% find_shift_3D_nonrigid - GPU accelerated weighted optical flow method
|
||||
%
|
||||
% [shift,err] = find_shift_3D_nonrigid(vol_def, vol_ref, weight, downsample, smooth, regul)
|
||||
%
|
||||
% Inputs:
|
||||
% **vol_def deformed volume
|
||||
% **vol_ref reference volume
|
||||
% **weight importance weights for each pixel
|
||||
% **downsample downscale factor from the volume to DVF size
|
||||
% **smooth smoothness parameres for the recovered DVF
|
||||
% **regul regularization preventing empty regions to have too large effect on the DVF estimate
|
||||
% Outputs:
|
||||
% ++shift calculated local shift for reference to match deformed volume
|
||||
% ++err error between reference and the deformed volume
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [shift,err] = find_shift_3D_nonrigid(vol_def, vol_ref, weight, downsample, smooth, regul)
|
||||
|
||||
import plotting.*
|
||||
|
||||
|
||||
% calculate error
|
||||
resid = vol_def-vol_ref;
|
||||
|
||||
|
||||
% apply high pass filtering
|
||||
resid = resid - utils.imgaussfilt3_fft(resid, 5);
|
||||
|
||||
% calculate the error between the volumes
|
||||
err = weight .* resid.^2;
|
||||
err = sqrt(mean(err(:)));
|
||||
|
||||
% avoid numerical instabilities
|
||||
weight = weight / mean(abs(resid(:)));
|
||||
|
||||
Npix = size(vol_ref);
|
||||
for i = 1:3
|
||||
ind_def{i} = gpuArray(linspace(1,Npix(i)/downsample, Npix(i))');
|
||||
end
|
||||
[X,Y,Z]= meshgrid(ind_def{:});
|
||||
|
||||
|
||||
for ax = 1:3
|
||||
% get gradient direction
|
||||
vol_def_diff = math.get_img_grad_conv( vol_ref,2,ax);
|
||||
|
||||
% estimate the optimal step
|
||||
% GPU kernel merging
|
||||
[num, denum]= arrayfun(@get_coefs,weight, resid, vol_def_diff);
|
||||
|
||||
% bin the volume to make smoothing faster
|
||||
num = utils.binning_3D(num, downsample);
|
||||
denum = utils.binning_3D(denum, downsample);
|
||||
|
||||
num = padded_3D_smoothing(num, smooth/downsample/2);
|
||||
denum = padded_3D_smoothing(denum, smooth/downsample/2);
|
||||
|
||||
% add some small regularization
|
||||
denum = bsxfun(@plus, denum , regul*mean2(denum));
|
||||
|
||||
|
||||
shift{ax} = - num ./ denum;
|
||||
|
||||
% run simple line search to refined the optimal step, ideal it should be close to 1
|
||||
shift_full = interp3(shift{ax}, X,Y,Z);
|
||||
update = shift_full.*vol_def_diff;
|
||||
|
||||
Nsteps = 10;
|
||||
steps = logspace(0,1,Nsteps);
|
||||
for ii = 1:Nsteps
|
||||
res = arrayfun(@get_residuum_err, weight, resid,update, steps(ii));
|
||||
err_tmp(ii) = gather(sum(sum(sum(res))));
|
||||
if ii > 1 && err_tmp(ii) > err_tmp(ii-1)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
%% update the step
|
||||
shift{ax} = shift{ax} .* steps(math.argmin(err_tmp));
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function [num, denum]= get_coefs(W, resid, grad)
|
||||
% auxiliary function for fast GPU calculations
|
||||
agrad = abs(grad);
|
||||
W = W .* agrad;
|
||||
% estimate the optimal step
|
||||
num = W .* real(conj(resid) .* grad);
|
||||
denum = W .* agrad.^2;
|
||||
|
||||
|
||||
end
|
||||
|
||||
function res = get_residuum_err(weight, resid, update, step)
|
||||
res = weight .* (resid + step.* update).^2;
|
||||
end
|
||||
|
||||
function array = padded_3D_smoothing(array, smooth, split)
|
||||
% prevent periodic boundary issues for FFT conv smoothing
|
||||
if nargin < 3
|
||||
split = 1;
|
||||
end
|
||||
|
||||
Npad = ceil(min(size(array)/2, ceil(smooth/8)*16));
|
||||
array = padarray(array,[Npad(1),0,0],'symmetric','both');
|
||||
array = padarray(array,[0,Npad(2),0],'symmetric','both');
|
||||
array = padarray(array,[0,0,Npad(3)],'symmetric','both');
|
||||
|
||||
array = utils.imgaussfilt3_fft(array, smooth, split);
|
||||
|
||||
array = array(Npad(1):end-Npad(1)-1, Npad(2):end-Npad(2)-1,Npad(3):end-Npad(3)-1);
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
% get_deformation_fields - calculate the DVF from the observed deformation
|
||||
% field arrays bu deconvolution
|
||||
%
|
||||
% [deform_tensors_linear, inv_deform_tensors_linear] = ...
|
||||
% get_deformation_fields(shift_tensors, regularize_lambda, Npix_vol)
|
||||
%
|
||||
% Inputs:
|
||||
% **shift_tensors observed deformation
|
||||
% **regularize_lambda regularization constant for the deconvolution
|
||||
% **Npix_vol size of the reconstructed volume
|
||||
% Outputs:
|
||||
% ++deform_tensors_linear calculate forward DVF
|
||||
% ++inv_deform_tensors_linear calculate inverse DVF
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [deform_tensors_linear, inv_deform_tensors_linear] = ...
|
||||
get_deformation_fields(shift_tensors, regularize_lambda, Npix_vol)
|
||||
% simple deconvolution of the recovered shift arrays to the object
|
||||
% defomration arrays for linear deformation model
|
||||
|
||||
|
||||
Nblocks = length(shift_tensors);
|
||||
|
||||
if Nblocks == 1
|
||||
error('Number of blocks (subtomos) has to be > 1')
|
||||
end
|
||||
|
||||
if Nblocks > 1
|
||||
conv_mat = spdiags(ones(Nblocks,1),0,Nblocks, Nblocks+1) + spdiags(ones(Nblocks,1),1,Nblocks, Nblocks+1);
|
||||
conv_mat = conv_mat ./ sum(conv_mat,2);
|
||||
regul_mat = spdiags(2*ones(Nblocks,1), 0, Nblocks, Nblocks+1) - spdiags(ones(Nblocks,1), 1, Nblocks, Nblocks+1)-spdiags(ones(Nblocks,1), -1, Nblocks, Nblocks+1);
|
||||
regul_mat(1,1:2) = 0;
|
||||
|
||||
deform_mat = [];
|
||||
for block = 1:Nblocks
|
||||
for ax = 1:3
|
||||
deform_mat(:,:,:,ax,block) = gather(shift_tensors{block}{ax});
|
||||
end
|
||||
end
|
||||
size_deform_mat = size(deform_mat);
|
||||
deform_mat = reshape(deform_mat, [], Nblocks);
|
||||
|
||||
%% perform Tikhonov based deconvolution
|
||||
|
||||
% N = 50;
|
||||
% lams = logspace(-5,1,N);
|
||||
% for i = 1:N
|
||||
deconv_def_mat = ((conv_mat'*conv_mat + regularize_lambda*regul_mat'*regul_mat)\(conv_mat'*deform_mat'))';
|
||||
% enforce zero for the first deformation
|
||||
deconv_def_mat = deconv_def_mat - deconv_def_mat(:,1);
|
||||
|
||||
% err(i) = math.mean2((conv_mat*deconv_def_mat' - deform_mat').^2);
|
||||
% end
|
||||
|
||||
|
||||
deconv_def_mat = reshape(deconv_def_mat,[size_deform_mat(1:4), Nblocks+1] );
|
||||
for block = 1:Nblocks+1
|
||||
for ax = 1:3
|
||||
deform_tensors{block}{ax} = single(deconv_def_mat(:,:,:,ax,block));
|
||||
end
|
||||
end
|
||||
else
|
||||
deform_tensors = shift_tensors;
|
||||
end
|
||||
|
||||
[deform_tensors,inv_deform_tensors] = nonrigid.invert_DVF(deform_tensors, Npix_vol) ;
|
||||
|
||||
% join blocks to keep initial and final deform for each block together
|
||||
% -> linear deformation evolution is assumed in between
|
||||
if Nblocks > 1
|
||||
for block = 1:Nblocks
|
||||
deform_tensors_linear{block} = [deform_tensors{block}; deform_tensors{block+1}];
|
||||
inv_deform_tensors_linear{block} = [inv_deform_tensors{block}; inv_deform_tensors{block+1}];
|
||||
end
|
||||
else % just assume one single deformation
|
||||
deform_tensors_linear = deform_tensors;
|
||||
inv_deform_tensors_linear = inv_deform_tensors;
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,93 @@
|
||||
% get_mask - estimate support mask for the provided reconstructed volume
|
||||
%
|
||||
% [mask, W_rec] = get_mask(rec_0, mask_threshold, mask_dilate, show_mask)
|
||||
%
|
||||
% Inputs:
|
||||
% **rec_0 reconstruction volume
|
||||
% **mask_threshold relative threshold with respect to the maximum
|
||||
% **mask_dilate mask dilatation in pixels
|
||||
% **show_mask true / false if you want to plot the mask
|
||||
% Outputs:
|
||||
% ++mask binary mask
|
||||
% ++W_rec importance weights for the reconstructioin
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [mask, W_rec] = get_mask(rec_0, mask_threshold, mask_dilate, show_mask)
|
||||
|
||||
if nargin < 4
|
||||
show_mask = false;
|
||||
end
|
||||
|
||||
%% get mask
|
||||
|
||||
Nlayers = size(rec_0,3);
|
||||
Npix = size(rec_0,1);
|
||||
mask_dilate = ceil(mask_dilate);
|
||||
|
||||
mask = rec_0 > mask_threshold * quantile(rec_0(:), 0.99);
|
||||
mask = convn(single(mask), ones(mask_dilate,mask_dilate,mask_dilate, 'single'), 'same') > 1e-3*mask_dilate^3;
|
||||
|
||||
|
||||
%% get importance weighting for difference regions
|
||||
% importance weighting
|
||||
W_rec = gpuArray(single(tukeywin(Npix, 0.2) .* tukeywin(Npix, 0.2)' .* reshape(tukeywin(Nlayers, 0.2)',1,1,[]) )); % avoid edge issues
|
||||
W_rec = W_rec .* mask;
|
||||
W_rec = utils.imgaussfilt3_fft(W_rec,mask_dilate/2);
|
||||
W_rec = gather(W_rec);
|
||||
|
||||
if show_mask
|
||||
|
||||
plotting.smart_figure(212)
|
||||
plotting.imagesc_tomo(mask)
|
||||
suptitle('Estimated mask')
|
||||
drawnow
|
||||
|
||||
%% show mask
|
||||
plotting.smart_figure(46)
|
||||
subplot(1,2,1)
|
||||
plotting.imagesc3D(rec_0.* ~mask, 'init_frame', Nlayers/2)
|
||||
colorbar
|
||||
axis off image
|
||||
colormap bone
|
||||
title('Example of residuum after applied mask')
|
||||
subplot(1,2,2)
|
||||
hist(rec_0(1:100:end), 100)
|
||||
axis tight
|
||||
drawnow
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,72 @@
|
||||
% INVERT_DVF simple iterative method for estimation of the inverse deformation
|
||||
% field
|
||||
% Chen, Mingli, et al. "A simple fixed‐point approach to invert a deformation field a." Medical physics 35.1 (2008): 81-88.
|
||||
%
|
||||
% [deform_tensors,inv_deform_tensors] = invert_DVF(deform_tensors, Npix_vol)
|
||||
%
|
||||
% **deform_tensors cell of 3D arrays containing forward deformation DVF
|
||||
% **Npix_vol pixel size of the recosntructed volume
|
||||
% Outputs:
|
||||
% ++deform_tensors_linear calculate forward DVF
|
||||
% ++inv_deform_tensors_linear calculate inverse DVF
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [deform_tensors,inv_deform_tensors] = invert_DVF(deform_tensors, Npix_vol)
|
||||
|
||||
|
||||
Niter = 10;
|
||||
%% find invert transformation
|
||||
N = length(deform_tensors);
|
||||
for block = 1:N
|
||||
% init guess
|
||||
for ax = 1:3
|
||||
inv_deform_tensors{block}{ax} = -deform_tensors{block}{ax};
|
||||
end
|
||||
for i = 1:Niter
|
||||
for ax = 1:3
|
||||
scale = size(deform_tensors{block}{ax}, ax) / Npix_vol(ax) ; % calculate the deformation in deform_tensors grid
|
||||
inv_deform_tensors{block}{ax} = inv_deform_tensors{block}{ax}*0.5 + 0.5*utils.interp3_gpu(-deform_tensors{block}{ax}, ...
|
||||
scale*inv_deform_tensors{block}{1},scale*inv_deform_tensors{block}{2},scale*inv_deform_tensors{block}{3});
|
||||
end
|
||||
end
|
||||
% in my code I assume that deform_tensors and inv_deform_tensors
|
||||
% have the same direction (in the astra the direction is swapped)
|
||||
for ax = 1:3
|
||||
inv_deform_tensors{block}{ax} = -gather(inv_deform_tensors{block}{ax});
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,80 @@
|
||||
% nonrigid_registration - recovered DVF for given full reconstruction and
|
||||
% subreconstructions using optical flow method
|
||||
%
|
||||
%[shift_3D_total, vol_err, img_deform] = nonrigid_registration(volume_deform, volume_reference, weight, par, smooth, Niter, shift_3D_total)
|
||||
%
|
||||
% Inputs:
|
||||
% **volume_deform low quality deformed volume to be matched with reference
|
||||
% **volume_reference reference volume used for alignment
|
||||
% **weight importance weights for the 3D volumes
|
||||
% **par tomography parameter structure
|
||||
% **smooth constant to smooth the recovered DVF
|
||||
% **Niter number of iterations for the optical flow method
|
||||
% **shift_3D_total initial deformation field (zeros)
|
||||
% Outputs:
|
||||
% ++shift_3D_all recovered deformation for given full reconstruction and subreconstructions
|
||||
% ++vol_err error between volume and subvolumes
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [shift_3D_total, vol_err] = nonrigid_registration(volume_deform, volume_reference, weight, par, smooth, Niter, shift_3D_total)
|
||||
% estimate deformation fields to match two 3D volumes
|
||||
|
||||
Npix = size(volume_deform);
|
||||
|
||||
if ~exist('shift_3D_total', 'var')
|
||||
for ii = 1:3
|
||||
shift_3D_total{ii}= gpuArray.zeros( ceil(Npix/par.downsample_DVF) , 'single');
|
||||
end
|
||||
end
|
||||
|
||||
img_deform = utils.interp3_gpu(volume_deform, shift_3D_total{:});
|
||||
|
||||
for iter = 1:Niter
|
||||
|
||||
% core : estimate of the deformation field
|
||||
[shift_3D,vol_err(iter)] = nonrigid.find_shift_3D_nonrigid(img_deform,volume_reference, weight, par.downsample_DVF, smooth, par.regular);
|
||||
for ii = 1:3
|
||||
shift_3D_total{ii} = shift_3D_total{ii}+ par.relax_pos_corr*shift_3D{ii};
|
||||
end
|
||||
% apply inverse deformations on the deformated object
|
||||
img_deform = utils.interp3_gpu(volume_deform, -shift_3D_total{1}, -shift_3D_total{2}, -shift_3D_total{3} );
|
||||
|
||||
if iter > 1 && vol_err(end) > vol_err(end-1)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,250 @@
|
||||
% prepare_artificial_deform_data - prepare deformed phantom for algorithm tests
|
||||
%
|
||||
%[dphase, shift_3D_orig, angles, par, rec_ideal, volData_orig] = ...
|
||||
% prepare_artificial_deform_data(Nangles, Npix, Nlayers, Nblocks, smooth, binning,DVF_amplitude,DVF_period, par_0)
|
||||
%
|
||||
% Inputs:
|
||||
% **Nangles number of angles in the simulated dataset
|
||||
% **Npix int - pixel size of the phantom
|
||||
% **Nlayers number of layers in the phatom
|
||||
% **Nblocks number of subtomograms
|
||||
% **smooth constant used to estimate ratio between phantom pixel size and DVF pixels size
|
||||
% **binning simulate binning of the produced sinograms
|
||||
% **par_0 initial parameters structure that will be merged with the loaded paramters
|
||||
% Outputs:
|
||||
% ++dphase phase difference for the complex project
|
||||
% ++shift_3D_all_0 original deformation = {}
|
||||
% ++angles angles for each of the projection
|
||||
% ++par merged parameter structure
|
||||
% ++rec_ideal ideal construction with known DVF
|
||||
% ++volData_orig original phantom
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [dphase, shift_3D_orig, angles, par, rec_ideal, volData_orig] = ...
|
||||
prepare_artificial_deform_data(Nangles, Npix, Nlayers, Nblocks, smooth, binning,DVF_amplitude,DVF_period, par_0)
|
||||
|
||||
%% prepare deformated data for provided parameters
|
||||
|
||||
import utils.*
|
||||
import math.*
|
||||
import plotting.*
|
||||
|
||||
%% create data and geometry
|
||||
angles = pi+[linspace(0, 180, Nangles)];
|
||||
% create 8 subtomos
|
||||
angles = reshape(angles, Nblocks,[])';
|
||||
angles = angles(:);
|
||||
|
||||
lamino_angle = 90;
|
||||
Nw = ceil(Npix*sqrt(2)/16)*16;
|
||||
|
||||
|
||||
try
|
||||
disp('Loading stored model')
|
||||
load(['porous_glass_data',num2str(Npix),'.mat']);
|
||||
disp('Loading done')
|
||||
catch
|
||||
try
|
||||
%% porous_glass phantom
|
||||
disp('Creating phantom')
|
||||
rng default
|
||||
volData_orig = randn(2*[Npix, Npix, Nlayers], 'single');
|
||||
volData_orig = imgaussfilt3_fft(volData_orig, 6);
|
||||
porous_glass = imgaussfilt3_fft(volData_orig > 0, 2)>0.01 & volData_orig <= 0;
|
||||
volData_orig = randn(2*[Npix, Npix, Nlayers], 'single');
|
||||
volData_orig = imgaussfilt3_fft(volData_orig, 6);
|
||||
porous_glass = porous_glass | imgaussfilt3_fft(volData_orig > 0, 2)>0.01 & volData_orig <= 0;
|
||||
[Xq,Yq,Zq] = meshgrid(linspace(-0.5,0.5,2*Npix), linspace(-0.5,0.5,2*Npix), linspace(-0.5,0.5,2*Nlayers));
|
||||
porous_glass = interp3(single(porous_glass),Xq*Npix*3.5+Npix,Yq*Npix*3.5+Npix,Zq*Nlayers*3.5+Nlayers);
|
||||
porous_glass = porous_glass(end/4:end*3/4-1,end/4:end*3/4-1,end/4:end*3/4-1);
|
||||
porous_glass(isnan(porous_glass)) = 0;
|
||||
|
||||
% apply circular mask
|
||||
xgrid = -Npix/2+1 : Npix/2;
|
||||
[X,Y] = meshgrid(xgrid, xgrid);
|
||||
porous_glass = porous_glass .* imgaussfilt(single(X.^2+Y.^2 < (Npix/2.2)^2), 3);
|
||||
porous_glass = porous_glass .* reshape(tukeywin(Nlayers, 0.5), 1,1,[]);
|
||||
porous_glass = uint8(porous_glass/max(porous_glass(:)) * 255);
|
||||
savefast_safe(['porous_glass_data',num2str(Npix),'.mat'], 'porous_glass', true);
|
||||
catch
|
||||
keyboard
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
Bsize = ceil(Nangles/Nblocks);
|
||||
|
||||
% load porous_glass_data
|
||||
volData_orig = single(porous_glass);
|
||||
volData_orig = volData_orig(:,:,1:Nlayers);
|
||||
|
||||
% apply circular mask
|
||||
xgrid = -Npix/2+1 : Npix/2;
|
||||
[X,Y] = meshgrid(xgrid, xgrid);
|
||||
volData_orig = volData_orig .* imgaussfilt2_fft(single(X.^2+Y.^2 < (Npix/2.4)^2), 5);
|
||||
volData_orig = volData_orig .* reshape(tukeywin(Nlayers, 0.1), 1,1,[]);
|
||||
Nlayers = size(volData_orig,3);
|
||||
|
||||
%% initialize deformation vector fields reconstructions
|
||||
Nps = ceil([Npix, Npix, Nlayers]/par_0.downsample_DVF);
|
||||
|
||||
|
||||
%% generate deformation field
|
||||
volData_orig = gather(volData_orig);
|
||||
|
||||
|
||||
%% generate "measured" data
|
||||
|
||||
disp('Generating data')
|
||||
split = 1;
|
||||
|
||||
rng default
|
||||
for ax= 1:3
|
||||
for j = 1:2
|
||||
shift_3D{j}{ax} = imgaussfilt3_fft(randn(Nps), DVF_period);
|
||||
shift_3D{j}{ax} = shift_3D{j}{ax} / max(abs(shift_3D{j}{ax}(:)))*DVF_amplitude;
|
||||
end
|
||||
end
|
||||
|
||||
for ll = 1:Nblocks+1
|
||||
% ratio(1) = 1-exp(-3*((ll-1)/(Nblocks+1)));
|
||||
% ratio(2) = 1-exp(-3*((ll-1)/(Nblocks+1)));
|
||||
% ratio(3) = 1-exp(-3*((ll-1)/(Nblocks+1)));
|
||||
|
||||
ratio(1) = sin(2*pi*(ll-1)/(Nblocks+1));
|
||||
ratio(2) = sin(2*pi*(ll-1)/(Nblocks+1));
|
||||
ratio(3) = sin(2*pi*(ll-1)/(Nblocks+1));
|
||||
|
||||
for ax= 1:3
|
||||
shift_3D_orig{ll}{ax} = (ratio(ax)*shift_3D{1}{ax});
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
[cfg, vectors] = ...
|
||||
astra.ASTRA_initialize([Npix, Npix,Nlayers],[Nlayers,Nw],angles,lamino_angle, 0, 1);
|
||||
|
||||
|
||||
% resample the created DVF to reconstruction size of the DVF
|
||||
for ll = 1:Nblocks+1
|
||||
for kk = 1:3
|
||||
Np = size(shift_3D_orig{ll}{kk});
|
||||
[X,Y,Z] = meshgrid(linspace(1,Np(1),Nps(1)), linspace(1,Np(2),Nps(2)), linspace(1,Np(3),Nps(3)));
|
||||
shift_3D_orig{ll}{kk} = interp3(shift_3D_orig{ll}{kk},X,Y,Z);
|
||||
end
|
||||
end
|
||||
|
||||
[deform_tensors,inv_deform_tensors] = nonrigid.invert_DVF(shift_3D_orig, [Npix, Npix,Nlayers]);
|
||||
% join blocks to keep initial and final deform for each block together
|
||||
for block = 1:Nblocks
|
||||
deform_tensors_linear{block} = [deform_tensors{block}; deform_tensors{block+1}];
|
||||
inv_deform_tensors_linear{block} = [inv_deform_tensors{block}; inv_deform_tensors{block+1}];
|
||||
end
|
||||
|
||||
|
||||
|
||||
sinogram = tomo.Ax_sup_partial(volData_orig,cfg, vectors,split);
|
||||
|
||||
rec_ideal = tomo.FBP(sinogram , cfg, vectors,split, 'verbose',0);
|
||||
|
||||
% generate data
|
||||
for ll = 1:Nblocks
|
||||
ids = 1+(ll-1)*Bsize:min(Nangles, ll*Bsize);
|
||||
cfg.iProjAngles = length(ids);
|
||||
|
||||
sinogram(:,:,ids) = tomo.Ax_sup_partial(volData_orig,cfg, vectors(ids,:),split, ...
|
||||
'deformation_fields', deform_tensors_linear{ll});
|
||||
|
||||
end
|
||||
|
||||
|
||||
%create realistic issues
|
||||
sinogram = binning_2D(sinogram,binning);
|
||||
|
||||
% change the change to get phase jumps
|
||||
sinogram = sinogram / max(sinogram(:)) * 2*pi;
|
||||
|
||||
dphase = math.get_phase_gradient_1D(-sinogram, 2);
|
||||
|
||||
|
||||
|
||||
[cfg, vectors] = ...
|
||||
astra.ASTRA_initialize([Npix, Npix,Nlayers]/binning,[Nlayers,Nw]/binning,angles,lamino_angle, 0, 1);
|
||||
|
||||
|
||||
rec_0 = tomo.FBP(sinogram , cfg, vectors,split);
|
||||
rec_corr = 0;
|
||||
for ll = 1:Nblocks
|
||||
ids = 1+(ll-1)*Bsize:min(Nangles, ll*Bsize);
|
||||
cfg.iProjAngles = length(ids);
|
||||
rec_corr = rec_corr+tomo.FBP(sinogram(:,:,ids) , cfg, vectors(ids,:),split, 'verbose',0,...
|
||||
'deformation_fields', inv_deform_tensors_linear{ll} )/Nblocks;
|
||||
end
|
||||
|
||||
|
||||
% if debug()
|
||||
figure
|
||||
subplot(1,2,1)
|
||||
imagesc3D(max(0,rec_0), 'init_frame', Nlayers/2)
|
||||
axis off image; colormap bone
|
||||
title('Standard reconstruction')
|
||||
subplot(1,2,2)
|
||||
imagesc3D(max(0,rec_corr), 'init_frame', Nlayers/2)
|
||||
axis off image; colormap bone
|
||||
title('Ideally corrected reconstruction')
|
||||
drawnow
|
||||
% end
|
||||
|
||||
% store inputs to par structure
|
||||
par.binning = binning;
|
||||
par.valid_angles = 1:Nangles;
|
||||
par.air_gap = [20,20];
|
||||
par.factor = 1;
|
||||
par.output_folder = '';
|
||||
|
||||
for field = fields(par_0)'
|
||||
par.(field{1}) = par_0.(field{1});
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
% prepare_real_deform_data - load already prealigned and fixed projections
|
||||
%
|
||||
%[dphase, shift_3D_all_0, angles, par] = ...
|
||||
% prepare_real_deform_data(path_to_projections, projection_filename, sample_name, par_0)
|
||||
%
|
||||
% Inputs:
|
||||
% **path_to_projections path where are stored preloaded data
|
||||
% **projection_filename name of the file where are the preloaded data
|
||||
% **sample_name name of the sample, it used for cache file reparation
|
||||
% **par_0 initial paramters structure that will be merged with the loaded paramters
|
||||
% Outputs:
|
||||
% ++dphase phase difference for the complex project
|
||||
% ++shift_3D_all_0 original deformation = {}
|
||||
% ++angles angles for each of the projection
|
||||
% ++par merged parameter structure
|
||||
% ++object complex valued projections
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [dphase, shift_3D_all_0, angles, par, object] = ...
|
||||
prepare_real_deform_data(path_to_projections, projection_filename, sample_name, par_0)
|
||||
|
||||
import utils.*
|
||||
import math.*
|
||||
import plotting.*
|
||||
|
||||
shift_3D_all_0 = {};
|
||||
if ~exist('cache', 'dir')
|
||||
mkdir('cache')
|
||||
end
|
||||
|
||||
cached_file = fullfile(path_to_projections, ['cache_nonrigid_tomo', sample_name,'.mat']);
|
||||
% try to load cached data
|
||||
|
||||
verbose(0, 'Loading prepared data from %s', fullfile(path_to_projections, projection_filename))
|
||||
%% load complex valued projections
|
||||
d = load(fullfile(path_to_projections, projection_filename));
|
||||
verbose(0, 'Loading done')
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% create data and geometry
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
if isfield(d, 'dphase')
|
||||
dphase = d.dphase;
|
||||
else
|
||||
object = complex(d.stack_object_r,d.stack_object_i);
|
||||
|
||||
object_ROI = d.object_ROI;
|
||||
|
||||
|
||||
object = object(object_ROI{:},:);
|
||||
|
||||
|
||||
object = smooth_edges(object);
|
||||
|
||||
dphase = tomo.block_fun(@math.get_phase_gradient_1D,object, 2);
|
||||
|
||||
end
|
||||
if isfield(d, 'angles')
|
||||
angles = d.angles;
|
||||
else
|
||||
angles = d.theta;
|
||||
end
|
||||
|
||||
|
||||
dphase = smooth_edges(dphase);
|
||||
|
||||
|
||||
|
||||
|
||||
try
|
||||
par = d.par;
|
||||
catch
|
||||
par = struct();
|
||||
end
|
||||
|
||||
|
||||
|
||||
% rewrite loaded params by some defaults
|
||||
for field = fields(par_0)'
|
||||
par.(field{1}) = par_0.(field{1});
|
||||
end
|
||||
|
||||
par.output_folder = path_to_projections;
|
||||
|
||||
if debug()
|
||||
% plot angular blocks
|
||||
figure
|
||||
plot(angles, '.-')
|
||||
for ii = 1:Nblocks
|
||||
plotting.vline(ii*Bsize)
|
||||
end
|
||||
xlabel('Projection #')
|
||||
ylabel('Angle [deg]')
|
||||
title('Angular block splitting')
|
||||
drawnow
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,57 @@
|
||||
% REGULARIZE_3D_FIELD - remove rigid motion from the reconstructed DVF
|
||||
%
|
||||
% shift_3D_total= regularize_3D_field(shift_3D_total )
|
||||
%
|
||||
% Inputs:
|
||||
% **shift_3D_total reconstructed DVF
|
||||
% Outputs:
|
||||
% ++shift_3D_total optimized DVF
|
||||
%
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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 shift_3D_total= regularize_3D_field(shift_3D_total )
|
||||
Nblocks = length(shift_3D_total);
|
||||
for kk = 1:3
|
||||
% remove additional degrees of freedome
|
||||
shift_3D_avg = 0;
|
||||
for ll = 1:Nblocks
|
||||
shift_3D_avg = shift_3D_avg+ shift_3D_total{ll}{kk};
|
||||
end
|
||||
for ll = 1:Nblocks
|
||||
shift_3D_total{ll}{kk} = shift_3D_total{ll}{kk} - shift_3D_avg/Nblocks;
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,166 @@
|
||||
% show_deformation_field - plot reconstructed deformation vector field
|
||||
%
|
||||
% show_deformation_field(rec_avg, deform_tensors, apodize_radial, Nsvd, binning, upscale_arrows, slice_axis, down_DVF)
|
||||
%
|
||||
% Inputs:
|
||||
% **rec_avg optimal reconstuction
|
||||
% **deform_tensors reconstructed DVF
|
||||
% **apodize_radial apply radial appodization to crop artefacts around
|
||||
% **Nsvd number of SVD modes to be plotted
|
||||
% **binning currenlty used binning (used for scaling)
|
||||
% **upscale_arrows (scalar) scaling constant for the plotted arrows
|
||||
% **slice_axis axis along which the reconstruction will be sliced and plotted
|
||||
% **down_DVF (int) donsample DVF to make the arrows more sparse in the plot
|
||||
%
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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 show_deformation_field(rec_avg, deform_tensors, apodize_radial, Nsvd, binning, upscale_arrows, slice_axis, down_DVF)
|
||||
% show deformation vector field
|
||||
|
||||
Nblocks = length(deform_tensors);
|
||||
|
||||
for kk = 1:3
|
||||
for ll = 1:Nblocks+1
|
||||
if ll <= Nblocks
|
||||
shift_3D_mat(:,:,:,kk,ll) = deform_tensors{ll}{1,kk};
|
||||
else
|
||||
shift_3D_mat(:,:,:,kk,ll) = deform_tensors{ll-1}{min(end,2),kk};
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
[~,mask_small] = utils.apply_3D_apodization(deform_tensors{1}{1}, apodize_radial);
|
||||
|
||||
|
||||
|
||||
% apply mask on the results
|
||||
shift_3D_mat = shift_3D_mat .* mask_small;
|
||||
|
||||
% swap dimension to show the right plane
|
||||
switch slice_axis
|
||||
case 1
|
||||
rec_avg = rot90(permute(rec_avg, [2,3,1]),1);
|
||||
mask_small = rot90(permute(mask_small, [2,3,1]),1);
|
||||
shift_3D_mat = rot90(permute(shift_3D_mat, [2,3,1,4,5]),1);
|
||||
case 2
|
||||
rec_avg = rot90(permute(rec_avg, [1,3,2]),1);
|
||||
mask_small = rot90(permute(mask_small, [1,3,2]),1);
|
||||
shift_3D_mat = rot90(permute(shift_3D_mat, [2,3,1,4,5]),1);
|
||||
case 3
|
||||
end
|
||||
|
||||
|
||||
[Nx,Ny,Nlayers] = size(rec_avg);
|
||||
Nps = size(shift_3D_mat);
|
||||
mesh_2D = {1:down_DVF:Nps(1),1:down_DVF:Nps(2)};
|
||||
frame_s = ceil(Nps(3)/2);
|
||||
frame = ceil(Nlayers/2);
|
||||
|
||||
% calculate SVD
|
||||
shift_3D_mat = reshape(shift_3D_mat,[],Nblocks+1);
|
||||
[U,S,V] = math.fsvd(shift_3D_mat, Nsvd);
|
||||
U = reshape(U, [Nps(1:3), 3, Nsvd]);
|
||||
|
||||
U = U * sign(mean(V(:,1)));
|
||||
V = V * sign(mean(V(:,1)));
|
||||
if slice_axis == 3
|
||||
mean_amp = sqrt(mean(math.mean2(abs(U).^2 .* mask_small) ./ math.mean2(mask_small),3));
|
||||
else
|
||||
mean_amp = sqrt(mean(math.mean2(abs(U).^2)));
|
||||
end
|
||||
mean_amp = squeeze(mean_amp(1,1,1,:,1));
|
||||
mean_amp = mean_amp .* S(1) * V(3,1);
|
||||
mean_amp = mean_amp .* binning;
|
||||
fprintf('Mean deformation x:%3.2gpx y:%3.2gpx z:%3.2gpx \n',mean_amp )
|
||||
[~,S_tmp,~] = math.fsvd(shift_3D_mat, min(size(shift_3D_mat,2),Nsvd+10));
|
||||
fprintf(['Relative power of the modes:', repmat(' %3.3g%%, ',1,size(S_tmp,1)) , ' \n'], diag(S_tmp ./ sum(S_tmp(:)))*100 )
|
||||
|
||||
|
||||
figure(545)
|
||||
for mode = 1:Nsvd
|
||||
ax(mode) = subplot(2,Nsvd,mode);
|
||||
for kk = 1:3
|
||||
Q{mode,kk} = U(:,:,:,kk,mode) .* S(mode,mode);
|
||||
Q{mode,kk} = utils.imgaussfilt3_fft(Q{mode,kk}, down_DVF);
|
||||
end
|
||||
ygrid = ((1:Nps(1))-0.5)/Nps(1)*Nx;
|
||||
xgrid = ((1:Nps(2))-0.5)/Nps(2)*Ny;
|
||||
[x,y] = meshgrid(xgrid, ygrid);
|
||||
img = rec_avg(:,:,frame);
|
||||
img = min(1,img / math.sp_quantile(rec_avg(:), 0.95,5));
|
||||
imagesc(1-img, [-1,1]);
|
||||
colormap bone
|
||||
hold all
|
||||
|
||||
quiver(x(mesh_2D{:}),y(mesh_2D{:}),Q{mode,2}(mesh_2D{:},frame_s)*upscale_arrows, ...
|
||||
Q{mode,1}(mesh_2D{:},frame_s)*upscale_arrows,0,'Linewidth',2);
|
||||
axis off image
|
||||
hold off
|
||||
title(sprintf('%i. PCA of DVF field\n %ix upscaled',mode, upscale_arrows))
|
||||
subplot(2,Nsvd,Nsvd + mode)
|
||||
plot(V(:,mode))
|
||||
grid on
|
||||
axis tight
|
||||
xlabel('Interpolation node id')
|
||||
ylabel('Normalized evolution')
|
||||
end
|
||||
linkaxes(ax, 'xy')
|
||||
plotting.suptitle('Singular value decomposition of the DVF evolution')
|
||||
% end
|
||||
|
||||
figure(45545)
|
||||
subplot(1,2,1)
|
||||
plotting.imagesc3D(rec_avg, 'init_frame', size(rec_avg,3)/2)
|
||||
axis off image ; colormap bone
|
||||
colorbar
|
||||
title('Reconstruction example')
|
||||
subplot(1,2,2)
|
||||
deform = Q{1,1}*binning;
|
||||
plotting.imagesc3D(deform, 'init_frame', size(deform,3)/2)
|
||||
caxis(gather(math.sp_quantile(deform, [0.001, 0.999],5)))
|
||||
axis off image ; colormap bone
|
||||
title('Vertical deformation vector field')
|
||||
plotting.suptitle('1th PCA vector, horizontal cut')
|
||||
|
||||
drawnow
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
% show_reconstruction_quality - compare conventional reconstruction,
|
||||
% nonrigid reconstruction FBP and SART
|
||||
%
|
||||
% [rec_FBP, rec_NCT_FBP, rec_NCT_SART] = show_reconstruction_quality(sinogram, cfg, vectors, shift_3D_total, regularize_deform_evol)
|
||||
%
|
||||
% Inputs:
|
||||
% **sinogram current reconstruction
|
||||
% **vectors ASTRA configuration vectors
|
||||
% **cfg ASTRA configuration structure
|
||||
% **shift_3D_total recovered deformation vector field
|
||||
% **regularize_deform_evol regularization constant for the deformation field evolution calculation
|
||||
%
|
||||
% Outputs:
|
||||
% ++rec_FBP conventional FBP reconstruction
|
||||
% ++rec_NCT_FBP nonrigid FBP reconstruction
|
||||
% ++rec_NCT_SART nonrigid SART reconstruction
|
||||
%
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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) 2018 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 [rec_FBP, rec_NCT_FBP, rec_NCT_SART] = show_reconstruction_quality(sinogram, cfg, vectors, shift_3D_total, regularize_deform_evol)
|
||||
|
||||
Nangles = cfg.iProjAngles;
|
||||
|
||||
reset(gpuDevice)
|
||||
|
||||
Nblocks = length(shift_3D_total);
|
||||
split = astra.ASTRA_find_optimal_split(cfg);
|
||||
Bsize = ceil(Nangles/Nblocks);
|
||||
|
||||
if any(split(1:3)) > 1
|
||||
warning('Sample volume seems too large, try to reduce the reconstructed volume size')
|
||||
split(1:3) = 1; % at least try to make it work without splitting, otherwise recontruction will be poor
|
||||
end
|
||||
|
||||
rec_FBP = gather(tomo.FBP(sinogram, cfg, vectors)) ;
|
||||
|
||||
% generate deformation tensors from the shift tensors
|
||||
[deform_tensors, inv_deform_tensors] = nonrigid.get_deformation_fields(shift_3D_total, regularize_deform_evol, size(rec_FBP));
|
||||
|
||||
|
||||
%% FBP
|
||||
rec_NCT_FBP = nonrigid.FBP_deform(sinogram, cfg, vectors,Bsize, inv_deform_tensors);
|
||||
|
||||
|
||||
[SART_cache, cfg_SART] = tomo.SART_prepare(cfg, vectors, Bsize, split);
|
||||
SART_cache.R = min(1,SART_cache.R);
|
||||
|
||||
|
||||
|
||||
%% SART - solve it using all constraints
|
||||
[~,rec_mask] = utils.apply_3D_apodization(rec_NCT_FBP,0);
|
||||
rec_NCT_SART = rec_NCT_FBP;
|
||||
Niter_SART = 10;
|
||||
clear err_sart
|
||||
disp('====== SART ==========')
|
||||
|
||||
for kk = 1:Niter_SART
|
||||
utils.progressbar(kk, Niter_SART)
|
||||
[rec_NCT_SART,err_sart(kk,:)] = tomo.SART(rec_NCT_SART, sinogram, cfg_SART, vectors, SART_cache, split, ...
|
||||
'relax',0, 'deformation_fields', deform_tensors,'inv_deformation_fields', inv_deform_tensors, ...
|
||||
'constraint', @(x)(max(0,x.*rec_mask)), 'verbose',0);
|
||||
|
||||
% figure(1343)
|
||||
% subplot(1,2,1)
|
||||
% plot(err_sart)
|
||||
% hold all
|
||||
% plot(mean(err_sart'),'k', 'LineWidth',2)
|
||||
% hold off
|
||||
% set(gca, 'xscale', 'log')
|
||||
% set(gca, 'yscale', 'log')
|
||||
% grid on
|
||||
% axis tight
|
||||
% title('SART error evolution')
|
||||
% subplot(1,2,2)
|
||||
% plotting.imagesc3D(rec_NCT_SART, 'init_frame', floor(size(rec_NCT_SART,3)/2))
|
||||
% axis image
|
||||
% colormap bone
|
||||
% axis off image
|
||||
% drawnow
|
||||
|
||||
|
||||
end
|
||||
|
||||
% remove edges
|
||||
rec_FBP = utils.apply_3D_apodization(rec_FBP, 0);
|
||||
rec_NCT_FBP = utils.apply_3D_apodization(rec_NCT_FBP,0);
|
||||
|
||||
|
||||
figure(10)
|
||||
if exist('orig_phantom', 'var') && ~isempty(orig_phantom)
|
||||
orig_phantom = utils.crop_pad(orig_phantom, [cfg.iVolX,cfg.iVolY]);
|
||||
orig_phantom = orig_phantom ./ mean(orig_phantom(:)) * mean(rec_FBP(:))*0.9;
|
||||
rec_all = gather(cat(2, orig_phantom,rec_FBP, rec_NCT_FBP, rec_NCT_SART));
|
||||
else
|
||||
rec_all = gather(cat(2, rec_FBP, rec_NCT_FBP, rec_NCT_SART));
|
||||
end
|
||||
range = quantile(rec_all(:), [1e-2, 1-1e-2]);
|
||||
|
||||
plotting.imagesc3D(rec_all, 'init_frame', size(rec_all,3)/2)
|
||||
caxis(range);
|
||||
axis off image; colormap bone
|
||||
title('Original reconstruction / Deform FBP / Deform SART')
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,134 @@
|
||||
% show_rigid_corrections - plot recovered shifts for each of the projection
|
||||
%
|
||||
% show_rigid_corrections(rec, sinogram_shifted, err,shift_all, angles, iter, par)
|
||||
%
|
||||
% Inputs:
|
||||
% **rec current reconstruction
|
||||
% **sinogram_shifted sinogram with already applied position shifts
|
||||
% **err projection space (sinogram - model) error
|
||||
% **shift_all reconstructed projections
|
||||
% **angles angles of the projections
|
||||
% **iter current iteration
|
||||
% **par parameter structure of the nonrigid tomo
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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 show_rigid_corrections(rec, sinogram_shifted, err,shift_all, angles, iter, par)
|
||||
import utils.*
|
||||
import math.*
|
||||
|
||||
[Nlayers,~,~] = size(sinogram_shifted);
|
||||
|
||||
[angles, ind_sort] = sort(angles);
|
||||
sinogram_shifted = sinogram_shifted(:,:,ind_sort);
|
||||
err = err(:,ind_sort);
|
||||
shift_all = shift_all(:,ind_sort,:);
|
||||
|
||||
|
||||
verbose(1,'Plotting')
|
||||
|
||||
figure(5464)
|
||||
clf()
|
||||
subplot(2,3,1)
|
||||
|
||||
imagesc(squeeze(sinogram_shifted(ceil(Nlayers/2),:,:))');
|
||||
axis off
|
||||
colormap bone
|
||||
title('Corrected sinogram')
|
||||
|
||||
subplot(2,3,2)
|
||||
if iter > 1
|
||||
hold on
|
||||
plot(angles, (shift_all(iter,:,1)-shift_all(iter-1,:,1))*par.binning, 'r')
|
||||
plot(angles, (shift_all(iter,:,2)-shift_all(iter-1,:,2))*par.binning, 'b')
|
||||
hold off
|
||||
legend({'horiz', 'vert'})
|
||||
end
|
||||
title('Current position update')
|
||||
xlim([min(angles), max(angles)])
|
||||
ylabel('Shift [px]')
|
||||
xlabel('Angle [deg]')
|
||||
|
||||
subplot(2,3,3)
|
||||
hold on
|
||||
plot(angles,shift_all(iter,:,1)*par.binning, 'r')
|
||||
plot(angles,shift_all(iter,:,2)*par.binning, 'b')
|
||||
hold off
|
||||
title('Total position update')
|
||||
legend({'horiz', 'vert'})
|
||||
ylabel('Shift [px]')
|
||||
xlim([min(angles), max(angles)])
|
||||
xlabel('Angle [deg]')
|
||||
|
||||
|
||||
subplot(2,3,4)
|
||||
Nlayers = size(rec,3);
|
||||
plotting.imagesc3D(rec, 'init_frame', ceil(Nlayers/2))
|
||||
caxis(gather(math.sp_quantile(rec(:,:,ceil(Nlayers/2)), [0.01,0.99], 1)));
|
||||
axis off image
|
||||
title('Current reconstruction')
|
||||
colormap bone
|
||||
subplot(2,3,5)
|
||||
hold on
|
||||
plot(err)
|
||||
plot(mean(err,2), 'k', 'LineWidth', 3);
|
||||
hold off
|
||||
grid on
|
||||
axis tight
|
||||
xlim([1,iter+1])
|
||||
set(gca, 'xscale', 'log')
|
||||
set(gca, 'yscale', 'log')
|
||||
title('MSE evolution')
|
||||
xlabel('Iteration')
|
||||
ylabel('Mean square error')
|
||||
|
||||
|
||||
subplot(2,3,6)
|
||||
hold on
|
||||
plot(angles, err(end,:), 'k.')
|
||||
hold off
|
||||
if any(~par.valid_angles)
|
||||
legend({'errors', 'ignored'})
|
||||
end
|
||||
title('Current error')
|
||||
xlim([min(angles), max(angles)])
|
||||
xlabel('Angle [deg]')
|
||||
|
||||
drawnow
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,111 @@
|
||||
% show_sinograms - compare reconstructed and mesaured projections
|
||||
%
|
||||
% show_sinograms(rec_avg,dphase, vectors,cfg, angles, shift_3D_total, par, show_derivative = false )
|
||||
%
|
||||
% Inputs:
|
||||
% **rec_avg - optimal NCT reconstruction
|
||||
% **dphase phase difference calculated from the measured data
|
||||
% **vectors ASTRA configuration vectors
|
||||
% **cfg ASTRA configuration structure
|
||||
% **angles angles of the projections
|
||||
% **shift_3D_total recovered deformation vector field
|
||||
% **par parameter structure of the nonrigid tomo
|
||||
% *optional*
|
||||
% ++show_derivative if false, show directly the recovered signal otherwise the phase derivative
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| 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 show_sinograms(rec_avg,dphase, vectors,cfg, angles, shift_3D_total, par, show_derivative )
|
||||
if nargin < 8
|
||||
show_derivative = false; % show directly the recovered signal
|
||||
end
|
||||
|
||||
Nangles = cfg.iProjAngles;
|
||||
Nblocks = length(shift_3D_total);
|
||||
Bsize = ceil(Nangles/Nblocks);
|
||||
|
||||
% generate deformation tensors from the shift tensors
|
||||
deform_tensors = nonrigid.get_deformation_fields(shift_3D_total, par.regularize_deform_evol, size(rec_avg));
|
||||
|
||||
|
||||
|
||||
% SHOW ANIMATION OF PROJECTIONS
|
||||
rec_avg = gather(rec_avg);
|
||||
|
||||
split = astra.ASTRA_find_optimal_split(cfg,1,Nblocks);
|
||||
|
||||
for ll = 1:Nblocks
|
||||
ids = 1+(ll-1)*Bsize:min(Nangles, ll*Bsize);
|
||||
sinogram_corr(:,:,ids) = gather(tomo.Ax_sup_partial(rec_avg,cfg, vectors(ids,:),split, 'deformation_fields', deform_tensors{ll}));
|
||||
end
|
||||
|
||||
split = astra.ASTRA_find_optimal_split(cfg);
|
||||
sinogram_ideal = tomo.Ax_sup_partial(rec_avg,cfg, vectors,split);
|
||||
|
||||
if show_derivative
|
||||
dphase_avg = math.get_phase_gradient_1D(exp(-1i*sinogram_ideal),2);
|
||||
dphase_corr = math.get_phase_gradient_1D(exp(-1i*sinogram_corr),2);
|
||||
sino_diff = dphase_corr - math.sum2(dphase_corr .* dphase) ./ math.sum2(dphase.^2) .* dphase ;
|
||||
% sino_diff = dphase_corr - dphase ;
|
||||
dsino_range = math.sp_quantile(sino_diff,[0.001, 0.999],10);
|
||||
sino_diff = max(min(sino_diff, dsino_range(2)), dsino_range(1));
|
||||
sino_range = math.sp_quantile(dphase_avg,[0.001,0.999],10);
|
||||
sino_diff = (sino_diff-dsino_range(1))/diff(dsino_range)*sino_range(2);
|
||||
sino_all= cat(2,dphase_corr, dphase, sino_diff);
|
||||
else
|
||||
phase = -math.unwrap2D_fft(dphase, 2, par.air_gap);
|
||||
sino_diff = sinogram_corr - math.sum2(sinogram_corr .* phase) ./ math.sum2(phase.^2) .* phase ;
|
||||
sino_range = math.sp_quantile(sinogram_corr,[0.001,0.999],10);
|
||||
sino_all= cat(2,sinogram_corr,phase, sino_diff+sino_range(2)/2);
|
||||
end
|
||||
|
||||
[~,order] = sort(angles);
|
||||
figure(45864)
|
||||
plotting.imagesc3D(sino_all, 'order', order)
|
||||
axis off image xy
|
||||
colormap bone
|
||||
set(gca, 'clim', sino_range)
|
||||
str = 'Model / Data / Difference';
|
||||
if show_derivative
|
||||
str = [str, ' - showing phase-gradient'];
|
||||
else
|
||||
str = [str, ' - showing unwrapped phase'];
|
||||
end
|
||||
title(str)
|
||||
drawnow
|
||||
|
||||
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user