Shapeworks Studio  2.1
Shape analysis software suite
itkSparseKernelTransform.hxx
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkSparseKernelTransform.txx,v $
5  Language: C++
6  Date: $Date: 2006-11-28 14:22:18 $
7  Version: $Revision: 1.1 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 #ifndef _itkSparseKernelTransform_txx
18 #define _itkSparseKernelTransform_txx
19 #include "itkSparseKernelTransform.h"
20 
21 // Report timings
22 #include <itkTimeProbe.h>
23 #include <itkTimeProbesCollectorBase.h>
24 
25 #include "Eigen/Sparse"
26 #include "Eigen/SparseLU"
27 
28 #include <vector>
29 
30 namespace itk
31 {
32 
33 
37 template <class TScalarType, unsigned int NDimensions>
38 SparseKernelTransform<TScalarType, NDimensions>::
39 SparseKernelTransform():Superclass(1)
40  // the second NDimensions is associated is provided as
41  // a tentative number for initializing the Jacobian.
42  // The matrix can be resized at run time so this number
43  // here is irrelevant. The correct size of the Jacobian
44  // will be NDimension X NDimension.NumberOfLandMarks.
45 {
46 
47  // m_I.set_identity();
48  m_I = IMatrixType::Identity();
49  m_SourceLandmarks = PointSetType::New();
50  m_TargetLandmarks = PointSetType::New();
51  m_Displacements = VectorSetType::New();
52  m_WMatrixComputed = false;
53 
54  m_LMatrixComputed = false;
55  m_LInverseComputed = false;
56 
57  m_Stiffness = 0.0;
58 
59  Eigen::setNbThreads(8);
60 }
61 
65 template <class TScalarType, unsigned int NDimensions>
66 SparseKernelTransform<TScalarType, NDimensions>::
67 ~SparseKernelTransform()
68 {
69 }
70 
71 template<class TScalarType, unsigned int NDimensions>
72 inline void SparseKernelTransform<TScalarType,
73  NDimensions>::ComputeJacobianWithRespectToParameters(
74  const InputPointType & in, JacobianType & jacobian) const {}
75 
76 template <class TScalarType, unsigned int NDimensions>
77 void
79 SetSourceLandmarks(PointSetType * landmarks)
80 {
81  itkDebugMacro("setting SourceLandmarks to " << landmarks );
82  if (this->m_SourceLandmarks != landmarks)
83  {
84  this->m_SourceLandmarks = landmarks;
85  this->UpdateParameters();
86  this->Modified();
87 
88  // these are invalidated when the source lms change
89  m_WMatrixComputed = false;
90  m_LMatrixComputed = false;
91  m_LInverseComputed = false;
92 
93  // you must recompute L and Linv - this does not require the targ lms
94  // Linverse is only needed ofr Jacobian computation, I will defer this in case Jacobian is needed
95  // we will assume by default that this transform is used only for warping, if it is a part of optimization
96  // the GetJacobian will feel that the inverse is not computed and will compute it
97  //this->ComputeLInverse();
98  this->ComputeL();
99 
100  }
101 }
102 
103 
107 template <class TScalarType, unsigned int NDimensions>
108 void
110 SetTargetLandmarks(PointSetType * landmarks)
111 {
112  itkDebugMacro("setting TargetLandmarks to " << landmarks );
113  if (this->m_TargetLandmarks != landmarks)
114  {
115  this->m_TargetLandmarks = landmarks;
116  // this is invalidated when the target lms change
117  m_WMatrixComputed=false;
118  this->ComputeWMatrix();
119  this->UpdateParameters();
120  this->Modified();
121  }
122 
123 }
124 
125 
126 
130 template <class TScalarType, unsigned int NDimensions>
133 ComputeG( const InputVectorType & ) const
134 {
135  //
136  // Should an Exception be thrown here ?
137  //
138  itkWarningMacro(<< "ComputeG() should be reimplemented in the subclass !!");
139  return m_GMatrix;
140 }
141 
145 template <class TScalarType, unsigned int NDimensions>
148 ComputeReflexiveG( PointsIterator ) const
149 {
150  m_GMatrix = GMatrixType::Zero();
151  for(unsigned d = 0; d < NDimensions; d++)
152  m_GMatrix(d,d) = m_Stiffness;
153 
154  //m_GMatrix.fill( NumericTraits< TScalarType >::Zero );
155  //m_GMatrix.fill_diagonal( m_Stiffness );
156 
157  return m_GMatrix;
158 }
159 
160 
161 
162 
167 template <class TScalarType, unsigned int NDimensions>
168 void
171  OutputPointType & result ) const
172 {
173 
174  unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
175 
176  PointsIterator sp = m_SourceLandmarks->GetPoints()->Begin();
177 
178  for(unsigned int lnd=0; lnd < numberOfLandmarks; lnd++ )
179  {
180  const GMatrixType & Gmatrix = ComputeG( thisPoint - sp->Value() );
181  for(unsigned int dim=0; dim < NDimensions; dim++ )
182  {
183  for(unsigned int odim=0; odim < NDimensions; odim++ )
184  {
185  result[ odim ] += Gmatrix(dim, odim ) * m_DMatrix(dim,lnd);
186  }
187  }
188  ++sp;
189  }
190 
191 }
192 
193 
197 template <class TScalarType, unsigned int NDimensions>
199 ::ComputeD(void) const
200 {
201  unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
202 
203  PointsIterator sp = m_SourceLandmarks->GetPoints()->Begin();
204  PointsIterator tp = m_TargetLandmarks->GetPoints()->Begin();
205  PointsIterator end = m_SourceLandmarks->GetPoints()->End();
206 
207  m_Displacements->Reserve( numberOfLandmarks );
208  typename VectorSetType::Iterator vt = m_Displacements->Begin();
209 
210  while( sp != end )
211  {
212  vt->Value() = tp->Value() - sp->Value();
213  vt++;
214  sp++;
215  tp++;
216  }
217  // std::cout<<" Computed displacements "<<m_Displacements<<std::endl;
218 }
219 
223 template <class TScalarType, unsigned int NDimensions>
225 ::ComputeWMatrix(void) const
226 {
227  itk::TimeProbe clock;
228 
229  // std::cout<<"Computing W matrix"<<std::endl;
230 
231  //typedef vnl_svd<TScalarType> SVDSolverType;
232 
233  if(!m_LMatrixComputed) {
234  this->ComputeL();
235  }
236  this->ComputeY();
237 
238  //SVDSolverType svd( m_LMatrix, 1e-8 );
239  //m_WMatrix = svd.solve( m_YMatrix );
240 
241  clock.Start();
242 
243  //Eigen::BiCGSTAB<LMatrixType> solver;
245  solver.preconditioner().setDroptol(1e-10);
246  solver.preconditioner().setFillfactor(1000);
247 
248  // Eigen::SparseLU<LMatrixType> solver;
249  solver.compute(m_LMatrix);
250 
251  if(solver.info()!= Eigen::Success) {
252  // decomposition failed
253  throw std::runtime_error("LMatrix failed to decompose ...!");
254  }
255 
256  unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
257  m_WMatrix = WMatrixType::Zero(NDimensions*(numberOfLandmarks+NDimensions+1), 1);
258  m_WMatrix = solver.solve(m_YMatrix);
259 
260  // m_WMatrix = WMatrixType::Random(NDimensions*(numberOfLandmarks+NDimensions+1), 1);
261  // solver.setMaxIterations(1);
262  // int i = 0;
263  // do {
264  // m_WMatrix = solver.solveWithGuess(m_YMatrix,m_WMatrix);
265  // std::cout << "#iteration: " << i << " " << "estimated error: " << solver.error() << std::endl;
266  // ++i;
267  // } while (solver.info()!= Eigen::Success && i<100);
268 
269  std::cout << "#iterations: " << solver.iterations() << std::endl;
270  std::cout << "estimated error: " << solver.error() << std::endl;
271 
272  std::cout << solver.error() << std::endl;
273  if(solver.info() != Eigen::Success) {
274  // solving failed
275  throw std::runtime_error("solving sparse system failed ...!");
276  }
277 
278  clock.Stop();
279  std::cout << "Computing Wmatrix:" << std::endl;
280  std::cout << "Mean: " << clock.GetMean() << std::endl;
281  std::cout << "Total: " << clock.GetTotal() << std::endl;
282 
283  this->ReorganizeW();
284  m_WMatrixComputed=true;
285 }
286 
290 //template <class TScalarType, unsigned int NDimensions>
291 //void SparseKernelTransform<TScalarType, NDimensions>::
292 //ComputeLInverse(void) const
293 //{
294 // // Assumes that L has already been computed
295 // // Necessary for the jacobian
296 // if(!m_LMatrixComputed) {
297 // this->ComputeL();
298 // }
299 // //std::cout<<"LMatrix is:"<<std::endl;
300 // //std::cout<<m_LMatrix<<std::endl;
301 
302 // itk::TimeProbesCollectorBase timeCollector;
303 // if (0){
304 // timeCollector.Start( "ComputeLInverse" );
305 // m_LMatrixInverse=vnl_matrix_inverse<TScalarType> (m_LMatrix);
306 // timeCollector.Stop( "ComputeLInverse" );
307 // }
308 
309 // // Convert to sparse matrix
310 // // Because of the special storage scheme of a SparseMatrix, special care has to be taken when adding new nonzero entries.
311 // // For instance, the cost of a single purely random insertion into a SparseMatrix is O(nnz),
312 // // where nnz is the current number of non-zero coefficients.
313 // // The simplest way to create a sparse matrix while guaranteeing good performance is thus to first build a list of
314 // // so-called triplets, and then convert it to a SparseMatrix.
315 // typedef Eigen::SparseMatrix<ScalarType> SpMat; // declares a column-major sparse matrix type of double
316 // typedef Eigen::Triplet<ScalarType> Triplet;
317 // SpMat A(m_LMatrix.rows(),m_LMatrix.cols());
318 
319 // std::vector<Triplet> tripletList;
320 // for ( unsigned int r = 0; r < m_LMatrix.rows(); r++ )
321 // for ( unsigned int c = 0; c < m_LMatrix.cols(); c++ )
322 // {
323 // ScalarType val = m_LMatrix.get( r, c );
324 // if ( val != 0 )
325 // tripletList.push_back(Triplet(r,c,val));
326 // }
327 // A.setFromTriplets(tripletList.begin(), tripletList.end());
328 // timeCollector.Stop( "ConvertLToSparse" );
329 
330 // // Method 4: LU Decomposition
331 // // Depends on local ITK vnl_sparse_lu modification
332 // timeCollector.Start( "ComputeLSparseInverse" );
333 // unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
334 // // vnl_sparse_symmetric_eigensystem eigSys;
335 // // eigSys.CalculateNPairs(lSparseMatrix,NDimensions*(numberOfLandmarks+NDimensions+1), false);
336 // // //LSparseMatrixType lMatrixInverse = vnl_sparse_lu( lSparseMatrix ).inverse();
337 // // timeCollector.Stop( "ComputeLSparseInverse" );
338 
339 
340 // m_LInverseComputed=true;
341 // //std::cout<<"LMatrix inverse is:"<<std::endl;
342 // //std::cout<<m_LMatrixInverse<<std::endl;
343 //}
344 
345 
349 template <class TScalarType, unsigned int NDimensions>
351 ComputeL(void) const
352 {
353  unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
354  //vnl_matrix<TScalarType> O2(NDimensions*(NDimensions+1),
355  // NDimensions*(NDimensions+1), 0);
356 
357  this->ComputeP();
358  this->ComputeK();
359 
360  //m_LMatrix.set_size( NDimensions*(numberOfLandmarks+NDimensions+1),
361  // NDimensions*(numberOfLandmarks+NDimensions+1) );
362  //m_LMatrix.fill( 0.0 );
363  m_LMatrix = LMatrixType( NDimensions*(numberOfLandmarks+NDimensions+1),
364  NDimensions*(numberOfLandmarks+NDimensions+1) );
365 
366  //std::vector<TripletType> tripletList;
367 
368  // putting KMATRIX
369  //m_LMatrix.update( m_KMatrix, 0, 0 );
370  //it.value();
371  //it.row(); // row index
372  //it.col(); // col index (here it is equal to k)
373  //it.index(); // inner index, here it is equal to it.row()
374  for (int k = 0; k < m_KMatrix.outerSize(); ++k) // column index
375  for (typename KMatrixType::InnerIterator it(m_KMatrix,k); it; ++it)
376  m_LMatrix.insert(it.row(), it.col()) = it.value() ;
377  //tripletList.push_back( TripletType ( it.row(), it.col(), it.value() ) );
378 
379  // putting PMATRIX - will keep the lower only ??
380  //m_LMatrix.update( m_PMatrix, 0, m_KMatrix.columns() );
381  //m_LMatrix.update( m_PMatrix.transpose(), m_KMatrix.rows(), 0);
382  for (int p = 0; p < m_PMatrix.outerSize(); ++p) // column index
383  for (typename PMatrixType::InnerIterator it(m_PMatrix,p); it; ++it)
384  {
385  // fill P -> upper
386  m_LMatrix.insert(it.row(), NDimensions*numberOfLandmarks + it.col()) = it.value() ;
387  //tripletList.push_back( TripletType ( it.row(), NDimensions*numberOfLandmarks + it.col(), it.value() ) );
388 
389  // fill P.transpose -> lower
390  m_LMatrix.insert(NDimensions*numberOfLandmarks + it.col(), it.row()) = it.value() ;
391  //tripletList.push_back( TripletType ( NDimensions*numberOfLandmarks + it.col(), it.row(), it.value() ) );
392  }
393  //m_LMatrix.update( O2, m_KMatrix.rows(), m_KMatrix.columns());
394 
395  // // shireen: for debugging let's make sure that the L matrix is sparse (based on gaussian basis)
396  // std::ofstream ofs;
397  // ofs.open("Lsparse.csv");
398  // for (int k = 0; k < m_LMatrix.outerSize(); ++k) // column index
399  // for (typename LMatrixType::InnerIterator it(m_LMatrix,k); it; ++it)
400  // ofs << it.row() << ", " << it.col() << ", " << it.value() << std::endl;
401  // ofs.close();
402 
403 
404  std::cout << "Lmatrix - nnz = " << m_LMatrix.nonZeros() << std::endl;
406 
407  //m_LMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
409 }
410 
411 
415 template <class TScalarType, unsigned int NDimensions>
417 ComputeK(void) const
418 {
419  unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
420  GMatrixType G;
421  //std::vector<TripletType> tripletList;
422 
423  m_KMatrix = KMatrixType( NDimensions * numberOfLandmarks,
424  NDimensions * numberOfLandmarks );
425  //m_KMatrix.set_size( NDimensions * numberOfLandmarks,
426  // NDimensions * numberOfLandmarks );
427 
428  //m_KMatrix.fill( 0.0 );
429 
430  PointsIterator p1 = m_SourceLandmarks->GetPoints()->Begin();
431  PointsIterator end = m_SourceLandmarks->GetPoints()->End();
432 
433  // K matrix is symmetric, so only evaluate the upper triangle and
434  // store the values in both the upper and lower triangle
435  unsigned int i = 0;
436  while( p1 != end )
437  {
438  PointsIterator p2 = p1; // start at the diagonal element
439  unsigned int j = i;
440 
441  // Compute the block diagonal element, i.e. kernel for pi->pi
442  //G = ComputeReflexiveG(p1);
443 
444  // force to compute the basis on the diagonal
445  const InputVectorType s = p1.Value() - p1.Value();
446  G = ComputeG(s); // the basis
447 
448  //m_KMatrix.update(G, i*NDimensions, i*NDimensions);
449  for(unsigned int d = 0; d < NDimensions; d++)
450  {
451  if(G(d,d) != 0 )
452  m_KMatrix.insert(i*NDimensions+d ,i*NDimensions+d) = G(d,d) + m_Stiffness; // this is as a regularizer
453  //tripletList.push_back(TripletType(i*NDimensions+d ,i*NDimensions+d, m_GMatrix(d,d)));
454  }
455 
456  p2++;
457  j++;
458 
459  // Compute the upper (and copy into lower) triangular part of K
460  // only save the lower part, don't need it
461  while( p2 != end )
462  {
463  const InputVectorType s = p1.Value() - p2.Value();
464  G = ComputeG(s); // the basis
465 
466  // write value in upper and lower triangle of matrix
467  for(unsigned int ii = 0 ; ii < NDimensions; ii++)
468  for(unsigned int jj = 0 ; jj < NDimensions; jj++)
469  {
470  if (G(ii,jj) != 0)
471  {
472  m_KMatrix.insert(i*NDimensions+ii ,j*NDimensions+jj) = G(ii,jj); // upper
473  m_KMatrix.insert(j*NDimensions+ii ,i*NDimensions+jj) = G(ii,jj); // lower
474  }
475 
476  //tripletList.push_back(TripletType(i*NDimensions+ii ,j*NDimensions+jj, G(ii,jj)));
477  //tripletList.push_back(TripletType(j*NDimensions+ii ,i*NDimensions+jj, G(ii,jj)));
478  }
479 
480  // m_KMatrix.update(G, i*NDimensions, j*NDimensions);
481  // m_KMatrix.update(G, j*NDimensions, i*NDimensions);
482  p2++;
483  j++;
484  }
485  p1++;
486  i++;
487  }
488  //std::cout<<"K matrix: "<<std::endl;
489  //std::cout<<m_KMatrix<<std::endl;
490 
491  // // shireen: for debugging let's make sure that the L matrix is sparse (based on gaussian basis)
492  // std::ofstream ofs;
493  // ofs.open("Ksparse.csv");
494  // for (int k = 0; k < m_KMatrix.outerSize(); ++k) // column index
495  // for (typename KMatrixType::InnerIterator it(m_KMatrix,k); it; ++it)
496  // ofs << it.row() << ", " << it.col() << ", " << it.value() << std::endl;
497  // ofs.close();
498 
499  std::cout << "Kmatrix - nnz = " << m_KMatrix.nonZeros() << std::endl;
501 
502  //m_KMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
503 }
504 
505 
506 
510 template <class TScalarType, unsigned int NDimensions>
512 ComputeP() const
513 {
514  unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
515 
516  //IMatrixType I = IMatrixType::Identity();
517  //IMatrixType temp;
518  InputPointType p;
519 
520  //I.set_identity();
521 
522  //std::vector<TripletType> tripletList;
523 
524  //m_PMatrix.set_size( NDimensions*numberOfLandmarks,
525  // NDimensions*(NDimensions+1) );
526  //m_PMatrix.fill( 0.0 );
527  m_PMatrix = PMatrixType(NDimensions*numberOfLandmarks,
528  NDimensions*(NDimensions+1) );
529  for (unsigned int i = 0; i < numberOfLandmarks; i++)
530  {
531  m_SourceLandmarks->GetPoint(i, &p);
532  for (unsigned int j = 0; j < NDimensions; j++)
533  {
534  //temp = I * p[j];
535  for(unsigned int d = 0 ; d < NDimensions; d++)
536  {
537  m_PMatrix.insert(i*NDimensions + d, j*NDimensions + d) = p[j];
538  //tripletList.push_back( TripletType( i*NDimensions + d, j*NDimensions + d, p[j] ) );
539  }
540  //m_PMatrix.update(temp, i*NDimensions, j*NDimensions);
541  }
542 
543  for(unsigned int d = 0 ; d < NDimensions; d++)
544  {
545  m_PMatrix.insert(i*NDimensions + d, NDimensions*NDimensions + d) = 1;
546  //tripletList.push_back( TripletType( i*NDimensions + d, NDimensions*NDimensions + d, 1 ) );
547  }
548  //m_PMatrix.update(I, i*NDimensions, NDimensions*NDimensions);
549  }
550 
551  std::cout << "Pmatrix - nnz = " << m_PMatrix.nonZeros() << std::endl;
553  //m_PMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
554 }
555 
556 
557 
561 template <class TScalarType, unsigned int NDimensions>
563 ComputeY(void) const
564 {
565  unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
566 
567  this->ComputeD();
568 
569  typename VectorSetType::ConstIterator displacement =
570  m_Displacements->Begin();
571 
572  //m_YMatrix.set_size( NDimensions*(numberOfLandmarks+NDimensions+1), 1);
573  //m_YMatrix.fill( 0.0 );
574  m_YMatrix = YMatrixType::Zero(NDimensions*(numberOfLandmarks+NDimensions+1), 1);
575 
576  for (unsigned int i = 0; i < numberOfLandmarks; i++)
577  {
578  for (unsigned int j = 0; j < NDimensions; j++)
579  {
580  m_YMatrix(i*NDimensions+j, 0) = displacement.Value()[j];
581  //m_YMatrix.put(i*NDimensions+j, 0, displacement.Value()[j]);
582  }
583  displacement++;
584  }
585 
586  for (unsigned int i = 0; i < NDimensions*(NDimensions+1); i++)
587  {
588  m_YMatrix(numberOfLandmarks*NDimensions+i, 0) = 0;
589  //m_YMatrix.put(numberOfLandmarks*NDimensions+i, 0, 0);
590  }
591 }
592 
593 
597 template <class TScalarType, unsigned int NDimensions>
598 void
600 ::ReorganizeW(void) const
601 {
602  unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
603 
604  // The deformable (non-affine) part of the registration goes here
605  m_DMatrix = DMatrixType::Zero(NDimensions,numberOfLandmarks);
606  //m_DMatrix.set_size(NDimensions,numberOfLandmarks);
607 
608  unsigned int ci = 0;
609  for(unsigned int lnd=0; lnd < numberOfLandmarks; lnd++ )
610  {
611  for(unsigned int dim=0; dim < NDimensions; dim++ )
612  {
613  //std::cout << m_WMatrix(ci,0) << std::endl;
614  m_DMatrix(dim,lnd) = m_WMatrix(ci++,0);
615  }
616  }
617 
618  // This matrix holds the rotational part of the Affine component
619  m_AMatrix = AMatrixType::Zero(NDimensions, NDimensions);
620  for(unsigned int j=0; j < NDimensions; j++ )
621  {
622  for(unsigned int i=0; i < NDimensions; i++ )
623  {
624  m_AMatrix(i,j) = m_WMatrix(ci++,0);
625  }
626  }
627 
628  // This vector holds the translational part of the Affine component
629  m_BVector = BMatrixType::Zero(NDimensions,1);
630  for(unsigned int k=0; k < NDimensions; k++ )
631  {
632  m_BVector(k) = m_WMatrix(ci++,0);
633  }
634 
635  // release WMatrix memory by assigning a small one.
636  m_WMatrix = WMatrixType(1,1);
637 
639 
640  // std::ofstream ofs;
641  // ofs.open("D.csv");
642  // for (int k = 0; k < m_DMatrix.outerSize(); ++k) // column index
643  // for (typename DMatrixType::InnerIterator it(m_DMatrix,k); it; ++it)
644  // ofs << it.row() << ", " << it.col() << ", " << it.value() << std::endl;
645  // ofs.close();
646 }
647 
648 
649 
653 template <class TScalarType, unsigned int NDimensions>
654 typename SparseKernelTransform<TScalarType, NDimensions>::OutputPointType
656 ::TransformPoint(const InputPointType& thisPoint) const
657 {
658 
659  OutputPointType result;
660 
661  typedef typename OutputPointType::ValueType ValueType;
662 
663  result.Fill( NumericTraits< ValueType >::Zero );
664 
665  this->ComputeDeformationContribution( thisPoint, result );
666 
667  // Add the rotational part of the Affine component
668  for(unsigned int j=0; j < NDimensions; j++ )
669  {
670  for(unsigned int i=0; i < NDimensions; i++ )
671  {
672  result[i] += m_AMatrix(i,j) * thisPoint[j];
673  }
674  }
675 
676 
677 
678  // This vector holds the translational part of the Affine component
679  for(unsigned int k=0; k < NDimensions; k++ )
680  {
681  result[k] += m_BVector(k) + thisPoint[k];
682  }
683 
684  return result;
685 
686 }
687 
688 
689 
690 
692 //template <class TScalarType, unsigned int NDimensions>
693 //const typename SparseKernelTransform<TScalarType,NDimensions>::JacobianType &
694 //SparseKernelTransform< TScalarType,NDimensions>::
695 //GetJacobian( const InputPointType & thisPoint) const
696 //{
697 // if(!m_LInverseComputed) {
698 // this->ComputeLInverse();
699 // }
700 // unsigned long numberOfLandmarks = m_SourceLandmarks->GetNumberOfPoints();
701 // Superclass::m_Jacobian.SetSize(NDimensions, numberOfLandmarks*NDimensions);
702 // Superclass::m_Jacobian.Fill( 0.0 );
703 
704 // PointsIterator sp = m_SourceLandmarks->GetPoints()->Begin();
705 // for(unsigned int lnd=0; lnd < numberOfLandmarks; lnd++ )
706 // {
707 // const GMatrixType & Gmatrix = ComputeG( thisPoint - sp->Value() );
708 // ///std::cout<<"G for landmark "<<lnd<<std::endl<<Gmatrix<<std::endl;
709 // for(unsigned int dim=0; dim < NDimensions; dim++ )
710 // {
711 // for(unsigned int odim=0; odim < NDimensions; odim++ )
712 // {
713 // for(unsigned int lidx=0; lidx < numberOfLandmarks*NDimensions; lidx++ )
714 // {
715 // Superclass::m_Jacobian[ odim ] [lidx] += Gmatrix(dim, odim ) *
716 // m_LMatrixInverse[lnd*NDimensions+dim][lidx];
717 // }
718 // }
719 // }
720 // ++sp;
721 
722 // }
723 // for(unsigned int odim=0; odim < NDimensions; odim++ )
724 // {
725 // for(unsigned int lidx=0; lidx < numberOfLandmarks*NDimensions; lidx++ )
726 // {
727 // for(unsigned int dim=0; dim < NDimensions; dim++ )
728 // {
729 // Superclass::m_Jacobian[ odim ] [lidx] += thisPoint[dim] *
730 // m_LMatrixInverse[(numberOfLandmarks+dim)*NDimensions+odim][lidx];
731 // }
732 
733 // Superclass::m_Jacobian[ odim ] [lidx] += m_LMatrixInverse[(numberOfLandmarks+NDimensions)*NDimensions+odim][lidx];
734 // }
735 // }
736 
737 // return Superclass::m_Jacobian;
738 
739 //}
740 
741 // Set to the identity transform - ie make the Source and target lm the same
742 template <class TScalarType, unsigned int NDimensions>
743 void
746 {
747  this->SetParameters(this->GetFixedParameters());
748 }
749 
750 // Set the parameters
751 // NOTE that in this transformation both the Source and Target
752 // landmarks could be considered as parameters. It is assumed
753 // here that the Target landmarks are provided by the user and
754 // are not changed during the optimization process required for
755 // registration.
756 template <class TScalarType, unsigned int NDimensions>
757 void
759 SetParameters( const ParametersType & parameters )
760 {
761  // std::cout<<"Setting parameters to "<<parameters<<std::endl;
762  typename PointsContainer::Pointer landmarks = PointsContainer::New();
763  const unsigned int numberOfLandmarks = parameters.Size() / NDimensions;
764  landmarks->Reserve( numberOfLandmarks );
765 
766  PointsIterator itr = landmarks->Begin();
767  PointsIterator end = landmarks->End();
768 
769  InputPointType landMark;
770 
771  unsigned int pcounter = 0;
772  while( itr != end )
773  {
774  for(unsigned int dim=0; dim<NDimensions; dim++)
775  {
776  landMark[ dim ] = parameters[ pcounter ];
777  pcounter++;
778  }
779  itr.Value() = landMark;
780  itr++;
781  }
782 
783  // m_SourceLandmarks->SetPoints( landmarks );
784  m_TargetLandmarks->SetPoints( landmarks );
785 
786  // W MUST be recomputed if the target lms are set
787  this->ComputeWMatrix();
788 
789  // if(!m_LInverseComputed) {
790  // this->ComputeLInverse();
791  // }
792 
793  // Modified is always called since we just have a pointer to the
794  // parameters and cannot know if the parameters have changed.
795  this->Modified();
796 
797 }
798 
799 // Set the fixed parameters
800 // Since the API of the SetParameters() function sets the
801 // source landmarks, this function was added to support the
802 // setting of the target landmarks, and allowing the Transform
803 // I/O mechanism to be supported.
804 template <class TScalarType, unsigned int NDimensions>
805 void
807 SetFixedParameters( const ParametersType & parameters )
808 {
809  typename PointsContainer::Pointer landmarks = PointsContainer::New();
810  const unsigned int numberOfLandmarks = parameters.Size() / NDimensions;
811 
812  landmarks->Reserve( numberOfLandmarks );
813 
814  PointsIterator itr = landmarks->Begin();
815  PointsIterator end = landmarks->End();
816 
817  InputPointType landMark;
818 
819  unsigned int pcounter = 0;
820  while( itr != end )
821  {
822  for(unsigned int dim=0; dim<NDimensions; dim++)
823  {
824  landMark[ dim ] = parameters[ pcounter ];
825  pcounter++;
826  }
827  itr.Value() = landMark;
828  itr++;
829  }
830 
831  // m_TargetLandmarks->SetPoints( landmarks );
832  m_SourceLandmarks->SetPoints( landmarks );
833 
834  // these are invalidated when the source lms change
835  m_WMatrixComputed=false;
836  m_LMatrixComputed=false;
837  m_LInverseComputed=false;
838 
839  // you must recompute L and Linv - this does not require the targ lms
840  //this->ComputeLInverse();
841  this->ComputeL();
842 
843 }
844 
845 
846 // Update parameters array
847 // They are the components of all the landmarks in the source space
848 template <class TScalarType, unsigned int NDimensions>
849 void
851 UpdateParameters( void ) const
852 {
853  this->m_Parameters = ParametersType( m_TargetLandmarks->GetNumberOfPoints() * NDimensions );
854 
855  PointsIterator itr = m_TargetLandmarks->GetPoints()->Begin();
856  PointsIterator end = m_TargetLandmarks->GetPoints()->End();
857 
858  unsigned int pcounter = 0;
859  while( itr != end )
860  {
861  InputPointType landmark = itr.Value();
862  for(unsigned int dim=0; dim<NDimensions; dim++)
863  {
864  this->m_Parameters[ pcounter ] = landmark[ dim ];
865  pcounter++;
866  }
867  itr++;
868  }
869 }
870 
871 
872 
873 
874 // Get the parameters
875 // They are the components of all the landmarks in the source space
876 template <class TScalarType, unsigned int NDimensions>
879 GetParameters( void ) const
880 {
881  this->UpdateParameters();
882  return this->m_Parameters;
883 
884 }
885 
886 
887 // Get the fixed parameters
888 // This returns the target landmark locations
889 // This was added to support the Transform Reader/Writer mechanism
890 template <class TScalarType, unsigned int NDimensions>
893 GetFixedParameters( void ) const
894 {
895  this->m_FixedParameters = ParametersType( m_SourceLandmarks->GetNumberOfPoints() * NDimensions );
896 
897  PointsIterator itr = m_SourceLandmarks->GetPoints()->Begin();
898  PointsIterator end = m_SourceLandmarks->GetPoints()->End();
899 
900  unsigned int pcounter = 0;
901  while( itr != end )
902  {
903  InputPointType landmark = itr.Value();
904  for(unsigned int dim=0; dim<NDimensions; dim++)
905  {
906  this->m_FixedParameters[ pcounter ] = landmark[ dim ];
907  pcounter++;
908  }
909  itr++;
910  }
911 
912  return this->m_FixedParameters;
913 
914 }
915 
916 
917 
918 template <class TScalarType, unsigned int NDimensions>
919 void
921 PrintSelf(std::ostream& os, Indent indent) const
922 {
923  Superclass::PrintSelf(os,indent);
924  if (m_SourceLandmarks)
925  {
926  os << indent << "SourceLandmarks: " << std::endl;
927  m_SourceLandmarks->Print(os,indent.GetNextIndent());
928  }
929  if (m_TargetLandmarks)
930  {
931  os << indent << "TargetLandmarks: " << std::endl;
932  m_TargetLandmarks->Print(os,indent.GetNextIndent());
933  }
934  if (m_Displacements)
935  {
936  os << indent << "Displacements: " << std::endl;
937  m_Displacements->Print(os,indent.GetNextIndent());
938  }
939  os << indent << "Stiffness: " << m_Stiffness << std::endl;
940 }
941 } // namespace itk
942 
943 #endif
A bi conjugate gradient stabilized solver for sparse square problems.
Definition: BiCGSTAB.h:112
Superclass::JacobianType JacobianType
BiCGSTAB< _MatrixType, _Preconditioner > & compute(const MatrixType &A)
virtual void ComputeDeformationContribution(const InputPointType &inputPoint, OutputPointType &result) const
Index outerSize() const
Definition: SparseMatrix.h:126
Superclass::ParametersType ParametersType
Superclass::InputVectorType InputVectorType
virtual const GMatrixType & ComputeG(const InputVectorType &landmarkVector) const
Eigen::SparseMatrix< TScalarType > LMatrixType
Superclass::InputPointType InputPointType
virtual void SetParameters(const ParametersType &)
virtual void UpdateParameters(void) const
Index nonZeros() const
Definition: SparseMatrix.h:246
virtual OutputPointType TransformPoint(const InputPointType &thisPoint) const
virtual void SetSourceLandmarks(PointSetType *)
Eigen::SparseMatrix< TScalarType > KMatrixType
virtual const GMatrixType & ComputeReflexiveG(PointsIterator) const
virtual const ParametersType & GetFixedParameters(void) const
Scalar & insert(Index row, Index col)
Definition: SparseMatrix.h:220
virtual void SetTargetLandmarks(PointSetType *)
Eigen::SparseMatrix< TScalarType > PMatrixType
virtual const ParametersType & GetParameters(void) const
Eigen::Matrix< TScalarType, Eigen::Dynamic, Eigen::Dynamic > WMatrixType
const internal::solve_retval< BiCGSTAB< _MatrixType, _Preconditioner >, Rhs > solve(const MatrixBase< Rhs > &b) const
virtual void SetFixedParameters(const ParametersType &)