Code covered by the BSD License  

Highlights from
Iterative Closest Point Method

image thumbnail
from Iterative Closest Point Method by Per Bergström
ICP fit points in data to the points in model.

icp(model,data,max_iter,min_iter,fitting,thres,init_flag,tes_flag,refpnt)
function [TR, TT] = icp(model,data,max_iter,min_iter,fitting,thres,init_flag,tes_flag,refpnt)
% ICP Iterative Closest Point Algorithm. Takes use of
% Delaunay tesselation of points in model.
%
%   Ordinary usage:
%
%   [R, T] = icp(model,data)
%
%   ICP fit points in data to the points in model.
%   Fit with respect to minimize the sum of square
%   errors with the closest model points and data points.
%
%   INPUT:
%
%   model - matrix with model points, [Pm_1 Pm_2 ... Pm_nmod]
%   data - matrix with data points,   [Pd_1 Pd_2 ... Pd_ndat]
%
%   OUTPUT:
%
%   R - rotation matrix and
%   T - translation vector accordingly so
%
%           newdata = R*data + T .
%
%   newdata are transformed data points to fit model
%
%
%   Special usage:
%
%   icp(model)  or icp(model,tes_flag)
%
%   ICP creates a Delaunay tessellation of points in
%   model and save it as global variable Tes. ICP also
%   saves two global variables ir and jc for tes_flag=1 (default) or
%   Tesind and Tesver for tes_flag=2, which
%   makes it easy to find in the tesselation. To use the global variables
%   in icp, put tes_flag to 0.
%
%
%   Other usage:
%
%   [R, T] = icp(model,data,max_iter,min_iter,...
%                         fitting,thres,init_flag,tes_flag)
%
%   INPUT:
%
% 	max_iter - maximum number of iterations. Default=104
%
% 	min_iter - minimum number of iterations. Default=4
%
%   fitting  -  =2 Fit with respect to minimize the sum of square errors. (default)
%                  alt. =[2,w], where w is a weight vector corresponding to data.
%                  w is a vector of same length as data.
%                  Fit with respect to minimize the weighted sum of square errors.
%               =3 Fit with respect to minimize the sum to the amount 0.95
%                  of the closest square errors.
%                  alt. =[3,lambda], 0.0<lambda<=1.0, (lambda=0.95 default)
%                  In each iteration only the amount lambda of the closest
%                  points will affect the translation and rotation.
%                  If 1<lambda<=size(data,2), lambda integer, only the number lambda
%                  of the closest points will affect the translation and
%                  rotation in each iteration.
%
% 	thres - error differens threshold for stop iterations. Default 1e-5
%
% 	init_flag  -  =0 no initial starting transformation
%                 =1 transform data so the mean value of
%                     data is equal to mean value of model.
%                     No rotation. (init_flag=1 default)
%
% 	tes_flag  -  =0 No new tesselation has to be done. There
%                   alredy exists one for the current model points.
%                =1 A new tesselation of the model points will
%                   be done. (default)
%                =2 A new tesselation of the model points will
%                   be done. Another search strategy than tes_flag=1
%                =3 The closest point will be find by testing
%                   all combinations. No Delaunay tesselation will be done.
%
%   refpnt - (optional) (An empty vector is default.) refpnt is a point corresponding to the
%                 set of model points wich correspondig data point has to be find.
%                 How the points are weighted depends on the output from the
%                 function weightfcn found in the end of this m-file. The input in weightfcn is the
%                 distance between the closest model point and refpnt.
%
%   To clear old global tesselation variables run: "clear global Tes ir jc" (tes_flag=1)
%   or run: "clear global Tes Tesind Tesver" (tes_flag=2) in Command Window.
%
%   m-file can be downloaded for free at
%   http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=12627&objectType=FILE
%
%   icp version 1.4
%
%   written by Per Bergstrm 2007-03-07

if nargin<1

    error('To few input arguments!');

