GMMReducer.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package MemoryX::GaussianMixtureHelpers
17 * @author Alexey Kozlov <kozlov@kit.edu>
18 * @copyright 2013 Alexey Kozlov
19 * @license http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22 
23 #include "GMMReducer.h"
24 
25 #include <cfloat>
26 
27 // Eigen
28 #include <Eigen/Eigenvalues>
29 
30 namespace memoryx
31 {
32  GaussianMixtureDistributionBasePtr GMMReducer::reduceByComponentCount(const GaussianMixtureDistributionBasePtr& fullGMM, int countComp)
33  {
34  GaussianMixtureDistributionPtr reducedGMM = GaussianMixtureDistributionPtr::dynamicCast(fullGMM->clone());
35 
36  if (!reducedGMM || countComp < 1)
37  {
39  }
40 
41  reducedGMM->normalize();
42 
43  const int FULL_GMM_SIZE = fullGMM->size();
44 
45  while (reducedGMM->size() > countComp)
46  {
47  float minCost = FLT_MAX;
48  int mergeIndexes = -1;
49 
50  for (int i = 0; i < reducedGMM->size(); ++i)
51  for (int j = i + 1; j < reducedGMM->size(); ++j)
52  {
53  const float cost = getMergingCost(reducedGMM, i, j);
54 
55  if (cost < minCost)
56  {
57  minCost = cost;
58  mergeIndexes = i * FULL_GMM_SIZE + j;
59  }
60  }
61 
62  if (mergeIndexes > 0)
63  {
64  mergeGMMComponents(reducedGMM, mergeIndexes / FULL_GMM_SIZE, mergeIndexes % FULL_GMM_SIZE);
65  }
66  }
67 
68  return reducedGMM;
69  }
70 
71  GaussianMixtureDistributionBasePtr GMMReducer::reduceByMaxAABB(const GaussianMixtureDistributionBasePtr& fullGMM, float maxSideLength)
72  {
73  return reduceByMaxDeviation(fullGMM, maxSideLength, eAABB);
74  }
75 
76  GaussianMixtureDistributionBasePtr GMMReducer::reduceByMaxOrientedBBox(const GaussianMixtureDistributionBasePtr& fullGMM, float maxSideLength)
77  {
78  return reduceByMaxDeviation(fullGMM, maxSideLength, eOrientedBBox);
79  }
80 
81  GaussianMixtureDistributionBasePtr GMMReducer::reduceByMaxEqualSphere(const GaussianMixtureDistributionBasePtr& fullGMM, float maxSphereRadius)
82  {
83  return reduceByMaxDeviation(fullGMM, maxSphereRadius, eEqualSphere);
84  }
85 
86  GaussianMixtureDistributionBasePtr GMMReducer::reduceByMaxDeviation(const GaussianMixtureDistributionBasePtr& fullGMM,
87  float maxDeviation, DeviationMeasure devMeasure)
88  {
89  GaussianMixtureDistributionPtr reducedGMM = GaussianMixtureDistributionPtr::dynamicCast(fullGMM->clone());
90 
91  if (!reducedGMM || devMeasure < 0)
92  {
94  }
95 
96  // calculate measure-specific variance values in advance to save computation in loop
97  float precalcDeviation = 0.f;
98 
99  switch (devMeasure)
100  {
101  case eAABB:
102  case eOrientedBBox:
103  precalcDeviation = maxDeviation * maxDeviation;
104  break;
105 
106  case eEqualSphere:
107  precalcDeviation = maxDeviation * maxDeviation * maxDeviation;
108  break;
109 
110  default:
111  precalcDeviation = 0.f;
112  }
113 
114  reducedGMM->normalize();
115 
116  bool merged = false;
117 
118  struct PairDistanceComparator
119  {
121  {
122  return (i.second < j.second);
123  }
124  };
125 
126  do
127  {
128  const int REDUCED_GMM_SIZE = reducedGMM->size();
129  GMMCompPairDistanceVector distVector;
130  distVector.reserve((REDUCED_GMM_SIZE - 1 * REDUCED_GMM_SIZE) / 2);
131  fillMergingCostVector(reducedGMM, distVector);
132 
133  // sort distVector
134  std::sort(distVector.begin(), distVector.end(), PairDistanceComparator::compare);
135 
136  // TODO change order? check devMeasure BEFORE calc distance -> should be faster
137  merged = false;
138 
139  for (GMMCompPairDistanceVector::const_iterator it = distVector.begin(); it != distVector.end(); ++it)
140  {
141  const int index1 = it->first / REDUCED_GMM_SIZE;
142  const int index2 = it->first % REDUCED_GMM_SIZE;
143  GaussianMixtureComponent mergedComp;
144  mergeGMMComponents(reducedGMM->getComponent(index1), reducedGMM->getComponent(index2), mergedComp);
145  bool doMerge = false;
146  Eigen::Matrix3f cov = NormalDistributionPtr::dynamicCast(mergedComp.gaussian)->toEigenCovariance();
147 
148  switch (devMeasure)
149  {
150  case eAABB:
151  {
152  doMerge = (cov(0, 0) < precalcDeviation &&
153  cov(1, 1) < precalcDeviation &&
154  cov(2, 2) < precalcDeviation);
155  break;
156  }
157 
158  case eOrientedBBox:
159  {
160  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> es(cov);
161  Eigen::Vector3f evals = es.eigenvalues();
162  doMerge = (evals(0) < precalcDeviation &&
163  evals(1) < precalcDeviation &&
164  evals(2) < precalcDeviation);
165  break;
166  }
167 
168  case eEqualSphere:
169  {
170  doMerge = sqrtf(cov.determinant()) < precalcDeviation;
171  break;
172  }
173 
174  default:
175  doMerge = false;
176  }
177 
178  if (doMerge)
179  {
180  std::cout << "Adding component: " << mergedComp.gaussian->output() << " (instead of " << index1 << " and " << index2 << ")" << std::endl;
181  replaceComponentsWithMerged(reducedGMM, index1, index2, mergedComp);
182  merged = true;
183  break;
184  }
185  }
186  }
187  while (merged);
188 
189  return reducedGMM;
190  }
191 
192  void GMMReducer::mergeGMMComponents(const GaussianMixtureComponent& comp1, const GaussianMixtureComponent& comp2, GaussianMixtureComponent& mergedComp)
193  {
194  NormalDistributionPtr gaussian1 = NormalDistributionPtr::dynamicCast(comp1.gaussian);
195  NormalDistributionPtr gaussian2 = NormalDistributionPtr::dynamicCast(comp2.gaussian);
196 
197  const Eigen::VectorXf x1 = gaussian1->toEigenMean();
198  const Eigen::VectorXf x2 = gaussian2->toEigenMean();
199  const Eigen::MatrixXf p1 = gaussian1->toEigenCovariance();
200  const Eigen::MatrixXf p2 = gaussian2->toEigenCovariance();
201 
202  const float w1 = comp1.weight;
203  const float w2 = comp2.weight;
204 
205  const float k = 1. / (w1 + w2);
206  const Eigen::VectorXf d = x1 - x2;
207 
208  const Eigen::VectorXf mean = k * (w1 * x1 + w2 * x2);
209  const Eigen::MatrixXf cov = k * (w1 * p1 + w2 * p2 + k * w1 * w2 * d * d.transpose());
210 
211  mergedComp.gaussian = new MultivariateNormalDistribution(mean, cov);
212  mergedComp.weight = w1 + w2;
213  }
214 
215  void GMMReducer::replaceComponentsWithMerged(GaussianMixtureDistributionPtr& gmm, int index1, int index2, const GaussianMixtureComponent& mergedComp)
216  {
217  gmm->setComponent(index1, mergedComp);
218  gmm->removeComponent(index2);
219  }
220 
222  {
223  GaussianMixtureComponent comp1 = gmm->getComponent(index1);
224  GaussianMixtureComponent comp2 = gmm->getComponent(index2);
225 
226  GaussianMixtureComponent mergedComp;
227  mergeGMMComponents(comp1, comp2, mergedComp);
228  replaceComponentsWithMerged(gmm, index1, index2, mergedComp);
229  }
230 
231  float GMMReducer::getMergingCost(const GaussianMixtureDistributionBasePtr& gmm, int c1, int c2)
232  {
233  return gmmDistance->getDistance(gmm->getComponent(c1), gmm->getComponent(c2));
234  }
235 
236  void GMMReducer::fillMergingCostVector(const GaussianMixtureDistributionBasePtr& gmm, GMMCompPairDistanceVector& costVec)
237  {
238  const int GMM_SIZE = gmm->size();
239 
240  for (int i = 0; i < GMM_SIZE - 1; ++i)
241  for (int j = i + 1; j < GMM_SIZE; ++j)
242  {
243  const float cost = getMergingCost(gmm, i, j);
244  const int index = i * GMM_SIZE + j;
245  costVec.push_back(GMMCompPairDistance(index, cost));
246  }
247  }
248 }
memoryx::eOrientedBBox
@ eOrientedBBox
Definition: GMMReducer.h:40
memoryx::GMMCompPairDistanceVector
std::vector< GMMCompPairDistance > GMMCompPairDistanceVector
Definition: GMMReducer.h:45
index
uint8_t index
Definition: EtherCATFrame.h:59
memoryx::GMMReducer::reduceByMaxAABB
virtual GaussianMixtureDistributionBasePtr reduceByMaxAABB(const GaussianMixtureDistributionBasePtr &fullGMM, float maxSideLength)
Definition: GMMReducer.cpp:71
memoryx::GMMCompPairDistance
std::pair< int, float > GMMCompPairDistance
Definition: GMMReducer.h:44
memoryx
VirtualRobot headers.
Definition: CommonPlacesTester.cpp:48
memoryx::GMMReducer::mergeGMMComponents
void mergeGMMComponents(const GaussianMixtureComponent &comp1, const GaussianMixtureComponent &comp2, GaussianMixtureComponent &mergedComp)
Definition: GMMReducer.cpp:192
memoryx::DeviationMeasure
DeviationMeasure
Definition: GMMReducer.h:37
memoryx::GMMReducer::fillMergingCostVector
virtual void fillMergingCostVector(const GaussianMixtureDistributionBasePtr &gmm, GMMCompPairDistanceVector &costVec)
Definition: GMMReducer.cpp:236
memoryx::GMMReducer::replaceComponentsWithMerged
void replaceComponentsWithMerged(GaussianMixtureDistributionPtr &gmm, int index1, int index2, const GaussianMixtureComponent &mergedComp)
Definition: GMMReducer.cpp:215
IceInternal::Handle
Definition: forward_declarations.h:8
armarx::mean
std::optional< float > mean(const boost::circular_buffer< NameValueMap > &buffer, const std::string &key)
Definition: KinematicUnitGuiPlugin.cpp:1615
memoryx::GMMReducer::reduceByMaxEqualSphere
virtual GaussianMixtureDistributionBasePtr reduceByMaxEqualSphere(const GaussianMixtureDistributionBasePtr &fullGMM, float maxSphereRadius)
Definition: GMMReducer.cpp:81
memoryx::eAABB
@ eAABB
Definition: GMMReducer.h:39
memoryx::GMMReducer::getMergingCost
virtual float getMergingCost(const GaussianMixtureDistributionBasePtr &gmm, int c1, int c2)
Definition: GMMReducer.cpp:231
GMMReducer.h
memoryx::GaussianMixtureDistributionPtr
IceInternal::Handle< GaussianMixtureDistribution > GaussianMixtureDistributionPtr
Definition: ProbabilityMeasures.h:293
memoryx::eEqualSphere
@ eEqualSphere
Definition: GMMReducer.h:41
armarx::detail::compare
int compare(const T &lhs, const T &rhs)
Definition: TreeWidgetBuilder.h:278
GfxTL::Matrix3f
MatrixXX< 3, 3, float > Matrix3f
Definition: MatrixXX.h:600
memoryx::GMMReducer::reduceByMaxOrientedBBox
virtual GaussianMixtureDistributionBasePtr reduceByMaxOrientedBBox(const GaussianMixtureDistributionBasePtr &fullGMM, float maxSideLength)
Definition: GMMReducer.cpp:76
memoryx::GMMReducer::reduceByComponentCount
virtual GaussianMixtureDistributionBasePtr reduceByComponentCount(const GaussianMixtureDistributionBasePtr &fullGMM, int countComp)
Definition: GMMReducer.cpp:32
memoryx::GMMReducer::gmmDistance
GMMDistancePtr gmmDistance
Definition: GMMReducer.h:77
memoryx::GMMReducer::reduceByMaxDeviation
virtual GaussianMixtureDistributionBasePtr reduceByMaxDeviation(const GaussianMixtureDistributionBasePtr &fullGMM, float maxDeviation, DeviationMeasure devMeasure)
Definition: GMMReducer.cpp:86
armarx::VariantType::MultivariateNormalDistribution
const armarx::VariantTypeId MultivariateNormalDistribution
Definition: ProbabilityMeasures.h:36