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
+152
View File
@@ -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