Shapeworks Studio  2.1
Shape analysis software suite
itkPSMRBFCorrespondenceInterpolator.hxx
1 /*=========================================================================
2  *
3  * Copyright Insight Software Consortium
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef __itkPSMRBFCorrespondenceInterpolator_hxx
19 #define __itkPSMRBFCorrespondenceInterpolator_hxx
20 #include "itkPSMRBFCorrespondenceInterpolator.h"
21 
22 namespace itk
23 {
24 
25 template <unsigned int VDimension>
26 PSMRBFCorrespondenceInterpolator<VDimension>
27 ::PSMRBFCorrespondenceInterpolator()
28 {
29 
30  //
31  // TODO: NOTE ! This function is currently only implemented for 3D
32  //
33  if (VDimension != 3)
34  {
35  itkExceptionMacro("This function is currently only implemented for 3D point sets.");
36  }
37 
38 }
39 
40 template <unsigned int VDimension>
41 void
44 {
45  // Make sure we have points on the input
46  if (m_PointSetA.size() == 0 || m_PointSetB.size() == 0)
47  {
48  itkExceptionMacro("Surface point sets have not been specified.");
49  }
50 
51  // Make sure the point set sizes match
52  if (m_PointSetA.size() != m_PointSetB.size())
53  {
54  itkExceptionMacro("Surface point sets A and B are not the same size.");
55  }
56 
57  // N is the number of points
58  const unsigned int N = m_PointSetA.size();
59 
60  // TODO: Need algorithm references
61  // TODO: Need to implement for at least 2D
62 
63  typedef vnl_vector<double> vectype;
64  typedef vnl_matrix<double> matrixtype;
65 
66  // Transforms are from 1 to 2
67  vectype b(N+4); // point data from file 2
68  vectype x(N+4); // parameters to be solved for
69  matrixtype A(N+4,N+4);
70  matrixtype Phi(N,N);
71 
72  // Compute Phi values
73  vectype Xi(3);
74  vectype Xj(3);
75  for (unsigned int i = 0; i < N; i++)
76  {
77  Xi[0] = (m_PointSetA[i])[0];
78  Xi[1] = (m_PointSetA[i])[1];
79  Xi[2] = (m_PointSetA[i])[2];
80 
81  for (unsigned int j = 0; j < N; j++)
82  {
83  Xj[0] = (m_PointSetA[j])[0];
84  Xj[1] = (m_PointSetA[j])[1];
85  Xj[2] = (m_PointSetA[j])[2];
86 
87  // Biharmonic Radial Basis Function
88  Phi(i,j) = (Xi - Xj).magnitude();
89 
90  // Thin plate spline basis -- probably need some logic to switch on dimensionality
91  // Phi(i,j) = dot_product(Xi - Xj,Xi - Xj) * log((Xi - Xj).magnitude() + 1.0e-6);
92  }
93  }
94 
95  // Construct the coefficient matrix A from PointSetA and Phi's
96  for (unsigned int i = 0; i < 4; i++)
97  {
98  for (unsigned int j = 0; j < N +4; j++)
99  {
100  if (j >= N) A(i,j) = 0.0;
101  else if (i == 3) A(i,j) = 1.0;
102  else A(i,j) = (m_PointSetA[j])[i];
103  }
104  }
105 
106  // Rest of the matrix A
107  for (unsigned int i = 0; i < N; i++)
108  {
109  for (unsigned int j = 0; j < N +4; j++)
110  {
111  if (j < N) A(i+4,j) = Phi(i,j);
112  else if (j == N+3) A(i+4,j) = 1.0;
113  else A(i+4,j) = (m_PointSetA[i])[2-(j-N)];
114  }
115  }
116 
117  // To keep things simple, solve in each dimension separately
118  // matrixtype P(4,3);
119  // matrixtype C(N,3);
120  m_P.set_size(4,3);
121  m_C.set_size(N,3);
122 
123  for (unsigned int D = 0; D < 3; D++)
124  {
125  // Construct the position data vector b from file 2
126  // [0 0 0 0 x1' x2' x3' ... xN' ]^T
127  b[0] = b[1] = b[2] = b[3] = 0.0;
128  for(unsigned int i = 0; i < N; i++)
129  {
130  b[i+4] = (m_PointSetB[i])[D];
131  }
132 
133 
134  // Solve for parameters
135  // x = vnl_matrix_inverse<double>(A) * b;
136  x = vnl_svd<double>(A).solve(b);
137 
138  // Store results
139  for (unsigned int i = 0; i < N; i++)
140  {
141  m_C(i,D) = x[i];
142  }
143 
144  m_P(0,D) = x[N+3];
145  m_P(1,D) = x[N+2];
146  m_P(2,D) = x[N+1];
147  m_P(3,D) = x[N];
148 
149  } // end D
150 
151  m_Initialized = true;
152 }
153 
154 template <unsigned int VDimension>
157 ::Evaluate(const PointType &pt) const
158 {
159  if (m_Initialized == false)
160  {
161  itkExceptionMacro("Function has not been initialized");
162  }
163 
164  // N is the number of points
165  const unsigned int N = m_PointSetA.size();
166 
167  // X is the input point
168  vnl_vector<double> X(VDimension);
169  for (unsigned int D = 0; D < VDimension; D++)
170  { X(D) = pt[D]; }
171 
172  // Convert PointSetA from points to vnl_vectors-- perhaps store this in the class?
173  std::vector<vnl_vector<double> > points(N);
174  for (unsigned int i = 0; i < N; i++)
175  {
176  points[i].set_size(VDimension);
177  for (unsigned int D = 0; D < VDimension; D++)
178  {
179  points[i](D) = m_PointSetA[i][D];
180  }
181 
182  }
183 
184  // Return value in which to accumulate
185  PointType ret;
186 
187  // For each dimension ...
188  for (unsigned int D = 0; D < VDimension; D++)
189  {
190  ret[D] = 0.0f; // initialize to zero
191 
192  // Compute RBF term in D
193  for (unsigned int i = 0; i < N; i++)
194  {
195  ret[D] += m_C(i,D) * (X - points[i]).magnitude();
196  }
197 
198  // Add the polynomial term
199  for (unsigned int i = 0; i < VDimension; i++)
200  {
201  // std::cout << "ret[D] += m_P(i+1,D) + X(i) ->" << ret[D] << " += " << m_P(i+1,D) << " + " << X(i) << std::endl;
202  ret[D] += m_P(i+1,D) * X(i);
203  }
204  ret[D] += m_P(0,D);
205 
206  }
207 
208  return ret;
209 }
210 
211 } // end namespace itk
212 #endif
Definition: Shape.h:14
virtual PointType Evaluate(const PointType &pt) const