-
Notifications
You must be signed in to change notification settings - Fork 75
/
Copy pathregpt2surf.m
106 lines (95 loc) · 3.86 KB
/
regpt2surf.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
function [A, b, newpos] = regpt2surf(node, elem, p, pmask, A0, b0, cmask, maxiter)
% [A,b,newpos]=regpt2surf(node,elem,p,pmask,A0,b0,cmask,maxiter)
% Perform point cloud registration to a triangular surface
% (surface can be either triangular or cubic), Gauss-Newton method
% is used for the calculation
%
% author: Qianqian Fang <q.fang at neu.edu>
% date: 12/12/2008
%
% parameters:
% node: node coordinate of the surface mesh (nn x 3)
% elem: element list of the surface mesh (3 columns for
% triangular mesh, 4 columns for cubic surface mesh)
% p: points to be registered, 3 columns for x,y and z respectively
% pmask: a mask vector with the same length as p, determines the
% method to handle the point, if pmask(i)=-1, the point is a free
% node and can be move by the optimization, if pmask(i)=0, the
% point is fixed; if pmask(i)=n>0, the distance between p(i,:)
% and node(n,:) will be part of the object function and be optimized
% A0: a 3x3 matrix, as the initial guess for the affine A matrix (rotation&scaling)
% b0: a 3x1 vector, as the initial guess for the affine b vector (translation)
% cmask: a binary 12x1 vector, determines which element of [A(:);b] will be optimized
% if cmask(i)=0, the corresponding coefficient will not be updated
% maxiter: a integer, specifying the optimization iterations
%
% outputs:
% A: 3x3 matrix, the updated affine A matrix
% b: 3x1 vector, the updated affine b vector
% newpos: the registered positions for p, newpos=A*p'+b
%
% Please find more information at http://iso2mesh.sf.net/cgi-bin/index.cgi?metch
%
% this function is part of "metch" toobox, see COPYING for license
A = A0;
b = b0(:);
% for simplicity, I wrap A and b into one single vector C
C = [A(:); b];
delta = 1e-4;
newpos = (reshape(C(1:9), 3, 3) * p' + repmat(C(end - 2:end), 1, size(p, 1)))';
nv = nodesurfnorm(node, elem);
clen = length(C);
cuplist = find(cmask == 1);
pfree = find(pmask < 0);
pfix = find(pmask > 0);
% start Gauss-Newton iterations
for iter = 1:maxiter
% calculate the current residual: the sum of distances to the surface
dist0 = zeros(length(pfree) + length(pfix), 1);
if (~isempty(pfree))
[dist0(pfree), cn0] = dist2surf(node, nv, newpos(pfree, :));
end
if (~isempty(pfix))
fixdist = node(pmask(pfix), :) - newpos(pfix, :);
dist0(pfix) = sqrt(sum(fixdist .* fixdist, 2));
end
fprintf('iter=%d error=%f\n', iter, sum(abs(dist0)));
% build the Jacobian (sensitivity) matrix
J = zeros(length(dist0), length(C));
for i = 1:clen
if (cmask(i) == 0)
continue
end
dC = C;
if (C(i))
dC(i) = C(i) * (1 + delta);
else
dC(i) = C(i) + delta;
end
newp = (reshape(dC(1:9), 3, 3) * p' + repmat(dC(end - 2:end), 1, size(p, 1)))';
dist = zeros(length(pfree) + length(pfix), 1);
if (~isempty(pfree))
if (length(cn0) == length(pfree))
dist(pfree) = dist2surf(node, nv, newp(pfree, :), cn0);
else
dist(pfree) = dist2surf(node, nv, newp(pfree, :));
end
end
if (~isempty(pfix))
fixdist = node(pmask(pfix), :) - newp(pfix, :);
dist(pfix) = sqrt(sum(fixdist .* fixdist, 2));
end
% J=dL/dC
J(:, i) = (dist - dist0) / (dC(i) - C(i));
end
% weight the matrix (normalization)
wj = sqrt(sum(J .* J));
J(:, cuplist) = J(:, cuplist) ./ repmat(wj(cuplist), length(dist0), 1);
% calculate the update: J*dC=dL
dC = (J(:, cuplist) \ dist0) ./ wj(cuplist)';
C(cuplist) = C(cuplist) - 0.5 * dC;
% get the updated positions with the calculated A and b
newpos = (reshape(C(1:9), 3, 3) * p' + repmat(C(end - 2:end), 1, size(p, 1)))';
end
A = reshape(C(1:9), 3, 3);
b = C(end - 2:end);