Orfeo Toolbox  3.16
itkDeformableSimplexMesh3DFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkDeformableSimplexMesh3DFilter.txx,v $
5  Language: C++
6  Date: $Date: 2009-10-29 18:40:35 $
7  Version: $Revision: 1.26 $
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  Portions of this code are covered under the VTK copyright.
13  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details.
14 
15  This software is distributed WITHOUT ANY WARRANTY; without even
16  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
17  PURPOSE. See the above copyright notices for more information.
18 
19 =========================================================================*/
20 #ifndef __itkDeformableSimplexMesh3DFilter_txx
21 #define __itkDeformableSimplexMesh3DFilter_txx
22 
24 #include "itkNumericTraits.h"
25 
26 #include <set>
27 
28 #include <vxl_version.h>
29 #if VXL_VERSION_DATE_FULL > 20040406
30 # include <vnl/vnl_cross.h>
31 # define itk_cross_3d vnl_cross_3d
32 #else
33 # define itk_cross_3d cross_3d
34 #endif
35 
36 namespace itk
37 {
38 
39 /* Constructor. */
40 template <typename TInputMesh, typename TOutputMesh>
43 {
44  m_Step = 0;
45  m_Iterations = 20;
46  m_Alpha = 0.2;
47  m_Beta = 0.01;
48  m_Gamma = 0.05;
49  m_Damping = 0.65;
50  m_Rigidity = 1;
51 
52  m_ImageDepth = 0;
53  m_ImageHeight = 0;
54  m_ImageWidth = 0;
55 
57 
58  OutputMeshPointer output = OutputMeshType::New();
60  this->ProcessObject::SetNthOutput(0, output.GetPointer());
61 
62  this->m_Data = NULL;
63 }
64 
65 template <typename TInputMesh, typename TOutputMesh>
68 {
69 }
70 
71 
72 /* PrintSelf. */
73 template <typename TInputMesh, typename TOutputMesh>
74 void
76 ::PrintSelf(std::ostream& os, Indent indent) const
77 {
78  Superclass::PrintSelf(os,indent);
79  os << indent << "Alpha = " << this->GetAlpha() << std::endl;
80  os << indent << "Beta = " << this->GetBeta() << std::endl;
81  os << indent << "Gamma = " << this->GetGamma() << std::endl;
82  os << indent << "Rigidity = " << this->GetRigidity() << std::endl;
83  os << indent << "Iterations = " << this->GetIterations() << std::endl;
84  os << indent << "Step = " << this->GetStep() << std::endl;
85  os << indent << "ImageDepth = " << this->GetImageDepth() << std::endl;
86  if( this->GetGradient().IsNotNull() )
87  {
88  os << indent << "Gradient = " << this->GetGradient() << std::endl;
89  }
90  else
91  {
92  os << indent << "Gradient = " << "(None)" << std::endl;
93  }
94  os << indent << "ImageHeight = " << this->GetImageHeight() << std::endl;
95  os << indent << "ImageWidth = " << this->GetImageWidth() << std::endl;
96  os << indent << "Damping = " << this->GetDamping() << std::endl;
97  if( this->m_Data.IsNotNull() )
98  {
99  os << indent << "Data = " << this->GetData() << std::endl;
100  }
101  else
102  {
103  os << indent << "Data = " << "(None)" << std::endl;
104  }
105 
106 
107 }/* End PrintSelf. */
108 
109 
110 /* Generate Data */
111 template <typename TInputMesh, typename TOutputMesh>
112 void
115 {
116  this->Initialize();
117 
118  m_Step = 0;
119 
120  while ( m_Step < m_Iterations )
121  {
122  const float progress = static_cast<float>( m_Step ) /
123  static_cast<float>( m_Iterations );
124 
125  this->UpdateProgress( progress );
126 
127  this->ComputeGeometry();
128 
129  if ( m_Step % 10 == 0 && m_Step > 0 )
130  {
131  this->UpdateReferenceMetrics();
132  }
133 
134  this->ComputeDisplacement();
135  m_Step++;
136  }
137 
138  const InputMeshType * inputMesh = this->GetInput(0);
139  const InputPointsContainer * points = inputMesh->GetPoints();
140  InputPointsContainerConstIterator pointItr = points->Begin();
141 
142  while( pointItr != points->End() )
143  {
144  SimplexMeshGeometry * data;
145  unsigned long idx = pointItr.Index();
146  data = this->m_Data->GetElement(idx);
147  delete data->neighborSet;
148  pointItr++;
149  }
150  this->ComputeOutput();
151 }
152 
153 
154 /* Set default value of parameters and initialize local data container
155  * such as forces, displacements and displacement derivatives. */
156 template <typename TInputMesh, typename TOutputMesh>
157 void
160 {
161  const InputMeshType * inputMesh = this->GetInput(0);
162  const InputPointsContainer * points = inputMesh->GetPoints();
163  InputPointsContainerConstIterator pointItr = points->Begin();
164 
165  if ( this->m_Gradient.IsNotNull() )
166  {
167  GradientImageSizeType imageSize = this->m_Gradient->GetBufferedRegion().GetSize();
168 
169  m_ImageWidth = imageSize[0];
170  m_ImageHeight = imageSize[1];
171  m_ImageDepth = imageSize[2];
172  }
173  else
174  {
175  m_ImageWidth = 0;
176  m_ImageHeight = 0;
177  m_ImageDepth = 0;
178  }
179 
180  if( this->m_Data.IsNull() )
181  {
182  this->m_Data = this->GetInput(0)->GetGeometryData();
183  }
184 
185  while( pointItr != points->End() )
186  {
187  SimplexMeshGeometry * data;
188  unsigned long idx = pointItr.Index();
189 
190  data = this->m_Data->GetElement(idx);
191  data->pos = pointItr.Value();
192 
193  // InputMeshType::ArrayType neighbors = this->GetInput(0)->GetNeighbors( pointItr.Index() );
194 
195  data->neighbors[0] = points->GetElement(data->neighborIndices[0]);
196  data->neighbors[1] = points->GetElement(data->neighborIndices[1]);
197  data->neighbors[2] = points->GetElement(data->neighborIndices[2]);
198 
199  // store neighborset with a specific radius
200  InputNeighbors* neighborsList = this->GetInput(0)->GetNeighbors( pointItr.Index() , m_Rigidity);
201  InputNeighborsIterator neighborIt = neighborsList->begin();
202 
203  NeighborSetType * neighborSet = new NeighborSetType();
204  while ( neighborIt != neighborsList->end() )
205  {
206  neighborSet->insert( *neighborIt++ );
207  }
208  // garbage collection (from itkSimplexMesh)
209  delete neighborsList;
210  data->neighborSet = neighborSet;
211 
212  pointItr++;
213  }
214 
215  OutputMeshPointer outputMesh = this->GetOutput();
216 }
217 
218 /* Compute normals. */
219 template <typename TInputMesh, typename TOutputMesh>
220 void
223 {
224  PointType Foot;
225  CovariantVectorType normal;
227  VectorType tmp;
228  // unsigned long idx = 0;
229 
230  const InputMeshType * inputMesh = this->GetInput(0);
231  const InputPointsContainer * points = inputMesh->GetPoints();
232 
233  typename GeometryMapType::Iterator dataIt = this->m_Data->Begin();
234 
235  SimplexMeshGeometry* data;
236 
237  while ( dataIt != this->m_Data->End() )
238  {
239  // idx = dataIt.Index();
240  data = dataIt.Value();
241 
242  data->neighbors[0] = points->GetElement(data->neighborIndices[0]);
243  data->neighbors[1] = points->GetElement(data->neighborIndices[1]);
244  data->neighbors[2] = points->GetElement(data->neighborIndices[2]);
245 
246  // compute normal
247  normal.Fill(0.0);
248 
249  z.Set_vnl_vector( itk_cross_3d( (data->neighbors[1] - data->neighbors[0]).Get_vnl_vector() ,
250  (data->neighbors[2] - data->neighbors[0]).Get_vnl_vector()) );
251  z.Normalize();
252  normal += z;
253 
254  // copy normal
255  data->normal = normal;
256 
257  // compute the simplex angle
258  data->ComputeGeometry();
259 
260  tmp = data->neighbors[0] - data->pos;
261 
262  double D = 1.0/(2*data->sphereRadius); /* */
263 
264  double tmpNormalProd = dot_product(tmp.Get_vnl_vector(),data->normal.Get_vnl_vector());
265 
266  double sinphi = 2 * data->circleRadius * D * vnl_math_sgn( tmpNormalProd );
267  double phi = vcl_asin(sinphi);
268 
269  data->phi = phi;
270  data->meanCurvature = vcl_abs(sinphi/data->circleRadius);
271  tmp = data->pos - data->neighbors[0];
272 
273  //compute the foot of p projection of p onto the triangle spanned by its neighbors
274  double distance = -tmpNormalProd;
275  tmp.Set_vnl_vector((data->pos).Get_vnl_vector() - distance * normal.Get_vnl_vector() );
276  Foot.Fill(0.0);
277  Foot += tmp;
278 
279  data->distance = ((data->circleCenter)-Foot).GetNorm();
280 
281  data->eps = ComputeBarycentricCoordinates( Foot, data);
282  dataIt.Value() = data;
283  dataIt++;
284  }
285 }
286 
287 template <typename TInputMesh, typename TOutputMesh>
288 void
291 {
292  const InputMeshType * inputMesh = this->GetInput(0);
293 
294  // Filters should not modify their input...
295  // There is a design flaw here.
296  InputPointsContainer * nonConstPoints =
297  const_cast< InputPointsContainer * >( inputMesh->GetPoints() );
298 
299  typename GeometryMapType::Iterator dataIt = this->m_Data->Begin();
300  SimplexMeshGeometry * data;
301  VectorType displacement;
302 
303  while( dataIt != this->m_Data->End() )
304  {
305  data = dataIt.Value();
306 
307  this->ComputeInternalForce( data );
308 
309  this->ComputeExternalForce( data );
310 
311  displacement.Set_vnl_vector( m_Alpha * (data->internalForce).Get_vnl_vector() +
312  (data->externalForce).Get_vnl_vector() );
313 
314  data->pos += displacement;
315  nonConstPoints->InsertElement( dataIt.Index(), data->pos );
316 
317  dataIt++;
318  }
319 }
320 
321 /* */
322 template <typename TInputMesh, typename TOutputMesh>
323 void
326 {
327  VectorType tangentForce, normalForce;
328  double eps1Diff, eps2Diff, eps3Diff;
329  // double diffAbsSum;
330  double d, phi, r;
331  NeighborSetType * neighborSet;
332  PointType xOrig;
333  PointType eps, epsRef;
334  double phiRef;
335  PointType f_int;
336 
337  xOrig = data->pos;
338  eps = data->eps;
339  epsRef = data->referenceMetrics;
340 
341  eps1Diff = epsRef[0]-eps[0];
342  eps2Diff = epsRef[1]-eps[1];
343  eps3Diff = epsRef[2]-eps[2];
344  // diffAbsSum = vcl_abs(eps1Diff)+vcl_abs(eps2Diff)+vcl_abs(eps3Diff);
345 
346  tangentForce.Set_vnl_vector( eps1Diff * (data->neighbors[0]).Get_vnl_vector() +
347  eps2Diff * (data->neighbors[1]).Get_vnl_vector() +
348  eps3Diff * (data->neighbors[2]).Get_vnl_vector()
349  );
350 
351  r = data->circleRadius;
352  d = data->distance;
353  phi = data->phi;
354 
355  neighborSet = data->neighborSet;
356 
357  NeighborSetIterator neighborIt = neighborSet->begin();
358  phiRef = 0.0;
359 
360  while ( neighborIt != neighborSet->end() )
361  {
362  phiRef += this->m_Data->GetElement(*neighborIt++)->phi;
363  }
364  phiRef /= (double) neighborSet->size();
365 
366  double L = L_Func(r,d,phi);
367  double L_Ref = L_Func(r,d,phiRef);
368 
369  normalForce.Set_vnl_vector(-1.0 * ( L_Ref - L ) * (data->normal).Get_vnl_vector());
370 
371  data->internalForce.Fill(0.0);
372 
373  // quick hack fixing for div by zero error
374  if (L_Ref != (double) NumericTraits<unsigned long>::max() && L != (double) NumericTraits<unsigned long>::max())
375  {
376  data->internalForce += tangentForce + normalForce;
377  }
378 }
379 
380 
382 template <typename TInputMesh, typename TOutputMesh>
383 void
386 {
387  PointType vec_for, tmp_vec_1, tmp_vec_2, tmp_vec_3;
388  GradientIndexType coord, coord2, tmp_co_1, tmp_co_2, tmp_co_3;
389 
390  coord[0] = static_cast<GradientIndexValueType>(data->pos[0]);
391  coord[1] = static_cast<GradientIndexValueType>(data->pos[1]);
392  coord[2] = static_cast<GradientIndexValueType>(data->pos[2]);
393 
394  coord2[0] = static_cast<GradientIndexValueType>( vcl_ceil(data->pos[0]) );
395  coord2[1] = static_cast<GradientIndexValueType>( vcl_ceil(data->pos[1]) );
396  coord2[2] = static_cast<GradientIndexValueType>( vcl_ceil(data->pos[2]) );
397 
398  tmp_co_1[0] = coord2[0];
399  tmp_co_1[1] = coord[1];
400  tmp_co_1[2] = coord[2];
401 
402  tmp_co_2[0] = coord[0];
403  tmp_co_2[1] = coord2[1];
404  tmp_co_2[2] = coord[2];
405 
406  tmp_co_3[0] = coord[0];
407  tmp_co_3[1] = coord[1];
408  tmp_co_3[2] = coord2[2];
409 
410  if ( (coord[0] >= 0) && (coord[1] >= 0) && (coord[2] >= 0) &&
411  (coord2[0] < m_ImageWidth) && (coord2[1] < m_ImageHeight) && (coord2[2] < m_ImageDepth) )
412  {
413  vec_for[0] = m_Gradient->GetPixel(coord)[0];
414  vec_for[1] = m_Gradient->GetPixel(coord)[1];
415  vec_for[2] = m_Gradient->GetPixel(coord)[2];
416 
417  tmp_vec_1[0] = m_Gradient->GetPixel(tmp_co_1)[0] - m_Gradient->GetPixel(coord)[0];
418  tmp_vec_1[1] = m_Gradient->GetPixel(tmp_co_1)[1] - m_Gradient->GetPixel(coord)[1];
419  tmp_vec_1[2] = m_Gradient->GetPixel(tmp_co_1)[2] - m_Gradient->GetPixel(coord)[2];
420  tmp_vec_2[0] = m_Gradient->GetPixel(tmp_co_2)[0] - m_Gradient->GetPixel(coord)[0];
421  tmp_vec_2[1] = m_Gradient->GetPixel(tmp_co_2)[1] - m_Gradient->GetPixel(coord)[1];
422  tmp_vec_2[2] = m_Gradient->GetPixel(tmp_co_2)[2] - m_Gradient->GetPixel(coord)[2];
423  tmp_vec_3[0] = m_Gradient->GetPixel(tmp_co_3)[0] - m_Gradient->GetPixel(coord)[0];
424  tmp_vec_3[1] = m_Gradient->GetPixel(tmp_co_3)[1] - m_Gradient->GetPixel(coord)[1];
425  tmp_vec_3[2] = m_Gradient->GetPixel(tmp_co_3)[2] - m_Gradient->GetPixel(coord)[2];
426 
427  vec_for[0] = vec_for[0] + ((data->pos)[0]-coord[0])*tmp_vec_1[0]
428  + ((data->pos)[1]-coord[1])*tmp_vec_2[0] + ((data->pos)[2]-coord[2])*tmp_vec_3[0];
429  vec_for[1] = vec_for[1] + ((data->pos)[1]-coord[1])*tmp_vec_2[1]
430  + ((data->pos)[0]-coord[0])*tmp_vec_1[1] + ((data->pos)[2]-coord[2])*tmp_vec_3[1];
431  vec_for[2] = vec_for[2] + ((data->pos)[2]-coord[2])*tmp_vec_3[2]
432  + ((data->pos)[1]-coord[1])*tmp_vec_2[2] + ((data->pos)[0]-coord[0])*tmp_vec_1[2];
433  }
434  else
435  {
436  vec_for.Fill(0);
437  }
438 
439  double mag = dot_product(data->normal.Get_vnl_vector(),vec_for.Get_vnl_vector());
440  // double mag = vec_for[0]*(data->normal)[0] + vec_for[1]*(data->normal)[1]+ vec_for[2]*(data->normal)[2];
441 
442  vec_for[0] = mag*(data->normal)[0]/*num_for*/;
443  vec_for[1] = mag*(data->normal)[1]/*num_for*/;
444  vec_for[2] = mag*(data->normal)[2]/*num_for*/;
445 
446  mag = vec_for.GetVectorFromOrigin().GetNorm();
447 
448  if (mag > 0.5)
449  {
450  for (int i=0; i<3; i++)
451  vec_for[i] = (0.5 * vec_for[i])/mag;
452  }
453 
454  data->externalForce[0] = m_Beta * vec_for[0];
455  data->externalForce[1] = m_Beta * vec_for[1];
456  data->externalForce[2] = m_Beta * vec_for[2];
457 
458 }
459 
460 /* Copy the content of m_Location into the Output. */
461 template <typename TInputMesh, typename TOutputMesh>
462 void
465 {
466  OutputMeshType * output = this->GetOutput();
467 
468  this->CopyInputMeshToOutputMeshPoints();
469  this->CopyInputMeshToOutputMeshPointData();
470  this->CopyInputMeshToOutputMeshCells();
471  this->CopyInputMeshToOutputMeshCellData();
472 
473  output->SetGeometryData(this->m_Data);
474  output->SetLastCellId( this->GetInput(0)->GetLastCellId() );
475 }
476 
477 
478 /* */
479 template <typename TInputMesh, typename TOutputMesh>
480 void
483 {
484  const InputMeshType * inputMesh = this->GetInput(0);
485 
486  // Filters should not change their input.
487  // There is a design flaw here.
488  InputMeshType * nonConstInputMesh = const_cast< InputMeshType * >( inputMesh );
489 
490  double H;
491  double H_N1;
492  double H_N2;
493  double H_N3;
494  double H_Mean;
495 
496  GeometryMapIterator dataIt = this->m_Data->Begin();
497 
498  SimplexMeshGeometry * data;
499 
500  while ( dataIt != this->m_Data->End() )
501  {
502  data = dataIt->Value();
503  H_N1 =((SimplexMeshGeometry*)(this->m_Data->GetElement(data->neighborIndices[0])))->meanCurvature;
504  H_N2 =((SimplexMeshGeometry*)(this->m_Data->GetElement(data->neighborIndices[1])))->meanCurvature;
505  H_N3 =((SimplexMeshGeometry*)(this->m_Data->GetElement(data->neighborIndices[2])))->meanCurvature;
506  H = data->meanCurvature;
507 
508  H_Mean = (H_N1 + H_N2 + H_N3)/3.0;
509 
510  PointType deltaH;
511 
512  deltaH[0] = (H_N1 - H_Mean)/H_Mean;
513  deltaH[1] = (H_N2 - H_Mean)/H_Mean;
514  deltaH[2] = (H_N3 - H_Mean)/H_Mean;
515 
516  //deltaH[0] = (H_N1 - H_Mean)/H;
517  //deltaH[1] = (H_N2 - H_Mean)/H;
518  //deltaH[2] = (H_N3 - H_Mean)/H;
519 
520  PointType eps, eps_opt;
521  // compute optimal reference metrics
522  eps_opt[0] = (1.0/3.0) + m_Gamma * deltaH[0];
523  eps_opt[1] = (1.0/3.0) + m_Gamma * deltaH[1];
524  eps_opt[2] = (1.0/3.0) + m_Gamma * deltaH[2];
525 
526  eps = data->referenceMetrics;
527 
528  eps[0] = eps[0] + 0.5 * (eps_opt[0] - eps[0]);
529  eps[1] = eps[1] + 0.5 * (eps_opt[1] - eps[1]);
530  eps[2] = eps[2] + 0.5 * (eps_opt[2] - eps[2]);
531 
532  // set current reference metrics
533  data->referenceMetrics = eps;
534  nonConstInputMesh->SetPointData( dataIt->Index() , H );
535  dataIt.Value() = data;
536  // m_Data->InsertElement(dataIt->Index(),data);
537  dataIt++;
538  }
539 }
540 
541 
542 template <typename TInputMesh, typename TOutputMesh>
544 ::L_Func(double r,double d, double phi)
545 {
546  double r2 = r*r;
547  double d2 = d*d;
548  double r2Minusd2 = r2-d2;
549  double tanPhi = vcl_tan(phi);
550 
551  double eps = 1.0;
552  if (phi*vnl_math_sgn(phi) > vnl_math::pi_over_2)
553  {
554  eps = -1.0;
555  }
556  double L;
557  double tmpSqr = r2 + r2Minusd2 * tanPhi*tanPhi;
558  if (tmpSqr > 0)
559  {
560  double denom = eps*(vcl_sqrt(tmpSqr) + r);
561  if ( denom != 0 )
562  {
563  L = (r2Minusd2 * tanPhi) / denom;
564  }
565  else
566  {
567  L = (double) NumericTraits<unsigned long>::max();
568  // L = 0.0;
569  }
570  }
571  else
572  {
573  L = (double) NumericTraits<unsigned long>::max();
574  }
575  return L;
576 }
577 
578 
579 template <typename TInputMesh, typename TOutputMesh>
583 {
584  PointType a,b,c;
585  a = data->neighbors[0];
586  b = data->neighbors[1];
587  c = data->neighbors[2];
588 
589  VectorType n,na,nb,nc;
590  n.Set_vnl_vector( itk_cross_3d((b-a).Get_vnl_vector(), (c-a).Get_vnl_vector()) );
591  na.Set_vnl_vector( itk_cross_3d((c-b).Get_vnl_vector(), (p-b).Get_vnl_vector()) );
592  nb.Set_vnl_vector( itk_cross_3d((a-c).Get_vnl_vector(), (p-c).Get_vnl_vector()) );
593  nc.Set_vnl_vector( itk_cross_3d((b-a).Get_vnl_vector(), (p-a).Get_vnl_vector()) );
594 
595  PointType eps;
596  eps[0] = dot_product(n.Get_vnl_vector(),na.Get_vnl_vector()) / n.GetSquaredNorm();
597  eps[1] = dot_product(n.Get_vnl_vector(),nb.Get_vnl_vector()) / n.GetSquaredNorm();
598  eps[2] = dot_product(n.Get_vnl_vector(),nc.Get_vnl_vector()) / n.GetSquaredNorm();
599 
600  return eps;
601 }
602 } /* end namespace itk. */
603 
604 #endif //__itkDeformableSimplexMesh3DFilter_TXX

Generated at Sat Feb 2 2013 23:34:38 for Orfeo Toolbox with doxygen 1.8.1.1