GteIntpThinPlateSpline3.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
10 #include <Mathematics/GteGMatrix.h>
11 #include <algorithm>
12 #include <cmath>
13 #include <limits>
14 
15 // WARNING. The implementation allows you to transform the inputs (x,y,z) to
16 // the unit cube and perform the interpolation in that space. The idea is
17 // to keep the floating-point numbers to order 1 for numerical stability of
18 // the algorithm. The classical thin-plate spline algorithm does not include
19 // this transformation. The interpolation is invariant to translations and
20 // rotations of (x,y,z) but not to scaling.
21 
22 namespace gte
23 {
24 
25 template <typename Real>
27 {
28 public:
29  // Construction. Data points are (x,y,z,f(x,y,z)). The smoothing parameter
30  // must be nonnegative
31  IntpThinPlateSpline3(int numPoints, Real const* X, Real const* Y,
32  Real const* Z, Real const* F, Real smooth, bool transformToUnitCube);
33 
34  // Check this after the constructor call to see whether the thin plate
35  // spline coefficients were successfully computed. If so, then calls to
36  // operator()(Real,Real,Real) will work properly.
37  inline bool IsInitialized() const;
38 
39  // Evaluate the interpolator. If IsInitialized()returns 'false', the
40  // operator will return std::numeric_limits<Real>::max().
41  Real operator()(Real x, Real y, Real z) const;
42 
43  // Compute the functional value a^T*M*a when lambda is zero or
44  // lambda*w^T*(M+lambda*I)*w when lambda is positive. See the thin plate
45  // splines PDF for a description of these quantities.
46  Real ComputeFunctional() const;
47 
48 private:
49  // Kernel(t) = -|t|
50  static Real Kernel(Real t);
51 
52  // Input data.
54  std::vector<Real> mX;
55  std::vector<Real> mY;
56  std::vector<Real> mZ;
57  Real mSmooth;
58 
59  // Thin plate spline coefficients. The A[] coefficients are associated
60  // with the Green's functions G(x,y,z,*) and the B[] coefficients are
61  // associated with the affine term B[0] + B[1]*x + B[2]*y + B[3]*z.
62  std::vector<Real> mA; // mNumPoints elements
63  Real mB[4];
64 
65  // Extent of input data.
69 
71 };
72 
73 
74 template <typename Real>
76  Real const* Y, Real const* Z, Real const* F, Real smooth,
77  bool transformToUnitCube)
78  :
79  mNumPoints(numPoints),
80  mX(numPoints),
81  mY(numPoints),
82  mZ(numPoints),
83  mSmooth(smooth),
84  mA(numPoints),
85  mInitialized(false)
86 {
87  if (numPoints < 4 || !X || !Y || !Z || !F || smooth < (Real)0)
88  {
89  LogError("Invalid input.");
90  return;
91  }
92 
93  int i, row, col;
94 
95  if (transformToUnitCube)
96  {
97  // Map input (x,y,z) to unit cube. This is not part of the classical
98  // thin-plate spline algorithm, because the interpolation is not
99  // invariant to scalings.
100  auto extreme = std::minmax_element(X, X + mNumPoints);
101  mXMin = *extreme.first;
102  mXMax = *extreme.second;
103  mXInvRange = ((Real)1) / (mXMax - mXMin);
104  for (i = 0; i < mNumPoints; ++i)
105  {
106  mX[i] = (X[i] - mXMin) * mXInvRange;
107  }
108 
109  extreme = std::minmax_element(Y, Y + mNumPoints);
110  mYMin = *extreme.first;
111  mYMax = *extreme.second;
112  mYInvRange = ((Real)1) / (mYMax - mYMin);
113  for (i = 0; i < mNumPoints; ++i)
114  {
115  mY[i] = (Y[i] - mYMin) * mYInvRange;
116  }
117 
118  extreme = std::minmax_element(Z, Z + mNumPoints);
119  mZMin = *extreme.first;
120  mZMax = *extreme.second;
121  mZInvRange = ((Real)1) / (mZMax - mZMin);
122  for (i = 0; i < mNumPoints; ++i)
123  {
124  mZ[i] = (Z[i] - mZMin) * mZInvRange;
125  }
126  }
127  else
128  {
129  // The classical thin-plate spline uses the data as is. The values
130  // mXMax, mYMax, and mZMax are not used, but they are initialized
131  // anyway (to irrelevant numbers).
132  mXMin = (Real)0;
133  mXMax = (Real)1;
134  mXInvRange = (Real)1;
135  mYMin = (Real)0;
136  mYMax = (Real)1;
137  mYInvRange = (Real)1;
138  mZMin = (Real)0;
139  mZMax = (Real)1;
140  mZInvRange = (Real)1;
141  std::copy(X, X + mNumPoints, mX.begin());
142  std::copy(Y, Y + mNumPoints, mY.begin());
143  std::copy(Z, Z + mNumPoints, mZ.begin());
144  }
145 
146  // Compute matrix A = M + lambda*I [NxN matrix].
148  for (row = 0; row < mNumPoints; ++row)
149  {
150  for (col = 0; col < mNumPoints; ++col)
151  {
152  if (row == col)
153  {
154  AMat(row, col) = mSmooth;
155  }
156  else
157  {
158  Real dx = mX[row] - mX[col];
159  Real dy = mY[row] - mY[col];
160  Real dz = mZ[row] - mZ[col];
161  Real t = sqrt(dx * dx + dy * dy + dz * dz);
162  AMat(row, col) = Kernel(t);
163  }
164  }
165  }
166 
167  // Compute matrix B [Nx4 matrix].
168  GMatrix<Real> BMat(mNumPoints, 4);
169  for (row = 0; row < mNumPoints; ++row)
170  {
171  BMat(row, 0) = (Real)1;
172  BMat(row, 1) = mX[row];
173  BMat(row, 2) = mY[row];
174  BMat(row, 3) = mZ[row];
175  }
176 
177  // Compute A^{-1}.
178  bool invertible;
179  GMatrix<Real> invAMat = Inverse(AMat, &invertible);
180  if (!invertible)
181  {
182  return;
183  }
184 
185  // Compute P = B^t A^{-1} [4xN matrix].
186  GMatrix<Real> PMat = MultiplyATB(BMat, invAMat);
187 
188  // Compute Q = P B = B^t A^{-1} B [4x4 matrix].
189  GMatrix<Real> QMat = PMat * BMat;
190 
191  // Compute Q^{-1}.
192  GMatrix<Real> invQMat = Inverse(QMat, &invertible);
193  if (!invertible)
194  {
195  return;
196  }
197 
198  // Compute P*w.
199  Real prod[4];
200  for (row = 0; row < 4; ++row)
201  {
202  prod[row] = (Real)0;
203  for (i = 0; i < mNumPoints; ++i)
204  {
205  prod[row] += PMat(row, i) * F[i];
206  }
207  }
208 
209  // Compute 'b' vector for smooth thin plate spline.
210  for (row = 0; row < 4; ++row)
211  {
212  mB[row] = (Real)0;
213  for (i = 0; i < 4; ++i)
214  {
215  mB[row] += invQMat(row, i) * prod[i];
216  }
217  }
218 
219  // Compute w-B*b.
220  std::vector<Real> tmp(mNumPoints);
221  for (row = 0; row < mNumPoints; ++row)
222  {
223  tmp[row] = F[row];
224  for (i = 0; i < 4; ++i)
225  {
226  tmp[row] -= BMat(row, i) * mB[i];
227  }
228  }
229 
230  // Compute 'a' vector for smooth thin plate spline.
231  for (row = 0; row < mNumPoints; ++row)
232  {
233  mA[row] = (Real)0;
234  for (i = 0; i < mNumPoints; ++i)
235  {
236  mA[row] += invAMat(row, i) * tmp[i];
237  }
238  }
239 
240  mInitialized = true;
241 }
242 
243 template <typename Real>
245 {
246  return mInitialized;
247 }
248 
249 template <typename Real>
250 Real IntpThinPlateSpline3<Real>::operator()(Real x, Real y, Real z) const
251 {
252  if (mInitialized)
253  {
254  // Map (x,y,z) to the unit cube.
255  x = (x - mXMin) * mXInvRange;
256  y = (y - mYMin) * mYInvRange;
257  z = (z - mZMin) * mZInvRange;
258 
259  Real result = mB[0] + mB[1] * x + mB[2] * y + mB[3] * z;
260  for (int i = 0; i < mNumPoints; ++i)
261  {
262  Real dx = x - mX[i];
263  Real dy = y - mY[i];
264  Real dz = z - mZ[i];
265  Real t = sqrt(dx*dx + dy*dy + dz*dz);
266  result += mA[i] * Kernel(t);
267  }
268  return result;
269  }
270 
271  return std::numeric_limits<Real>::max();
272 }
273 
274 template <typename Real>
276 {
277  Real functional = (Real)0;
278  for (int row = 0; row < mNumPoints; ++row)
279  {
280  for (int col = 0; col < mNumPoints; ++col)
281  {
282  if (row == col)
283  {
284  functional += mSmooth * mA[row] * mA[col];
285  }
286  else
287  {
288  Real dx = mX[row] - mX[col];
289  Real dy = mY[row] - mY[col];
290  Real dz = mZ[row] - mZ[col];
291  Real t = sqrt(dx * dx + dy * dy + dz * dz);
292  functional += Kernel(t) * mA[row] * mA[col];
293  }
294  }
295  }
296 
297  if (mSmooth > (Real)0)
298  {
299  functional *= mSmooth;
300  }
301 
302  return functional;
303 }
304 
305 template <typename Real>
307 {
308  return -std::abs(t);
309 }
310 
311 
312 }
Real operator()(Real x, Real y, Real z) const
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
GLint GLenum GLint x
Definition: glcorearb.h:404
GMatrix< Real > MultiplyATB(GMatrix< Real > const &A, GMatrix< Real > const &B)
Definition: GteGMatrix.h:737
GLenum GLenum GLsizei void * row
Definition: glext.h:2725
#define LogError(message)
Definition: GteLogger.h:92
GLdouble GLdouble t
Definition: glext.h:239
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:843
IntpThinPlateSpline3(int numPoints, Real const *X, Real const *Y, Real const *Z, Real const *F, Real smooth, bool transformToUnitCube)
Quaternion< Real > Inverse(Quaternion< Real > const &d)
GLuint64EXT * result
Definition: glext.h:10003
GLint y
Definition: glcorearb.h:98


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:00