Shapeworks Studio  2.1
Shape analysis software suite
itkPSMShapeEntropyFunction.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 __itkPSMShapeEntropyFunction_hxx
19 #define __itkPSMShapeEntropyFunction_hxx
20 #include "itkPSMShapeEntropyFunction.h"
21 
22 #include "vnl/algo/vnl_symmetric_eigensystem.h"
23 //#include "itkParticleGaussianModeWriter.h"
24 #include <string>
25 
26 namespace itk
27 {
28 
29 //template <unsigned int VDimension>
30 //void
31 //PSMShapeEntropyFunction<VDimension>
32 //::WriteModes(const std::string &prefix, int n) const
33 //{
34 // typename ParticleGaussianModeWriter<VDimension>::Pointer writer =
35 // ParticleGaussianModeWriter<VDimension>::New();
36 // writer->SetShapeMatrix(m_ShapeMatrix);
37 // writer->SetFileName(prefix.c_str());
38 // writer->SetNumberOfModes(n);
39 // writer->Update();
40 //}
41 
42 template <unsigned int VDimension>
43 void
44 PSMShapeEntropyFunction<VDimension>
45 ::ComputeCovarianceMatrix()
46 {
47  // NOTE: This code requires that indices be contiguous, i.e. it wont work if
48  // you start deleting particles.
49  const unsigned int num_samples = m_ShapeMatrix->cols();
50  const unsigned int num_dims = m_ShapeMatrix->rows();
51 
52  // Do we need to resize the covariance matrix?
53  if (m_PointsUpdate.rows() != num_dims || m_PointsUpdate.cols() != num_samples)
54  {
55  m_PointsUpdate.set_size(num_dims, num_samples);
56  }
57 
58  vnl_matrix_type points_minus_mean(num_dims, num_samples);
59  vnl_vector_type means(num_dims);
60 
61  // Compute the covariance matrix and the mean shape vector.
62  for (unsigned int j = 0; j < num_dims; j++)
63  {
64  double total = 0.0;
65  for (unsigned int i = 0; i < num_samples; i++)
66  {
67  total += m_ShapeMatrix->operator()(j, i);
68  }
69  means(j) = total/(double)num_samples;
70  }
71 
72 
73  for (unsigned int j = 0; j < num_dims; j++)
74  {
75  for (unsigned int i = 0; i < num_samples; i++)
76  {
77  points_minus_mean(j, i) = m_ShapeMatrix->operator()(j, i) - means(j);
78  }
79  }
80 
81  vnl_matrix_type A = points_minus_mean.transpose()
82  * points_minus_mean * (1.0/((double)(num_samples-1)));
83 
84  // Regularize A
85  for (unsigned int i = 0; i < num_samples; i++)
86  {
87  A(i, i) = A(i, i) + m_MinimumVariance;
88  }
89 
90  // Compute the eigenvalues and vectors and the point updates.
91  vnl_symmetric_eigensystem<double> symEigen(A);
92  m_PointsUpdate = points_minus_mean * ((symEigen.pinverse()).transpose());
93  m_MinimumEigenValue = symEigen.D(0, 0);
94 
95  m_CurrentEnergy = 0.0;
96  for (unsigned int i = 1; i < num_samples; i++)
97  {
98  if (symEigen.D(i, i) < m_MinimumEigenValue)
99  {
100  m_MinimumEigenValue = symEigen.D(i, i);
101  }
102  m_CurrentEnergy += log(symEigen.D(i,i));
103  }
104  // m_CurrentEnergy = 0.5*log(symEigen.determinant());
105  m_CurrentEnergy /= num_samples;
106 
107  // Record the variance for each PCA shape "parameter" (mode).
108  // Variance is the eigenvalue of the covariance matrix. Reverse
109  // order of values because we want them in decreasing order of
110  // magnitude.
111  if (m_ShapePCAVariances.size() < num_samples)
112  {
113  m_ShapePCAVariances.resize(num_samples);
114  }
115  for (int i = 0; i < (int)num_samples; i++)
116  {
117  int tmp = num_samples - i - 1;
118  m_ShapePCAVariances[i] = symEigen.D(tmp, tmp) - m_MinimumVariance;
119  }
120 }
121 
122 template <unsigned int VDimension>
125 ::Evaluate(unsigned int idx, unsigned int d, const ParticleSystemType * system,
126  double &maxdt, double &energy) const
127 {
128  // NOTE: This code requires that indices be contiguous, i.e. it
129  // won't work if you start deleting particles.
130  energy = m_CurrentEnergy;
131  maxdt = m_MinimumEigenValue;
132  const unsigned int DomainsPerShape = m_ShapeMatrix->GetDomainsPerShape();
133  const unsigned int PointsPerDomain = system->GetNumberOfParticles(d);
134 
135  VectorType gradE;
136  unsigned int k = ((d % DomainsPerShape) * PointsPerDomain * VDimension)
137  + (idx * VDimension);
138  for (unsigned int i = 0; i< VDimension; i++)
139  {
140  gradE[i] = m_PointsUpdate(k + i, d / DomainsPerShape);
141  }
142 
143 
144  return system->TransformVector(gradE,
145  system->GetInversePrefixTransform(d) *
146  system->GetInverseTransform(d));
147 }
148 
149 } // end namespace itk
150 #endif
const TransformType & GetInverseTransform(unsigned int i) const
unsigned long int GetNumberOfParticles(unsigned int d=0) const
const TransformType & GetInversePrefixTransform(unsigned int i) const
A facade class that manages interactions with a particle system.
VectorType TransformVector(const VectorType &, const TransformType &) const
virtual VectorType Evaluate(unsigned int, unsigned int, const ParticleSystemType *, double &, double &) const
vnl_vector_fixed< double, VDimension > VectorType