ANIMA  4.0
animaVMFDistribution.hxx
Go to the documentation of this file.
1 #pragma once
2 #include <cmath>
3 
4 #include "animaVMFDistribution.h"
7 
8 #include <vnl/vnl_matrix.h>
9 
10 #include <itkMacro.h>
11 
12 namespace anima
13 {
14 
15 template <class VectorType, class ScalarType> double ComputeVMFPdf(const VectorType &v, const VectorType &meanDirection, const ScalarType &kappa)
16 {
17  if (std::abs(anima::ComputeNorm(meanDirection) - 1.0) > 1.0e-6 || std::abs(anima::ComputeNorm(v) - 1.0) > 1.0e-6)
18  {
19  std::cout << "Norm of mean direction: " << anima::ComputeNorm(meanDirection) << std::endl;
20  std::cout << "Norm of evaluated direction: " << anima::ComputeNorm(v) << std::endl;
21  throw itk::ExceptionObject(__FILE__, __LINE__,"Von Mises & Fisher distribution requires unitary vectors.",ITK_LOCATION);
22  }
23 
24  double resVal;
25 
26  if (kappa < 1e-4)
27  {
28  resVal = std::exp(kappa * anima::ComputeScalarProduct(meanDirection, v)) / (4.0 * M_PI);
29  }
30  else
31  {
32  double tmpVal = anima::ComputeScalarProduct(meanDirection, v) - 1.0;
33  tmpVal *= kappa;
34 
35  resVal = std::exp(tmpVal);
36  resVal *= kappa;
37  tmpVal = 1.0 - std::exp(-2.0 * kappa);
38  resVal /= (2.0 * M_PI * tmpVal);
39  }
40 
41  return resVal;
42 }
43 
44 template <class ScalarType, unsigned int Dimension>
45 double
46 VMFDistance(const itk::Point <ScalarType, Dimension> &muFirst, const double &kappaFirst,
47  const itk::Point <ScalarType, Dimension> &muSec, const double &kappaSec)
48 {
49  double dist = 0;
50 
51  double scalarProduct = 0;
52  for (unsigned int i = 0;i < Dimension;++i)
53  scalarProduct += muFirst[i] * muSec[i];
54 
55  if (scalarProduct < -1.0)
56  scalarProduct = -1.0;
57 
58  if (scalarProduct > 1.0)
59  scalarProduct = 1.0;
60 
61  double acosValue = std::acos(scalarProduct);
62 
63  dist = anima::safe_log(std::max(1.0e-16,kappaSec) / std::max(1.0e-16,kappaFirst));
64  dist *= dist;
65  dist += acosValue * acosValue;
66 
67  return sqrt(dist);
68 }
69 
70 template <class ScalarType>
71 double
72 GetVonMisesConcentrationMLE(const ScalarType rbar)
73 {
74  // This function performs maximum-likelihood estimation of the concentration parameter for the 2D von Mises distribution. Given \theta_1, ..., \theta_n n i.i.d. angles following the same von Mises distribution with mean \mu and concentration parameter \kappa, rbar is expected to be the square root of the sum of the squared average cosine of the angles and the squared average sine of the angles.
75 
76  double kappa = 0.0;
77 
78  if (rbar < 0.44639)
79  {
80  // Approximation given by Eq. (5.4.8) p. 123. Provides two figure accuracy for rbar < 0.45
81  double rbarSq = rbar * rbar;
82  kappa = rbar * (12.0 + 6.0 * rbarSq + 5.0 * rbarSq * rbarSq) / 6.0;
83  } // Next, linear interpolation between tabulated values reported in Appendix 2.2 p. 297
84  else if (rbar < 0.48070)
85  kappa = 0.1 * (rbar - 0.44639) / (0.48070 - 0.44639) + 1.0;
86  else if (rbar < 0.51278)
87  kappa = 0.1 * (rbar - 0.48070) / (0.51278 - 0.48070) + 1.1;
88  else if (rbar < 0.54267)
89  kappa = 0.1 * (rbar - 0.51278) / (0.54267 - 0.51278) + 1.2;
90  else if (rbar < 0.57042)
91  kappa = 0.1 * (rbar - 0.54267) / (0.57042 - 0.54267) + 1.3;
92  else if (rbar < 0.59613)
93  kappa = 0.1 * (rbar - 0.57042) / (0.59613 - 0.57042) + 1.4;
94  else if (rbar < 0.61990)
95  kappa = 0.1 * (rbar - 0.59613) / (0.61990 - 0.59613) + 1.5;
96  else if (rbar < 0.64183)
97  kappa = 0.1 * (rbar - 0.61990) / (0.64183 - 0.61990) + 1.6;
98  else if (rbar < 0.66204)
99  kappa = 0.1 * (rbar - 0.64183) / (0.66204 - 0.64183) + 1.7;
100  else if (rbar < 0.68065)
101  kappa = 0.1 * (rbar - 0.66204) / (0.68065 - 0.66204) + 1.8;
102  else if (rbar < 0.69777)
103  kappa = 0.1 * (rbar - 0.68065) / (0.69777 - 0.68065) + 1.9;
104  else if (rbar < 0.71353)
105  kappa = 0.1 * (rbar - 0.69777) / (0.71353 - 0.69777) + 2.0;
106  else if (rbar < 0.72803)
107  kappa = 0.1 * (rbar - 0.71353) / (0.72803 - 0.71353) + 2.1;
108  else if (rbar < 0.74138)
109  kappa = 0.1 * (rbar - 0.72803) / (0.74138 - 0.72803) + 2.2;
110  else if (rbar < 0.75367)
111  kappa = 0.1 * (rbar - 0.74138) / (0.75367 - 0.74138) + 2.3;
112  else if (rbar < 0.76500)
113  kappa = 0.1 * (rbar - 0.75367) / (0.76500 - 0.75367) + 2.4;
114  else if (rbar < 0.77545)
115  kappa = 0.1 * (rbar - 0.76500) / (0.77545 - 0.76500) + 2.5;
116  else if (rbar < 0.78511)
117  kappa = 0.1 * (rbar - 0.77545) / (0.78511 - 0.77545) + 2.6;
118  else if (rbar < 0.79404)
119  kappa = 0.1 * (rbar - 0.78511) / (0.79404 - 0.78511) + 2.7;
120  else if (rbar < 0.80231)
121  kappa = 0.1 * (rbar - 0.79404) / (0.80231 - 0.79404) + 2.8;
122  else
123  {
124  // Approximation given by Eq. (5.4.10) p. 123. Provides three figure accuracy for rbar > 0.8
125  double irbar = 1.0 - rbar;
126  double irbarSq = irbar * irbar;
127  kappa = 1.0 / (2.0 * irbar - irbarSq - irbar * irbarSq);
128  }
129 
130  return kappa;
131 }
132 
133 } // end of namespace anima
double GetVonMisesConcentrationMLE(const ScalarType rbar)
Maximum likelihood estimation of the concentration parameter of the 2D von Mises distribution accordi...
double ComputeNorm(const VectorType &v)
double VMFDistance(const itk::Point< ScalarType, Dimension > &muFirst, const double &kappaFirst, const itk::Point< ScalarType, Dimension > &muSec, const double &kappaSec)
double ComputeScalarProduct(const VectorType &v1, const VectorType &v2, const unsigned int NDimension)
double safe_log(const ScalarType x)
double ComputeVMFPdf(const VectorType &v, const VectorType &meanDirection, const ScalarType &kappa)