elseif or(nargin==1,nargin==2)

    bol=1;
    refpnt=[];
    if nargin==2
        if isempty(data)
            tes_flag=1;
        elseif isscalar(data)
            tes_flag=data;
            if not(tes_flag==1 | tes_flag==2)
                tes_flag=1;
            end
        else
            bol=0;
        end
    else
        tes_flag=1;
    end

    if bol

        global MODEL

        if isempty(model)
            error('Model can not be an empty matrix.');
        end

        if (size(model,2)<size(model,1))
            MODEL=model';
            TR=eye(size(model,2));
            TT=zeros(size(model,2),1);
        else
            MODEL=model;
            TR=eye(size(model,1));
            TT=zeros(size(model,1),1);
        end

        if (size(MODEL,2)==size(MODEL,1))
            error('This icp method demands the number of MODEL points to be greater then the dimension.');
        end

        icp_struct(tes_flag);

        return
    end
end

global MODEL DATA TR TT

if isempty(model)
    error('Model can not be an empty matrix.');
end

if (size(model,2)<size(model,1))
    MODEL=model';
else
    MODEL=model;
end

if (size(data,2)<size(data,1))
    data=data';
    DATA=data;
else
    DATA=data;
end

if size(DATA,1)~=size(MODEL,1)
    error('Different dimensions of DATA and MODEL!');
end

if nargin<9
    refpnt=[];
    if nargin<8
        tes_flag=1;
        if nargin<7
            init_flag=1;
            if nargin<6
                thres=1e-5;                     % threshold to icp iterations
                if nargin<5
                    fitting=2;                  % fitting method
                    if nargin<4
                        min_iter=4;             % min number of icp iterations
                        if nargin<3
                            max_iter=104;       % max number of icp iterations
                        end
                    end
                end
            end
        end
    end
elseif nargin>9
    warning('Too many input arguments!');
end

if isempty(tes_flag)
    tes_flag=1;
elseif not(tes_flag==0 | tes_flag==1 | tes_flag==2 | tes_flag==3)
    init_flag=1;
    warning('init_flag has been changed to 1');
end

if and((size(MODEL,2)==size(MODEL,1)),tes_flag~=0)
    error('This icp method demands the number of model points to be greater then the dimension.');
end

if isempty(min_iter)
    min_iter=4;
end

if isempty(max_iter)
    max_iter=100+min_iter;
end

if max_iter<min_iter;
    max_iter=min_iter;
    warning('max_iter<min_iter , max_iter has been changed to be equal min_iter');
end

if min_iter<0;
    min_iter=0;
    warning('min_iter<0 , min_iter has been changed to be equal 0');
end

if isempty(thres)
    thres=1e-5;
elseif thres<0
    thres=abs(thres);
    warning('thres negative , thres have been changed to -thres');
end

if isempty(fitting)

    fitting=2;

elseif fitting(1)==2

    [fi1,fi2]=size(fitting);
    lef=max([fi1,fi2]);
    if lef>1
        if fi1<fi2
            fitting=fitting';
        end

        if lef<(size(data,2)+1)
            warning('Illegeal size of fitting! Unweighted minimization will be used.');
            fitting=2;
        elseif min(fitting(2:(size(data,2)+1)))<0
            warning('Illegeal value of the weights! Unweighted minimization will be used.');
            fitting=2;
        elseif max(fitting(2:(size(data,2)+1)))==0
            warning('Illegeal values of the weights! Unweighted minimization will be used.');
            fitting=2;
        else
            su=sum(fitting(2:(size(data,2)+1)));
            fitting(2:(size(data,2)+1))=fitting(2:(size(data,2)+1))/su;
            thres=thres/su;
        end
    end

elseif fitting(1)==3
    if length(fitting)<2
        fitting=[fitting,round(0.95*size(data,2))];
    elseif fitting(2)>1

        if fitting(2)>floor(fitting(2))
            fitting(2)=floor(fitting(2));
            warning(['lambda has been changed to ',num2str(fitting(2)),'!']);
        end
        if fitting(2)>size(data,2)
            fitting(2)=size(data,2);
            warning(['lambda has been changed to ',num2str(fitting(2)),'!']);
        end

    elseif fitting(2)>0

        if fitting(2)<=0.5
            warning('lambda small. Troubles might occur!');
        end

        fitting(2)=round(fitting(2)*size(data,2));

    elseif fitting(2)<=0
        fitting(2)=round(0.95*size(data,2));
        warning(['lambda has been changed to ',num2str(fitting(2)),'!']);
    end

else
    fitting=2;
    warning('fitting has been changed to 2');
end

if isempty(init_flag)
    init_flag=1;
elseif not(init_flag==0 | init_flag==1)
    init_flag=1;
    warning('init_flag has been changed to 1');
end

