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
+199
View File
@@ -0,0 +1,199 @@
% 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