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
30namespace 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 {
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,
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
uint8_t index
virtual GaussianMixtureDistributionBasePtr reduceByComponentCount(const GaussianMixtureDistributionBasePtr &fullGMM, int countComp)
virtual GaussianMixtureDistributionBasePtr reduceByMaxAABB(const GaussianMixtureDistributionBasePtr &fullGMM, float maxSideLength)
GMMDistancePtr gmmDistance
Definition GMMReducer.h:85
virtual GaussianMixtureDistributionBasePtr reduceByMaxDeviation(const GaussianMixtureDistributionBasePtr &fullGMM, float maxDeviation, DeviationMeasure devMeasure)
void replaceComponentsWithMerged(GaussianMixtureDistributionPtr &gmm, int index1, int index2, const GaussianMixtureComponent &mergedComp)
virtual void fillMergingCostVector(const GaussianMixtureDistributionBasePtr &gmm, GMMCompPairDistanceVector &costVec)
virtual GaussianMixtureDistributionBasePtr reduceByMaxEqualSphere(const GaussianMixtureDistributionBasePtr &fullGMM, float maxSphereRadius)
virtual float getMergingCost(const GaussianMixtureDistributionBasePtr &gmm, int c1, int c2)
virtual GaussianMixtureDistributionBasePtr reduceByMaxOrientedBBox(const GaussianMixtureDistributionBasePtr &fullGMM, float maxSideLength)
void mergeGMMComponents(const GaussianMixtureComponent &comp1, const GaussianMixtureComponent &comp2, GaussianMixtureComponent &mergedComp)
The MultivariateNormalDistribution class.
VirtualRobot headers.
IceInternal::Handle< NormalDistribution > NormalDistributionPtr
IceInternal::Handle< GaussianMixtureDistribution > GaussianMixtureDistributionPtr
std::vector< GMMCompPairDistance > GMMCompPairDistanceVector
Definition GMMReducer.h:45
DeviationMeasure
Definition GMMReducer.h:38
@ eOrientedBBox
Definition GMMReducer.h:40
@ eEqualSphere
Definition GMMReducer.h:41
std::pair< int, float > GMMCompPairDistance
Definition GMMReducer.h:44