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
33  GMMReducer::reduceByComponentCount(const GaussianMixtureDistributionBasePtr& fullGMM,
34  int countComp)
35  {
37  GaussianMixtureDistributionPtr::dynamicCast(fullGMM->clone());
38 
39  if (!reducedGMM || countComp < 1)
40  {
42  }
43 
44  reducedGMM->normalize();
45 
46  const int FULL_GMM_SIZE = fullGMM->size();
47 
48  while (reducedGMM->size() > countComp)
49  {
50  float minCost = FLT_MAX;
51  int mergeIndexes = -1;
52 
53  for (int i = 0; i < reducedGMM->size(); ++i)
54  for (int j = i + 1; j < reducedGMM->size(); ++j)
55  {
56  const float cost = getMergingCost(reducedGMM, i, j);
57 
58  if (cost < minCost)
59  {
60  minCost = cost;
61  mergeIndexes = i * FULL_GMM_SIZE + j;
62  }
63  }
64 
65  if (mergeIndexes > 0)
66  {
68  reducedGMM, mergeIndexes / FULL_GMM_SIZE, mergeIndexes % FULL_GMM_SIZE);
69  }
70  }
71 
72  return reducedGMM;
73  }
74 
75  GaussianMixtureDistributionBasePtr
76  GMMReducer::reduceByMaxAABB(const GaussianMixtureDistributionBasePtr& fullGMM,
77  float maxSideLength)
78  {
79  return reduceByMaxDeviation(fullGMM, maxSideLength, eAABB);
80  }
81 
82  GaussianMixtureDistributionBasePtr
83  GMMReducer::reduceByMaxOrientedBBox(const GaussianMixtureDistributionBasePtr& fullGMM,
84  float maxSideLength)
85  {
86  return reduceByMaxDeviation(fullGMM, maxSideLength, eOrientedBBox);
87  }
88 
89  GaussianMixtureDistributionBasePtr
90  GMMReducer::reduceByMaxEqualSphere(const GaussianMixtureDistributionBasePtr& fullGMM,
91  float maxSphereRadius)
92  {
93  return reduceByMaxDeviation(fullGMM, maxSphereRadius, eEqualSphere);
94  }
95 
96  GaussianMixtureDistributionBasePtr
97  GMMReducer::reduceByMaxDeviation(const GaussianMixtureDistributionBasePtr& fullGMM,
98  float maxDeviation,
99  DeviationMeasure devMeasure)
100  {
101  GaussianMixtureDistributionPtr reducedGMM =
102  GaussianMixtureDistributionPtr::dynamicCast(fullGMM->clone());
103 
104  if (!reducedGMM || devMeasure < 0)
105  {
107  }
108 
109  // calculate measure-specific variance values in advance to save computation in loop
110  float precalcDeviation = 0.f;
111 
112  switch (devMeasure)
113  {
114  case eAABB:
115  case eOrientedBBox:
116  precalcDeviation = maxDeviation * maxDeviation;
117  break;
118 
119  case eEqualSphere:
120  precalcDeviation = maxDeviation * maxDeviation * maxDeviation;
121  break;
122 
123  default:
124  precalcDeviation = 0.f;
125  }
126 
127  reducedGMM->normalize();
128 
129  bool merged = false;
130 
131  struct PairDistanceComparator
132  {
133  static bool
135  {
136  return (i.second < j.second);
137  }
138  };
139 
140  do
141  {
142  const int REDUCED_GMM_SIZE = reducedGMM->size();
143  GMMCompPairDistanceVector distVector;
144  distVector.reserve((REDUCED_GMM_SIZE - 1 * REDUCED_GMM_SIZE) / 2);
145  fillMergingCostVector(reducedGMM, distVector);
146 
147  // sort distVector
148  std::sort(distVector.begin(), distVector.end(), PairDistanceComparator::compare);
149 
150  // TODO change order? check devMeasure BEFORE calc distance -> should be faster
151  merged = false;
152 
153  for (GMMCompPairDistanceVector::const_iterator it = distVector.begin();
154  it != distVector.end();
155  ++it)
156  {
157  const int index1 = it->first / REDUCED_GMM_SIZE;
158  const int index2 = it->first % REDUCED_GMM_SIZE;
159  GaussianMixtureComponent mergedComp;
161  reducedGMM->getComponent(index1), reducedGMM->getComponent(index2), mergedComp);
162  bool doMerge = false;
163  Eigen::Matrix3f cov =
164  NormalDistributionPtr::dynamicCast(mergedComp.gaussian)->toEigenCovariance();
165 
166  switch (devMeasure)
167  {
168  case eAABB:
169  {
170  doMerge = (cov(0, 0) < precalcDeviation && cov(1, 1) < precalcDeviation &&
171  cov(2, 2) < precalcDeviation);
172  break;
173  }
174 
175  case eOrientedBBox:
176  {
177  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> es(cov);
178  Eigen::Vector3f evals = es.eigenvalues();
179  doMerge = (evals(0) < precalcDeviation && evals(1) < precalcDeviation &&
180  evals(2) < precalcDeviation);
181  break;
182  }
183 
184  case eEqualSphere:
185  {
186  doMerge = sqrtf(cov.determinant()) < precalcDeviation;
187  break;
188  }
189 
190  default:
191  doMerge = false;
192  }
193 
194  if (doMerge)
195  {
196  std::cout << "Adding component: " << mergedComp.gaussian->output()
197  << " (instead of " << index1 << " and " << index2 << ")" << std::endl;
198  replaceComponentsWithMerged(reducedGMM, index1, index2, mergedComp);
199  merged = true;
200  break;
201  }
202  }
203  } while (merged);
204 
205  return reducedGMM;
206  }
207 
208  void
209  GMMReducer::mergeGMMComponents(const GaussianMixtureComponent& comp1,
210  const GaussianMixtureComponent& comp2,
211  GaussianMixtureComponent& mergedComp)
212  {
213  NormalDistributionPtr gaussian1 = NormalDistributionPtr::dynamicCast(comp1.gaussian);
214  NormalDistributionPtr gaussian2 = NormalDistributionPtr::dynamicCast(comp2.gaussian);
215 
216  const Eigen::VectorXf x1 = gaussian1->toEigenMean();
217  const Eigen::VectorXf x2 = gaussian2->toEigenMean();
218  const Eigen::MatrixXf p1 = gaussian1->toEigenCovariance();
219  const Eigen::MatrixXf p2 = gaussian2->toEigenCovariance();
220 
221  const float w1 = comp1.weight;
222  const float w2 = comp2.weight;
223 
224  const float k = 1. / (w1 + w2);
225  const Eigen::VectorXf d = x1 - x2;
226 
227  const Eigen::VectorXf mean = k * (w1 * x1 + w2 * x2);
228  const Eigen::MatrixXf cov = k * (w1 * p1 + w2 * p2 + k * w1 * w2 * d * d.transpose());
229 
230  mergedComp.gaussian = new MultivariateNormalDistribution(mean, cov);
231  mergedComp.weight = w1 + w2;
232  }
233 
234  void
236  int index1,
237  int index2,
238  const GaussianMixtureComponent& mergedComp)
239  {
240  gmm->setComponent(index1, mergedComp);
241  gmm->removeComponent(index2);
242  }
243 
244  void
246  {
247  GaussianMixtureComponent comp1 = gmm->getComponent(index1);
248  GaussianMixtureComponent comp2 = gmm->getComponent(index2);
249 
250  GaussianMixtureComponent mergedComp;
251  mergeGMMComponents(comp1, comp2, mergedComp);
252  replaceComponentsWithMerged(gmm, index1, index2, mergedComp);
253  }
254 
255  float
256  GMMReducer::getMergingCost(const GaussianMixtureDistributionBasePtr& gmm, int c1, int c2)
257  {
258  return gmmDistance->getDistance(gmm->getComponent(c1), gmm->getComponent(c2));
259  }
260 
261  void
262  GMMReducer::fillMergingCostVector(const GaussianMixtureDistributionBasePtr& gmm,
263  GMMCompPairDistanceVector& costVec)
264  {
265  const int GMM_SIZE = gmm->size();
266 
267  for (int i = 0; i < GMM_SIZE - 1; ++i)
268  for (int j = i + 1; j < GMM_SIZE; ++j)
269  {
270  const float cost = getMergingCost(gmm, i, j);
271  const int index = i * GMM_SIZE + j;
272  costVec.push_back(GMMCompPairDistance(index, cost));
273  }
274  }
275 } // namespace memoryx
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:76
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:209
memoryx::DeviationMeasure
DeviationMeasure
Definition: GMMReducer.h:37
memoryx::GMMReducer::fillMergingCostVector
virtual void fillMergingCostVector(const GaussianMixtureDistributionBasePtr &gmm, GMMCompPairDistanceVector &costVec)
Definition: GMMReducer.cpp:262
memoryx::GMMReducer::replaceComponentsWithMerged
void replaceComponentsWithMerged(GaussianMixtureDistributionPtr &gmm, int index1, int index2, const GaussianMixtureComponent &mergedComp)
Definition: GMMReducer.cpp:235
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:1620
memoryx::GMMReducer::reduceByMaxEqualSphere
virtual GaussianMixtureDistributionBasePtr reduceByMaxEqualSphere(const GaussianMixtureDistributionBasePtr &fullGMM, float maxSphereRadius)
Definition: GMMReducer.cpp:90
memoryx::eAABB
@ eAABB
Definition: GMMReducer.h:39
memoryx::GMMReducer::getMergingCost
virtual float getMergingCost(const GaussianMixtureDistributionBasePtr &gmm, int c1, int c2)
Definition: GMMReducer.cpp:256
GMMReducer.h
memoryx::GaussianMixtureDistributionPtr
IceInternal::Handle< GaussianMixtureDistribution > GaussianMixtureDistributionPtr
Definition: ProbabilityMeasures.h:356
memoryx::eEqualSphere
@ eEqualSphere
Definition: GMMReducer.h:41
armarx::detail::compare
int compare(const T &lhs, const T &rhs)
Definition: TreeWidgetBuilder.h:321
memoryx::GMMReducer::reduceByMaxOrientedBBox
virtual GaussianMixtureDistributionBasePtr reduceByMaxOrientedBBox(const GaussianMixtureDistributionBasePtr &fullGMM, float maxSideLength)
Definition: GMMReducer.cpp:83
memoryx::GMMReducer::reduceByComponentCount
virtual GaussianMixtureDistributionBasePtr reduceByComponentCount(const GaussianMixtureDistributionBasePtr &fullGMM, int countComp)
Definition: GMMReducer.cpp:33
GfxTL::Matrix3f
MatrixXX< 3, 3, float > Matrix3f
Definition: MatrixXX.h:649
memoryx::GMMReducer::gmmDistance
GMMDistancePtr gmmDistance
Definition: GMMReducer.h:85
memoryx::GMMReducer::reduceByMaxDeviation
virtual GaussianMixtureDistributionBasePtr reduceByMaxDeviation(const GaussianMixtureDistributionBasePtr &fullGMM, float maxDeviation, DeviationMeasure devMeasure)
Definition: GMMReducer.cpp:97
armarx::VariantType::MultivariateNormalDistribution
const armarx::VariantTypeId MultivariateNormalDistribution
Definition: ProbabilityMeasures.h:40