GteIntpThinPlateSpline2.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) to
16 // the unit square 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) but not to scaling.
21 
22 namespace gte
23 {
24 
25 template <typename Real>
27 {
28 public:
29  // Construction. Data points are (x,y,f(x,y)). The smoothing parameter
30  // must be nonnegative.
31  IntpThinPlateSpline2(int numPoints, Real const* X, Real const* Y,
32  Real const* F, Real smooth, bool transformToUnitSquare);
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) 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) 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^2 * log(t^2)
50  static Real Kernel(Real t);
51 
52  // Input data.
54  std::vector<Real> mX;
55  std::vector<Real> mY;
56  Real mSmooth;
57 
58  // Thin plate spline coefficients. The A[] coefficients are associated
59  // with the Green's functions G(x,y,*) and the B[] coefficients are
60  // associated with the affine term B[0] + B[1]*x + B[2]*y.
61  std::vector<Real> mA; // mNumPoints elements
62  Real mB[3];
63 
64  // Extent of input data.
67 
69 };
70 
71 
72 template <typename Real>
74  Real const* Y, Real const* F, Real smooth, bool transformToUnitSquare)
75  :
76  mNumPoints(numPoints),
77  mX(numPoints),
78  mY(numPoints),
79  mSmooth(smooth),
80  mA(numPoints),
81  mInitialized(false)
82 {
83  if (numPoints < 3 || !X || !Y || !F || smooth < (Real)0)
84  {
85  LogError("Invalid input.");
86  return;
87  }
88 
89  int i, row, col;
90 
91  if (transformToUnitSquare)
92  {
93  // Map input (x,y) to unit square. This is not part of the classical
94  // thin-plate spline algorithm because the interpolation is not
95  // invariant to scalings.
96  auto extreme = std::minmax_element(X, X + mNumPoints);
97  mXMin = *extreme.first;
98  mXMax = *extreme.second;
99  mXInvRange = ((Real)1) / (mXMax - mXMin);
100  for (i = 0; i < mNumPoints; ++i)
101  {
102  mX[i] = (X[i] - mXMin) * mXInvRange;
103  }
104 
105  extreme = std::minmax_element(Y, Y + mNumPoints);
106  mYMin = *extreme.first;
107  mYMax = *extreme.second;
108  mYInvRange = ((Real)1) / (mYMax - mYMin);
109  for (i = 0; i < mNumPoints; ++i)
110  {
111  mY[i] = (Y[i] - mYMin) * mYInvRange;
112  }
113  }
114  else
115  {
116  // The classical thin-plate spline uses the data as is. The values
117  // mXMax and mYMax are not used, but they are initialized anyway
118  // (to irrelevant numbers).
119  mXMin = (Real)0;
120  mXMax = (Real)1;
121  mXInvRange = (Real)1;
122  mYMin = (Real)0;
123  mYMax = (Real)1;
124  mYInvRange = (Real)1;
125  std::copy(X, X + mNumPoints, mX.begin());
126  std::copy(Y, Y + mNumPoints, mY.begin());
127  }
128 
129  // Compute matrix A = M + lambda*I [NxN matrix].
131  for (row = 0; row < mNumPoints; ++row)
132  {
133  for (col = 0; col < mNumPoints; ++col)
134  {
135  if (row == col)
136  {
137  AMat(row, col) = mSmooth;
138  }
139  else
140  {
141  Real dx = mX[row] - mX[col];
142  Real dy = mY[row] - mY[col];
143  Real t = sqrt(dx*dx + dy*dy);
144  AMat(row, col) = Kernel(t);
145  }
146  }
147  }
148 
149  // Compute matrix B [Nx3 matrix].
150  GMatrix<Real> BMat(mNumPoints, 3);
151  for (row = 0; row < mNumPoints; ++row)
152  {
153  BMat(row, 0) = (Real)1;
154  BMat(row, 1) = mX[row];
155  BMat(row, 2) = mY[row];
156  }
157 
158  // Compute A^{-1}.
159  bool invertible;
160  GMatrix<Real> invAMat = Inverse(AMat, &invertible);
161  if (!invertible)
162  {
163  return;
164  }
165 
166  // Compute P = B^T A^{-1} [3xN matrix].
167  GMatrix<Real> PMat = MultiplyATB(BMat, invAMat);
168 
169  // Compute Q = P B = B^T A^{-1} B [3x3 matrix].
170  GMatrix<Real> QMat = PMat * BMat;
171 
172  // Compute Q^{-1}.
173  GMatrix<Real> invQMat = Inverse(QMat, &invertible);
174  if (!invertible)
175  {
176  return;
177  }
178 
179  // Compute P*z.
180  Real prod[3];
181  for (row = 0; row < 3; ++row)
182  {
183  prod[row] = (Real)0;
184  for (i = 0; i < mNumPoints; ++i)
185  {
186  prod[row] += PMat(row, i) * F[i];
187  }
188  }
189 
190  // Compute 'b' vector for smooth thin plate spline.
191  for (row = 0; row < 3; ++row)
192  {
193  mB[row] = (Real)0;
194  for (i = 0; i < 3; ++i)
195  {
196  mB[row] += invQMat(row, i) * prod[i];
197  }
198  }
199 
200  // Compute z-B*b.
201  std::vector<Real> tmp(mNumPoints);
202  for (row = 0; row < mNumPoints; ++row)
203  {
204  tmp[row] = F[row];
205  for (i = 0; i < 3; ++i)
206  {
207  tmp[row] -= BMat(row, i) * mB[i];
208  }
209  }
210 
211  // Compute 'a' vector for smooth thin plate spline.
212  for (row = 0; row < mNumPoints; ++row)
213  {
214  mA[row] = (Real)0;
215  for (i = 0; i < mNumPoints; ++i)
216  {
217  mA[row] += invAMat(row, i) * tmp[i];
218  }
219  }
220 
221  mInitialized = true;
222 }
223 
224 template <typename Real> inline
226 {
227  return mInitialized;
228 }
229 
230 template <typename Real>
232 {
233  if (mInitialized)
234  {
235  // Map (x,y) to the unit square.
236  x = (x - mXMin) * mXInvRange;
237  y = (y - mYMin) * mYInvRange;
238 
239  Real result = mB[0] + mB[1] * x + mB[2] * y;
240  for (int i = 0; i < mNumPoints; ++i)
241  {
242  Real dx = x - mX[i];
243  Real dy = y - mY[i];
244  Real t = sqrt(dx*dx + dy*dy);
245  result += mA[i] * Kernel(t);
246  }
247  return result;
248  }
249 
250  return std::numeric_limits<Real>::max();
251 }
252 
253 template <typename Real>
255 {
256  Real functional = (Real)0;
257  for (int row = 0; row < mNumPoints; ++row)
258  {
259  for (int col = 0; col < mNumPoints; ++col)
260  {
261  if (row == col)
262  {
263  functional += mSmooth * mA[row] * mA[col];
264  }
265  else
266  {
267  Real dx = mX[row] - mX[col];
268  Real dy = mY[row] - mY[col];
269  Real t = sqrt(dx * dx + dy * dy);
270  functional += Kernel(t) * mA[row] * mA[col];
271  }
272  }
273  }
274 
275  if (mSmooth > (Real)0)
276  {
277  functional *= mSmooth;
278  }
279 
280  return functional;
281 }
282 
283 template <typename Real>
285 {
286  if (t > (Real)0)
287  {
288  Real t2 = t * t;
289  return t2 * log(t2);
290  }
291  return (Real)0;
292 }
293 
294 
295 }
Real operator()(Real x, Real y) const
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
IntpThinPlateSpline2(int numPoints, Real const *X, Real const *Y, Real const *F, Real smooth, bool transformToUnitSquare)
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