mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-17 21:39:08 +09:00
153 lines
5.8 KiB
Matlab
153 lines
5.8 KiB
Matlab
% 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
|
||
|