Contents
function [D, Q] = ... fmmisopropagation_base(W, start_pts, end_pts, order, L, niter, H, D0 )
% FMMISOPROPAGATION_BASE - Apply classical [OS88,KS98,SV00] and multistencil % [HF06,HF07] Fast Marching method (FMM) in 2D. % % D = FMMISOPROPAGATION_BASE(W, start_pts, end_pts, 0); % D = FMMISOPROPAGATION_BASE(W, start_pts, end_pts, 0, L, niter, H, D0); % Perform regular fast marching [KS98]. % % D = FMMISOPROPAGATION_BASE(W, start_pts, end_pts, 1); % D = FMMISOPROPAGATION_BASE(W, start_pts, end_pts, 1, L, niter, H, D0); % D = FMMISOPROPAGATION_BASE(W, start_pts, end_pts, 2); % D = FMMISOPROPAGATION_BASE(W, start_pts, end_pts, 2, L, niter, H, D0); % Perform multistencil fast marching [HF07] by using cross neighbours and % 1st or 2nd order derivatives. % % Inputs: % W : the scalar weight matrix (inverse of the speed); the geodesics will % follow regions where W is large; W must be > 0. % start_pts : a (2 x n) matrix where n is the number of starting points. % end_pts : a (2 x k) matrix where k is the number of ending points; the % FMM propagation stops when these points are reached. % order : scalar defining the method used to compute Fast Marching; it is % either: % - 0 for classical FMM [KS98] with the mex function FMMISOPROPAGATION_MEX % if it exists, or the Matlab function FMMSLOWPROPAGATION otherwise, % - 1 or 2 for Multistencil FMM of order 1 or 2 resp. [HF07], using % the mex function MSFM2D implemented by Kroon [MSFMM]. % L : optional constraint map to reduce the set of explored points, as % only points with current distance smaller than their values in L will % be visited; set entries to -Inf in L if you don't want points to be % visited by FMM; default: L=Inf, ie. all points are visited. % H : heuristic map; default: H=[]. % D0 : initial distance; default: D0=[], ie. all initial distances are null. % % Outputs: % D : a 2D array containing the value of the distance function to seed. % Q : optional variable returned when order=0; index of the closest point % from the set of starting points (0 for points which have not been % reached); Q provide a Voronoi decomposition of the domain. % % References: % [OS88] S. Osher and J. Sethian: "Fronts propagating with curvature speed: % Algorithms based on Hamilton-Jacobi formulations", J. Computational % Physics, 79:12-49, 1988. % [KS98] R. Kimmel and J. Sethian: "Computing geodesic paths on manifolds", % Proc. National Academy of Sciences, 95(15):8431-8435, 1998. % [SV00] J. Sethian and A. Vladimirsky: "Fast methods for the eikonal and % related Hamilton-Jacobi equations on unstructured meshes", Proc. % National Academy of Sciences, 97(11):5699-5703, 2000. % [HF06] M.S. Hassouna and A.A. Farag: "Accurate tracking of monotonically % advancing fronts," Proc. IEEE CVPR, vol. 1, pp. 355-362, 2006. % [HF07] M.S. Hassouna and A.A. Farag: "Multistencils fast marching % methods: a highly accurate solution to the eikonal equation on % cartesian domains", IEEE Trans. on Pattern Analysis and Machine % Intelligence, 29(9):1-12, 2007. % [MSFMM] Kroon's toolbox on multistencil FMM available at % http://www.mathworks.com/matlabcentral/fileexchange/24531-accurate-fast-marching % [PFMM] Peyre 's toolbox on FMM available at % https://www.ceremade.dauphine.fr/~peyre/matlab/fast-marching/content.html % % See also % Ressembles: FMM_BASE, FMMANISOPROPAGATION_BASE, DIJKSTRAPROPAGATION_BASE, % IM2FRONT_BASE, POTENTIAL2FRONT_BASE -- % Requires: FMMISOPROPAGATION_MEX, FM2DANISO_MEX.
Check the input parameters
% we allow variable inputs if nargin<=7, D0 = []; if nargin<=6, H = []; if nargin<=5, niter = Inf; end end end if nargin==4 || isempty(L), L = Inf(size(W(:,:,1,1))); end
Check/set the input is a scalar field used for isotropic propagation
d = nb_dims(W); if d==3 % a vector field has been passed: convert to the field magnitude W = sqrt(W(:,:,1).^2 + W(:,:,1).^2); elseif d==4 % a tensor field has been passed: compute the tensor norm W = rescale(im2potential_base(W, 'iso', 1)); % gstfeature_base(W(:,:,1,1), W(:,:,2,2), W(:,:,1,2), 'norm', 'zen'); end d = 2;
Call the mex functions or the default matlab
if order==0 if exist('fmmisopropagation_mex','file') % d = nb_dims(W); L(L==-Inf) = -1e9; L(L==Inf) = 1e9; niter = min(niter, 1.2*max(size(W))^d); [D, S, Q] = fmmisopropagation_mex(W, start_pts-1, end_pts-1, niter, H, L, D0 ); else [D, S, Q] = fmmslowpropagation(W, start_pts, end_pts ); end Q = Q+1; elseif ismember(order,[1 2]) % run Multistencil Fast Marching Method if ~exist('msfm2d','file') error('fmmisopropagation_base:methoderror', 'load Kroon''s fast marching library'); end usecross = true; % we by default use cross neighbours if order == 2, usesecond = true; else usesecond = false; end D = msfm2d(W, start_pts, usesecond, usecross); Q = []; else error('fmmisopropagation_base:inputerror', ... 'unknown order: should be in {0,1,2}'); end % replace C 'Inf' value (1e9) by Matlab Inf value. D(D>1e8) = Inf;
end %-------------------------------------------------------------------------- function [D, S, father] = fmmslowpropagation(W, start_pts, end_pts) % FMMSLOWPROPAGATION - Fast marching propagation method in Matlab. % [D,S] = fmmslowpropagation(W,start_points,end_points,nb_iter_max,H); niter = round( 1.2*size(W,1)^2 ); % dynamic allocation to initialize the data that records the state before/after % different steps of the FMM algorithm. data.D = Inf(size(W)); % action start_ind = sub2ind(size(W), start_pts(1,:), start_pts(2,:)); data.D( start_ind ) = 0; data.O = start_pts; % S=1 : far, S=0 : open, S=-1 : close data.S = ones(size(W)); data.S( start_ind ) = 0; data.W = W; data.father = zeros( [size(W),2] ); if ~isempty(end_pts) end_ind = sub2ind(size(W), end_pts(1,:), end_pts(2,:)); else end_ind = []; end i = 0; while i<niter && ~isempty(data.O) && isempty(find(data.S(end_ind)==-1,1,'first')) i = i+1; data = fastmarching_step(data); end D = data.D; S = data.S; father = data.father; end %-------------------------------------------------------------------------- function data1 = fastmarching_step(data) % FASTMARCHING_STEP - Perform one step in the Fast Marching algorithm. % data1 = fastmarching_step(data); % some constants for the state of (un)visited pixels kClose = -1; kOpen = 0; kFar = 1; D = data.D; % action, a 2D matrix O = data.O; % open list S = data.S; % state, either 'O' or 'C', a 2D matrix W = data.W; % weight matrix, a 2D array (speed function) father = data.father; [n,p] = size(D); % size of the grid % step size h = 1/n; if isempty(O) data1 = data; return; end ind_O = sub2ind(size(D), O(1,:), O(2,:)); [dum,I] = min(D(ind_O)); I = I(1); % selected vertex i = O(1,I); j = O(2,I); O(:,I) = []; % pop from open S(i,j) = kClose; % now its close % its neighbor nei = [1,0; 0,1; -1,0; 0,-1 ]; for k = 1:4 ii = i+nei(k,1); jj = j+nei(k,2); if ii>0 && jj>0 && ii<=n && jj<=p f = [0 0]; % current father
update the action using Upwind resolution
P = h/W(ii,jj); % neighbors values a1 = Inf; if ii<n a1 = D( ii+1,jj ); f(1) = sub2ind(size(W), ii+1,jj); end if ii>1 && D( ii-1,jj )<a1 a1 = D( ii-1,jj ); f(1) = sub2ind(size(W), ii-1,jj); end a2 = Inf; if jj<n a2 = D( ii,jj+1 ); f(2) = sub2ind(size(W), ii,jj+1); end if jj>1 && D( ii,jj-1 )<a2 a2 = D( ii,jj-1 ); f(2) = sub2ind(size(W), ii,jj-1); end if a1>a2 % swap to reorder tmp = a1; a1 = a2; a2 = tmp; f = f([2 1]); end % now the equation is (a-a1)^2+(a-a2)^2 = P, with a >= a2 >= a1. if P^2 > (a2-a1)^2 delta = 2*P^2-(a2-a1)^2; A1 = (a1+a2+sqrt(delta))/2; else A1 = a1 + P; f(2) = 0; end switch S(ii,jj) case kClose % check if action has change. Should not appen for FM if A1<D(ii,jj) % warning('FastMarching:NonMonotone', 'The update is not monotone'); % pop from Close and add to Open if false % don't reopen close points O(:,end+1) = [ii;jj]; %#ok S(ii,jj) = kOpen; D(ii,jj) = A1; end end case kOpen % check if action has change. if A1<D(ii,jj) D(ii,jj) = A1; father(ii,jj,:) = f; end case kFar %if D(ii,jj)~=Inf, warning('initialize Action to Inf'); end % add to open O(:,end+1) = [ii;jj]; %#ok S(ii,jj) = kOpen; % action must have change. D(ii,jj) = A1; father(ii,jj,:) = f; otherwise error('fastmarching_step:methoderror','unknown state'); end end end data1.D = D; data1.O = O; data1.S = S; data1.W = W; data1.father = father; end