if (size(refpnt,2)>size(refpnt,1))
    refpnt=refpnt';
end
if (size(refpnt,1)~=size(DATA,1))
    if not(isempty(refpnt))
        refpnt=[];
        warning('Dimension of refpnt dismatch. refpnt is put to [] (empty matrix).');
    end
end
if (size(refpnt,2)>1)
    refpnt=refpnt(:,1);
    warning('Only the first point in refpnt is used.');
end

% Start the ICP algorithm

N = size(DATA,2);

icp_init(init_flag,fitting);                    % initiate a starting rotation matrix and starting translation vector

tes_flag=icp_struct(tes_flag);                  % construct a Delaunay tesselation and two vectors make it easy to find in Tes

ERROR=icp_closest_start(tes_flag,fitting);      % initiate a vector with indices of closest MODEL points

icp_transformation(fitting,[]);                 % find transformation

DATA = TR*data;                                 % apply transformation
DATA=DATA+repmat(TT,1,N);                       %

for iter=1:max_iter
    olderror = ERROR;
    ERROR=icp_closest(tes_flag,fitting);        % find indices of closest MODEL points and total error

    if iter<min_iter
        icp_transformation(fitting,[]);         % find transformation
    else
        icp_transformation(fitting,refpnt);     % find transformation
    end

    DATA = TR*data;                             % apply transformation
    DATA=DATA+repmat(TT,1,N);                   %

    if iter>=min_iter
        if abs(olderror-ERROR) < thres
            break
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function icp_init(init_flag,fitting)
%function icp_init(init_flag)
%ICP_INIT Initial alignment for ICP.

global MODEL DATA TR TT

if init_flag==0

    TR=eye(size(MODEL,1));
    TT=zeros(size(MODEL,1),1);

elseif init_flag==1

    N = size(DATA,2);

    if fitting(1)==2

        if length(fitting)==1
            mem=mean(MODEL,2); med=mean(DATA,2);
        else
            mem=MODEL*fitting(2:(N+1)); med=DATA*fitting(2:(N+1));
        end

    else
        mem=mean(MODEL,2); med=mean(DATA,2);
    end

    TR=eye(size(MODEL,1));
    TT=mem-med;
    DATA=DATA+repmat(TT,1,N);                         % apply transformation

else
    error('Wrong init_flag');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function tes_flag=icp_struct(tes_flag)

if tes_flag==0
    global ir
    if isempty(ir)
        global Tesind
        if isempty(Tesind)
            error('No tesselation system exists');
        else
            tes_flag=2;
        end
    else
        tes_flag=1;
    end
elseif tes_flag==3
    return
