mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-17 23:59:11 +09:00
200 lines
9.8 KiB
Matlab
200 lines
9.8 KiB
Matlab
% MERGE_WEIGHTS_INTERIORED_ARRAYS auxiliar function for interior tomography for block processing by tomo.block_fun
|
||
% that adds up two arrays as X*W + (1-W)*Y, and unwrap resulting phase difference and
|
||
% return the phase
|
||
%
|
||
% phase_diff = merge_weights_interiored_arrays(stack_object, phase_diff_lowres, weights_interior,shift, ROI, param, exterior_weights_interior)
|
||
%
|
||
% Inputs:
|
||
% **stack_object - complex valued projections
|
||
% **phase_diff_lowres - phase gradient for the low resolution tomogram
|
||
% **weights_interior - relative weights_interiors of each region of the tomogram (denotes interior region )
|
||
% **shift - shifts applied to the phase gradient
|
||
% **ROI - region to be unwrapped
|
||
% **param - tomography parameter structure
|
||
% **exterior_weights_interior - scalar, relative weights_interior of the low res region during alignment
|
||
% Outputs:
|
||
% ++phase - unwrapped phase of the low + high resolution sinogram together
|
||
% ++weights_interiors - importance weights_interiors used for alignment, ie gives much smaller
|
||
% weights_interior to the low resolution region compared to the interion projection part
|
||
% based on the "exterior_weights_interior" input value
|
||
|
||
%*-----------------------------------------------------------------------*
|
||
%| |
|
||
%| 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 [phase_diff, weights_interiors] = merge_and_unwrap_sinograms(stack_object, tomo_lres, weights_interior,shift, theta, ROI, Nw_lres, param)
|
||
|
||
|
||
|
||
Npix_lres = size(tomo_lres);
|
||
Npix_full = ceil(Nw_lres*param.resolution_ratio);
|
||
|
||
% get phase difference of the interior tomo
|
||
phase_diff_interior = math.get_phase_gradient_1D(stack_object,2,0);
|
||
|
||
avg_shift = round(mean(shift));
|
||
Npix_partial = [size(stack_object,1), size(stack_object,2)]+2*ceil(max(abs(shift-avg_shift)));
|
||
Npix_partial = min(Npix_partial, Npix_full);
|
||
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%%% (1) UPSAMPLE WEIGHTS TO THE FULL RESOLUTION %%%%%
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
||
if isa(weights_interior, 'uint8') || ( isa(weights_interior, 'gpuArray') && strcmpi(classUnderlying(weights_interior),'uint8'))
|
||
% convert to single precision
|
||
weights_interior = single(weights_interior-1)/255;
|
||
end
|
||
if size(weights_interior,1) ~= size(stack_object,1) || size(weights_interior,2) ~= size(stack_object,2)
|
||
% assume that the weights_interior are stored downsampled to same memory
|
||
weights_interior = utils.interpolate_linear(weights_interior, size(stack_object));
|
||
end
|
||
|
||
% pad arrays with enough space for save shifting
|
||
phase_diff_interior = utils.crop_pad(phase_diff_interior , Npix_partial);
|
||
weights_interior = utils.crop_pad(weights_interior , Npix_partial);
|
||
|
||
|
||
|
||
% apply (shifts-avg_shift) on the interior tomogram and its weights_interiors
|
||
[phase_diff_interior, weights_interior] = shift_interior_sinograms(phase_diff_interior, weights_interior, shift-avg_shift);
|
||
|
||
|
||
|
||
[cfg_lres, vectors_lres] = astra.ASTRA_initialize(Npix_lres,Nw_lres,theta, 90, 0, 1);
|
||
|
||
% find optimal split of the dataset for given GPU
|
||
split = astra.ASTRA_find_optimal_split(cfg_lres);
|
||
% forward projection model
|
||
model = astra.Ax_partial(tomo_lres,cfg_lres, vectors_lres,split,'verbose', 0);
|
||
|
||
% get phase difference
|
||
phase_diff_lowres = math.get_phase_gradient_1D( exp(1i*model), 2, 0);
|
||
|
||
clear model
|
||
% use FFT centred upsampling to keep it accurate
|
||
%phase_diff_lowres = utils.interpolateFT_centered(phase_diff_lowres / param.resolution_ratio, Npix_full,1);
|
||
|
||
% linear interpolation is much faster but it introduces bias
|
||
bias = 1-1/param.resolution_ratio;
|
||
phase_diff_lowres = utils.imshift_fft(phase_diff_lowres,-[bias, bias]);
|
||
phase_diff_lowres = utils.interpolate_linear(phase_diff_lowres / param.resolution_ratio, Npix_full);
|
||
|
||
% pad arrays to full size and apply the average shift
|
||
phase_diff_interior = utils.imshift_fast(phase_diff_interior ,-avg_shift(1),-avg_shift(2), Npix_full);
|
||
weights_interior = utils.imshift_fast(weights_interior ,-avg_shift(1),-avg_shift(2), Npix_full);
|
||
|
||
alpha = 0.05; % avoid effects from weak regions of the weights
|
||
weights_interior = max(0, weights_interior-alpha)/(1-alpha); % remove artefacts from the FFT shift
|
||
|
||
% merge tomogram based on provided weights_interior
|
||
phase_diff = arrayfun(@merge_arrays,phase_diff_interior, phase_diff_lowres, weights_interior);
|
||
|
||
|
||
if ~isempty(param.vert_range)
|
||
% find optimal vertical range
|
||
Nlayers = length(ROI{1});
|
||
vrange0 = param.vert_range([1,end]);
|
||
vrange(2) = min(vrange0(2),Nlayers);
|
||
vrange(1) = max(1,vrange0(1));
|
||
|
||
% help with splitting in ASTRA (GPU memory limit)
|
||
vrange_center = ceil(mean(vrange));
|
||
estimated_split_factor = 4;
|
||
Nvert = floor((vrange(2)-vrange(1)+1) / estimated_split_factor)*estimated_split_factor;
|
||
vrange(1) = ceil(vrange_center - Nvert/2);
|
||
vrange(2) = floor(vrange_center + Nvert/2-1);
|
||
vrange = vrange(1):vrange(2);
|
||
else
|
||
vrange = ':';
|
||
end
|
||
|
||
|
||
|
||
% select only object_ROI -> make it easily splitable to GPU and avoid
|
||
% edge artefacts
|
||
phase_diff = phase_diff(ROI{1}(vrange),ROI{2},:);
|
||
weights_interior = weights_interior(ROI{1}(vrange),ROI{2},:);
|
||
|
||
|
||
% apply binning
|
||
if param.binning > 1
|
||
phase_diff = utils.interpolateFT_centered(phase_diff,ceil(size(phase_diff)/param.binning/2)*2, 1); % accurate interpolation using FFT
|
||
end
|
||
|
||
if strcmpi(param.unwrap_data_method, 'fft_1d')
|
||
phase_diff = math.unwrap2D_fft(phase_diff,2,param.air_gap,0);
|
||
end
|
||
|
||
% provide weights_interiors to be used for alignment
|
||
weights_interiors = param.exterior_weight + (1-param.exterior_weight)*weights_interior;
|
||
|
||
|
||
weights_interiors = utils.interpolate_linear(weights_interiors, ceil(size(weights_interiors)/10));
|
||
|
||
% keep in uint8 to save memory
|
||
weights_interiors = uint8(weights_interiors*255);
|
||
|
||
|
||
|
||
end
|
||
|
||
function C = merge_arrays(A, B, W)
|
||
W = max(0, min(1,W));
|
||
C = A.*W + (1-W).*B;
|
||
end
|
||
|
||
|
||
% FUNCTION [phase_diff_interior,weights_interior ] = shift_interior_sinograms(phase_diff_interior, weights_interior, shift )
|
||
% auxiliar function for interior tomography
|
||
% Inputs:
|
||
% phase_diff_interior - phase gradient for the interior tomo
|
||
% weights_interior - relative weights_interiors of each region of the tomogram (denotes interior region )
|
||
% shift - shifts applied to the phase gradient
|
||
% Outputs:
|
||
% phase_diff_interior - phase difference for only the interior part
|
||
% weights_interior - reliability weights_interiors estimated from the original field of view and shifted accordingly
|
||
|
||
function [phase_diff_interior,weights_interior ] = shift_interior_sinograms(phase_diff_interior, weights_interior, shift )
|
||
|
||
% shift phase and weights_interiors in parallel to save time and avoid numerical problems at the edges
|
||
phase_diff_interior = utils.imshift_fft(weights_interior .* exp(1i*phase_diff_interior),shift);
|
||
|
||
% get amplitude (weights_interiors)
|
||
weights_interior = abs(phase_diff_interior);
|
||
|
||
% get phase = phase diff
|
||
phase_diff_interior = angle(phase_diff_interior);
|
||
|
||
end
|