Subversion Repositories seema-scanner

Rev

Rev 218 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
213 jakw 1
function [alignment] = groupwiseOrthogonalProcrustes(P, initialAlign)
2
%groupwiseOrthogonalProcrustes Computes rototranslations to bring N
3
% matched point sets into alignment using non-linear optimization.
4
%
5
% Input:
6
%   P: (Np x Nc) cell array containing point coordinates in matched order.
7
%       empty cells indicate that the corresponding point set does not
8
%       include a point matched to that cluster.
9
%   initialAlignment: a N length struct with fields Rotation (3x3 matrix)  
10
%       and Translation (3-vector) for each of the point sets.
11
%
12
% Output:
13
%   alignment: a struct with fields Rotation (3x3 matrix) and Translation
14
%       (3-vector) for each of the point sets.
15
%
16
 
17
Np = size(P, 1);
18
assert(length(initialAlign) == Np);
19
 
20
xInit = zeros(6*Np, 1);
21
 
22
for i=1:Np
23
    [wi, thetai] = rmat2axis(initialAlign(i).Rotation);
24
    xInit((i-1)*6+1:(i-1)*6+3) = wi*thetai;
25
 
26
    xInit((i-1)*6+4:(i-1)*6+6) = initialAlign(i).Translation;
27
end
28
 
29
options = optimset('Algorithm', 'levenberg-marquardt', 'Display', 'iter-detailed', 'OutputFcn', @outfun, 'MaxIter', [], 'TolFun', 0, 'TolX', 0);
30
[x, ~, ~] = lsqnonlin(@orthProcFun, xInit, [], [], options);
31
 
32
alignment = struct('Rotation', {}, 'Translation', {});
33
for i=1:Np
34
    wi = x((i-1)*6+1:(i-1)*6+3);
35
    Ri = axis2rmat(wi, norm(wi));
36
    Ti = x((i-1)*6+4:(i-1)*6+6);
37
    alignment(i).Rotation = Ri;
38
    alignment(i).Translation = Ti;
39
end
40
 
41
 
42
    % objective function
43
    function e = orthProcFun(x)
44
 
45
        Np = size(P, 1);
46
        Nc = size(P, 2);
47
 
48
        % transform all points according to current x
49
        Pbar = cell(size(P));
50
        for i=1:Np
51
            wi = x((i-1)*6+1:(i-1)*6+3);
52
            Ri = axis2rmat(wi, norm(wi));
53
            Ti = x((i-1)*6+4:(i-1)*6+6);
54
            for j=1:Nc
55
                if(not(isempty(P{i,j})))
56
                    Pbar{i,j} = P{i,j}*Ri' + Ti';
57
                end
58
            end
59
        end
60
 
61
        % include all pairwise distances, normalizing for each point sets
62
        e = [];
63
        for i=1:Np   
64
            % number of points in current point set
65
            Nci = size(cat(2, Pbar{i,:}), 2);
66
            for j=1:Nc
67
                if(not(isempty(Pbar{i,j})))
68
                    for k=setxor(1:Np, i)
69
                        if(not(isempty(Pbar{k,j})))
70
                            e = [e; 1/Nci * norm(Pbar{k,j} - Pbar{i,j})];
71
                            %e = [e; norm(Pbar{k,j} - Pbar{i,j})];
72
                        end      
73
                    end   
74
                end
75
            end
76
        end
77
 
78
    end
79
 
80
    % output function called at every iteration
81
    function stop = outfun(x, optimValues, ~)
82
        stop = false;
83
    end
84
 
85
end
86
 
87
function [w, theta] = rmat2axis(R)
88
 
89
w = zeros(3, size(R,3));
90
theta = zeros(1, size(R,3));
91
 
92
[V,D] = eig(R);
93
[~,ix] = min(abs(diag(D)-1)); 
94
 
95
w(:) = V(:,ix); 
96
t = [R(3,2)-R(2,3),R(1,3)-R(3,1),R(2,1)-R(1,2)];
97
 
98
theta = atan2(t*w(:),trace(R(:,:))-1);
99
 
100
if theta<0
101
    theta = -theta(1); 
102
    w(:) = -w(:); 
103
end
104
end
105
 
106
function R = axis2rmat(w, theta)
107
 
108
if(theta > 0.0001)
109
    w = w./norm(w); % w should be a unit vector
110
end
111
 
112
P = w*transpose(w);
113
Q = [0 -w(3) w(2);
114
     w(3) 0 -w(1);
115
     -w(2) w(1) 0];
116
 
117
% using Rodigues' rotation formula
118
R = P + (eye(3) - P)*cos(theta) + Q*sin(theta);
119
end
120
 
121