else
    global MODEL Tes

    [m,n]=size(MODEL);

    if m==1
        [so1,ind1]=sort(MODEL);
        Tes=zeros(n,2);
        Tes(1:(n-1),1)=ind1(2:n)';
        Tes(2:n,2)=ind1(1:(n-1))';
        Tes(1,2)=Tes(1,1);
        Tes(n,1)=Tes(n,2);
        Tes(ind1,:)=Tes(:,:);
    else
        Tes=delaunayn(MODEL');

        if isempty(Tes)

            mem=mean(MODEL,2);
            MODELm=MODEL-repmat(mem,1,n);
            [U,S,V]=svd(MODELm*MODELm');
            onbasT=U(:,diag(S)>1e-8)'
            MODELred=onbasT*MODEL;

            if size(MODELred,1)==1
                [so1,ind1]=sort(MODELred);
                Tes=zeros(n,2);
                Tes(1:(n-1),1)=ind1(2:n)';
                Tes(2:n,2)=ind1(1:(n-1))';
                Tes(1,2)=Tes(1,1);
                Tes(n,1)=Tes(n,2);
                Tes(ind1,:)=Tes(:,:);
            else
                Tes=delaunayn(MODELred');
            end
        end
    end
    Tes=sortrows(sort(Tes,2));
    [mT,nT]=size(Tes);

    if tes_flag==1
        global ir jc

        num=zeros(1,n);

        for i=1:mT
            for j=1:nT
                num(Tes(i,j))=num(Tes(i,j))+1;
            end
        end

        num=cumsum(num);

        jc=ones(1,n+1);
        jc(2:end)=num+jc(2:end);

        ir=zeros(1,num(end));
        ind=jc(1:(end-1));

        %% calculate ir;
        for i=1:mT
            for j=1:nT
                ir(ind(Tes(i,j)))=i;
                ind(Tes(i,j))=ind(Tes(i,j))+1;
            end
        end
    else    % tes_flag==2
        global Tesind Tesver

        Tesind=zeros(mT,nT);
        Tesver=zeros(mT,nT);

        couvec=zeros(mT,1);

        for i=1:(mT-1)
            for j=(i+1):mT

                if couvec(i)==nT
                    break;
                elseif Tes(i,1)==Tes(j,1)

                    if nT==2

                        Tesind(i,2)=j;
                        Tesind(j,2)=i;

                        Tesver(i,2)=2;
                        Tesver(j,2)=2;

                        couvec(i)=couvec(i)+1;
                        couvec(j)=couvec(j)+1;

                    else

                        for k=2:nT
                            for kk=k:nT
                                if all(Tes(i,[2:(k-1),(k+1):nT])==Tes(j,[2:(kk-1),(kk+1):nT]))
                                    Tesind(i,k)=j;
                                    Tesind(j,kk)=i;

                                    Tesver(i,k)=kk;
                                    Tesver(j,kk)=k;

                                    couvec(i)=couvec(i)+1;
                                    couvec(j)=couvec(j)+1;
                                end
                            end

                            if or(couvec(i)==nT,couvec(j)==nT)
                                break
                            end
                        end

                    end

                elseif Tes(i,1)==Tes(j,2)

                    if nT==2

                        Tesind(i,2)=j;
                        Tesind(j,1)=i;

                        Tesver(i,2)=1;
                        Tesver(j,1)=2;

                        couvec(i)=couvec(i)+1;
                        couvec(j)=couvec(j)+1;

                    else
                        for k=2:nT

                            if all(Tes(i,[2:(k-1),(k+1):nT])==Tes(j,3:nT))
                                Tesind(i,k)=j;
                                Tesind(j,1)=i;

                                Tesver(i,k)=1;
                                Tesver(j,1)=k;

                                couvec(i)=couvec(i)+1;
                                couvec(j)=couvec(j)+1;
                            end

                            if or(couvec(i)==nT,couvec(j)==nT)
                                break
                            end
                        end
                    end

                elseif Tes(i,2)==Tes(j,1)

                    if nT==2

                        Tesind(i,1)=j;
                        Tesind(j,2)=i;
                        Tesver(i,1)=2;
                        Tesver(j,2)=1;

                        couvec(i)=couvec(i)+1;
                        couvec(j)=couvec(j)+1;

                    else

                        for k=2:nT

                            if all(Tes(i,3:nT)==Tes(j,[2:(k-1),(k+1):nT]))
                                Tesind(i,1)=j;
                                Tesind(j,k)=i;
                                Tesver(i,1)=k;
                                Tesver(j,k)=1;

                                couvec(i)=couvec(i)+1;
                                couvec(j)=couvec(j)+1;
                            end

                            if or(couvec(i)==nT,couvec(j)==nT)
                                break
                            end

                        end

                    end

                elseif Tes(i,2)==Tes(j,2)

                    if nT==2

                        Tesind(i,1)=j;
                        Tesind(j,1)=i;

                        Tesver(i,1)=1;
                        Tesver(j,1)=1;

                        couvec(i)=couvec(i)+1;
                        couvec(j)=couvec(j)+1;

                        if Tes(j,1)>Tes(i,2)
                            break;
                        end

                    elseif all(Tes(i,3:end)==Tes(j,3:end))

                        Tesind(i,1)=j;
                        Tesind(j,1)=i;

                        Tesver(i,1)=1;
                        Tesver(j,1)=1;

                        couvec(i)=couvec(i)+1;
                        couvec(j)=couvec(j)+1;

                    end

                elseif Tes(j,1)>Tes(i,2)
                    break;
                end
            end
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function ERROR=icp_closest_start(tes_flag,fitting)
% Usage:
%           ERROR = icp_closest_start(tes_flag)
%
% ERROR=sum of all errors between points in MODEL and points in DATA.
%
% ICP_CLOSEST_START finds indexes of closest MODEL points for each point in DATA.
% The _start version allocates memory for iclosest and finds the closest MODEL points
% to the DATA points

if tes_flag==3

    global MODEL DATA iclosest
    md=size(DATA,2);
    mm=size(MODEL,2);

    iclosest=zeros(1,md);

    ERROR=0;

    for id=1:md
        dist=Inf;
        for im=1:mm
            dista=norm(MODEL(:,im)-DATA(:,id));
            if dista<dist
                iclosest(id)=im;
                dist=dista;
            end
        end
        ERROR=ERROR+err(dist,fitting,id);
    end

elseif tes_flag==1

    global MODEL DATA Tes ir jc iclosest

    md=size(DATA,2);
    iclosest=zeros(1,md);
    mid=round(md/2);

    iclosest(mid)=round(size(MODEL,2)/2);

    bol=logical(1);
    while bol
        bol=not(bol);
        distc=norm(DATA(:,mid)-MODEL(:,iclosest(mid)));
        distcc=2*distc;
        for in=ir(jc(iclosest(mid)):(jc(iclosest(mid)+1)-1))
            for ind=Tes(in,:)
                distcc=norm(DATA(:,mid)-MODEL(:,ind));
                if distcc<distc
                    distc=distcc;
                    bol=not(bol);
                    iclosest(mid)=ind;
                    break;
                end
            end
            if bol
                break;
            end
        end
    end

    ERROR=err(distc,fitting,mid);

    for id = (mid+1):md
        iclosest(id)=iclosest(id-1);
        bol=not(bol);
        while bol
            bol=not(bol);
            distc=norm(DATA(:,id)-MODEL(:,iclosest(id)));
            distcc=2*distc;
            for in=ir(jc(iclosest(id)):(jc(iclosest(id)+1)-1))
                for ind=Tes(in,:)
                    distcc=norm(DATA(:,id)-MODEL(:,ind));
                    if distcc<distc
                        distc=distcc;
                        bol=not(bol);
                        iclosest(id)=ind;
                        break;
                    end
                end
                if bol
                    break;
                end
            end
        end
        ERROR=ERROR+err(distc,fitting,id);
    end

    for id=(mid-1):-1:1
        iclosest(id)=iclosest(id+1);
        bol=not(bol);
        while bol
            bol=not(bol);
            distc=norm(DATA(:,id)-MODEL(:,iclosest(id)));
            distcc=2*distc;
            for in=ir(jc(iclosest(id)):(jc(iclosest(id)+1)-1))
                for ind=Tes(in,:)
                    distcc=norm(DATA(:,id)-MODEL(:,ind));
                    if distcc<distc
                        distc=distcc;
                        bol=not(bol);
                        iclosest(id)=ind;
                        break;
                    end
                end
                if bol
                    break;
                end
            end
        end
        ERROR=ERROR+err(distc,fitting,id);
    end
else  % tes_flag==2

    global MODEL DATA Tes Tesind Tesver icTesind iclosest

    md=size(DATA,2);
    iclosest=zeros(1,md);
    icTesind=zeros(1,md);

    [mTes,nTes]=size(Tes);

    mid=round(md*0.5);

    icTesind(mid)=round(mTes*0.5);
    iclosest(mid)=max(Tesind(icTesind(mid),:));

    visited=logical(zeros(1,mTes));

    visited(icTesind(mid))=1;

    di2vec=sqrt(sum((repmat(DATA(:,mid),1,nTes)-MODEL(:,Tes(icTesind(mid),:))).^2,1));
    bol=logical(1);

    while bol

        [so,in]=sort(di2vec);

        for ii=nTes:-1:2
            Ti=Tesind(icTesind(mid),in(ii));
            if Ti>0
                if not(visited(Ti))
                    break;
                end
            end
        end

        if Ti==0
            bol=not(bol);
        elseif visited(Ti)
            bol=not(bol);
        else
            Tv=Tesver(icTesind(mid),in(ii));
            visited(Ti)=1;
            icTesind(mid)=Ti;
            di2vec([1:(Tv-1),(Tv+1):nTes])=di2vec([1:(in(ii)-1),(in(ii)+1):nTes]);
            di2vec(Tv)=norm(DATA(:,mid)-MODEL(:,Tes(Ti,Tv)));
        end
    end
    iclosest(mid)=Tes(icTesind(mid),in(1));
    ERROR=err(so(1),fitting,mid);

    for id = (mid+1):md

        iclosest(id)=iclosest(id-1);
        icTesind(id)=icTesind(id-1);

        visited(:)=0;
        visited(icTesind(id))=1;

        di2vec=sqrt(sum((repmat(DATA(:,id),1,nTes)-MODEL(:,Tes(icTesind(id),:))).^2,1));
        bol=not(bol);

        while bol

            [so,in]=sort(di2vec);

            for ii=nTes:-1:2
                Ti=Tesind(icTesind(id),in(ii));
                if Ti>0
                    if not(visited(Ti))
                        break;
                    end
                end
            end

            if Ti==0
                bol=not(bol);
            elseif visited(Ti)
                bol=not(bol);
            else
                Tv=Tesver(icTesind(id),in(ii));
                visited(Ti)=1;
                icTesind(id)=Ti;
                di2vec([1:(Tv-1),(Tv+1):nTes])=di2vec([1:(in(ii)-1),(in(ii)+1):nTes]);
                di2vec(Tv)=norm(DATA(:,id)-MODEL(:,Tes(Ti,Tv)));
            end
        end
        iclosest(id)=Tes(icTesind(id),in(1));
        ERROR=ERROR+err(so(1),fitting,id);
    end

    for id=(mid-1):-1:1

        iclosest(id)=iclosest(id+1);
        icTesind(id)=icTesind(id+1);

        visited(:)=0;
        visited(icTesind(id))=1;

        di2vec=sqrt(sum((repmat(DATA(:,id),1,nTes)-MODEL(:,Tes(icTesind(id),:))).^2,1));
        bol=not(bol);

        while bol

            [so,in]=sort(di2vec);

            for ii=nTes:-1:2
                Ti=Tesind(icTesind(id),in(ii));
                if Ti>0
                    if not(visited(Ti))
                        break;
                    end
                end
            end

            if Ti==0
                bol=not(bol);
            elseif visited(Ti)
                bol=not(bol);
            else
                Tv=Tesver(icTesind(id),in(ii));
                visited(Ti)=1;
                icTesind(id)=Ti;
                di2vec([1:(Tv-1),(Tv+1):nTes])=di2vec([1:(in(ii)-1),(in(ii)+1):nTes]);
                di2vec(Tv)=norm(DATA(:,id)-MODEL(:,Tes(Ti,Tv)));
            end
        end
        iclosest(id)=Tes(icTesind(id),in(1));
        ERROR=ERROR+err(so(1),fitting,id);
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function ERROR=icp_closest(tes_flag,fitting)
% Usage:
%           ERROR = icp_closest(tes_flag,fitting)
%
% ERROR=sum of all errors between points in model and points in data.
%
% ICP_CLOSEST finds indexes of closest model points for each point in data.

if tes_flag==3

    global MODEL DATA iclosest
    md=size(DATA,2);
    mm=size(MODEL,2);

    ERROR=0;

    for id=1:md
        dist=Inf;
        for im=1:mm
            dista=norm(MODEL(:,im)-DATA(:,id));
            if dista<dist
                iclosest(id)=im;
                dist=dista;
            end
        end
        ERROR=ERROR+err(dist,fitting,id);
    end

elseif tes_flag==1

    global MODEL DATA Tes ir jc iclosest

    [mTes,nTes]=size(Tes);
    ERROR=0;
    bol=logical(0);

    for id=1:size(DATA,2)

        bol=not(bol);
        while bol
            bol=not(bol);
            distc=norm(DATA(:,id)-MODEL(:,iclosest(id)));
            distcc=2*distc;
            for in=ir(jc(iclosest(id)):(jc(iclosest(id)+1)-1))
                for ind=Tes(in,:)
                    distcc=norm(DATA(:,id)-MODEL(:,ind));
                    if distcc<distc
                        distc=distcc;
                        bol=not(bol);
                        iclosest(id)=ind;
                        break;
                    end
                end
                if bol
                    break;
                end
            end
        end
        ERROR=ERROR+err(distc,fitting,id);
    end

else  % tes_flag==2

    global MODEL DATA Tes Tesind Tesver iclosest icTesind

    [mTes,nTes]=size(Tes);
    ERROR=0;
    bol=logical(0);
    visited=logical(zeros(1,mTes));

    for id=1:size(DATA,2)
        visited(:)=0;
        visited(icTesind(id))=1;

        di2vec=sqrt(sum((repmat(DATA(:,id),1,nTes)-MODEL(:,Tes(icTesind(id),:))).^2,1));
        bol=not(bol);

        while bol

            [so,in]=sort(di2vec);

            for ii=nTes:-1:2
                Ti=Tesind(icTesind(id),in(ii));
                if Ti>0
                    if not(visited(Ti))
                        break;
                    end
                end
            end

            if Ti==0
                bol=not(bol);
            elseif visited(Ti)
                bol=not(bol);
            else
                Tv=Tesver(icTesind(id),in(ii));
                visited(Ti)=1;
                icTesind(id)=Ti;
                di2vec([1:(Tv-1),(Tv+1):nTes])=di2vec([1:(in(ii)-1),(in(ii)+1):nTes]);
                di2vec(Tv)=norm(DATA(:,id)-MODEL(:,Tes(Ti,Tv)));
            end
        end
        iclosest(id)=Tes(icTesind(id),in(1));
        ERROR=ERROR+err(so(1),fitting,id);
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function icp_transformation(fitting,refpnt)
% Finds the rotation and translation of the DATA points

global MODEL DATA iclosest TR TT

M=size(DATA,1);
N=size(DATA,2);

bol=0;

if not(isempty(refpnt))
    bol=1;
    dis=sqrt(sum((MODEL(:,iclosest)-repmat(refpnt,1,N)).^2,1));
    weights=weightfcn(dis');
end

if bol

    if fitting(1)==2

        if length(fitting)>1
            weights=fitting(2:(N+1)).*weights;
            weights=weights/sum(weights);
        end

        med=DATA*weights; mem=MODEL(:,iclosest)*weights;
        A=DATA-repmat(med,1,N);
        B=MODEL(:,iclosest)-repmat(mem,1,N);

        for i=1:N
            A(:,i)=weights(i)*A(:,i);
        end

    elseif fitting(1)==3

        V=sum((DATA-MODEL(:,iclosest)).^2,1);
        [soV,in]=sort(V);
        ind=in(1:fitting(2));

        weights(ind)=weights(ind)/sum(weights(ind));

        med=DATA(:,ind)*weights(ind); mem=MODEL(:,iclosest(ind))*weights(ind);
        A=DATA(:,ind)-repmat(med,1,fitting(2));
        B=MODEL(:,iclosest(ind))-repmat(mem,1,fitting(2));

        for i=1:fitting(2)
            A(:,i)=weights(ind(i))*A(:,ind(i));
        end

    end

else

    if fitting(1)==2

        if length(fitting)==1

            med=mean(DATA,2); mem=mean(MODEL(:,iclosest),2);
            A=DATA-repmat(med,1,N);
            B=MODEL(:,iclosest)-repmat(mem,1,N);

        else

            med=DATA*fitting(2:(N+1)); mem=MODEL(:,iclosest)*fitting(2:(N+1));
            A=DATA-repmat(med,1,N);
            B=MODEL(:,iclosest)-repmat(mem,1,N);

            for i=1:N
                A(:,i)=fitting(i+1)*A(:,i);
            end

        end

    elseif fitting(1)==3

        V=sum((DATA-MODEL(:,iclosest)).^2,1);
        [soV,in]=sort(V);
        ind=in(1:fitting(2));

        med=mean(DATA(:,ind),2); mem=mean(MODEL(:,iclosest(ind)),2);
        A=DATA(:,ind)-repmat(med,1,fitting(2));
        B=MODEL(:,iclosest(ind))-repmat(mem,1,fitting(2));

    end

end

[U,S,V] = svd(B*A');
U(:,end)=U(:,end)*det(U*V');
R=U*V';

% Compute the translation
T=(mem-R*med);
TR=R*TR;  TT=R*TT+T;

function ERR=err(dist,fitting,ind)

if fitting(1)==2
    if (ind+1)>length(fitting)
        ERR=dist^2;
    else
        ERR=fitting(ind+1)*dist^2;
    end
elseif fitting(1)==3
    ERR=dist^2;
else
    ERR=0;
    warning('Unknown value of fitting!');
end

function weights=weightfcn(distances)

maxdistances=max(distances);
mindistances=min(distances);

if maxdistances>1.1*mindistances
    weights=1+mindistances/(maxdistances-mindistances)-distances/(maxdistances-mindistances);
else
    weights=maxdistances+mindistances-distances;
end

weights=weights/sum(weights);

Contact us at files@mathworks.com