Skip to content

Commit c485101

Browse files
committed
implemented faster approximate observation model
1 parent a1b226a commit c485101

File tree

4 files changed

+328
-34
lines changed

4 files changed

+328
-34
lines changed

distribution_test.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
density = importdata('/tmp/distribution_test/evaluation.txt');
77

88
%%
9-
bin_count = 100;
9+
bin_count = 1000;
1010
bin_width = (max(samples) - min(samples)) / bin_count;
1111
approximate_density = hist(samples, bin_count) / (size(samples,1) * bin_width);
1212

include/fast_filtering/utils/helper_functions.hpp

+97-21
Original file line numberDiff line numberDiff line change
@@ -990,52 +990,128 @@ template <typename T> class LogSumExp
990990
class DiscreteSampler
991991
{
992992
public:
993-
template <typename T> DiscreteSampler(std::vector<T> log_likelihoods)
993+
template <typename T> DiscreteSampler(std::vector<T> log_prob)
994994
{
995995
fibo_.seed(RANDOM_SEED);
996996

997-
// compute the likelihoods and normalize them ------------------------------------------------------------------------------
998-
sorted_indices_ = ff::hf::SortDescend(log_likelihoods);
999-
double max = log_likelihoods[sorted_indices_[0]];
1000-
for(int i = 0; i < int(log_likelihoods.size()); i++)
1001-
log_likelihoods[i] -= max;
997+
// compute the prob and normalize them
998+
sorted_indices_ = ff::hf::SortDescend(log_prob);
999+
double max = log_prob[sorted_indices_[0]];
1000+
for(int i = 0; i < int(log_prob.size()); i++)
1001+
log_prob[i] -= max;
10021002

1003-
std::vector<double> likelihoods(log_likelihoods.size());
1003+
std::vector<double> prob(log_prob.size());
10041004
double sum = 0;
1005-
for(int i = 0; i < int(log_likelihoods.size()); i++)
1005+
for(int i = 0; i < int(log_prob.size()); i++)
10061006
{
1007-
likelihoods[i] = exp(log_likelihoods[i]);
1008-
sum += likelihoods[i];
1007+
prob[i] = exp(log_prob[i]);
1008+
sum += prob[i];
10091009
}
1010-
for(int i = 0; i < int(likelihoods.size()); i++)
1011-
likelihoods[i] /= sum;
1012-
1013-
// compute the cumulative likelihood ------------------------------------------------------------------
1014-
cum_likelihoods_.resize(log_likelihoods.size());
1015-
cum_likelihoods_[0] = likelihoods[sorted_indices_[0]];
1016-
for(int i = 1; i < int(log_likelihoods.size()); i++)
1017-
cum_likelihoods_[i] = cum_likelihoods_[i-1] + likelihoods[sorted_indices_[i]];
1010+
for(int i = 0; i < int(prob.size()); i++)
1011+
prob[i] /= sum;
1012+
1013+
// compute the cumulative probability
1014+
cumulative_prob_.resize(log_prob.size());
1015+
cumulative_prob_[0] = prob[sorted_indices_[0]];
1016+
for(int i = 1; i < int(log_prob.size()); i++)
1017+
cumulative_prob_[i] = cumulative_prob_[i-1] + prob[sorted_indices_[i]];
10181018
}
10191019

10201020
~DiscreteSampler() {}
10211021

10221022
int Sample()
10231023
{
1024-
double rand_number = fibo_();
1024+
double uniform_sample = fibo_();
10251025
int sample_index = 0;
1026-
while(rand_number > cum_likelihoods_[sample_index]) sample_index++;
1026+
while(uniform_sample > cumulative_prob_[sample_index]) sample_index++;
10271027

10281028
return sorted_indices_[sample_index];
10291029
}
10301030

1031+
1032+
1033+
int MapStandardGaussian(double gaussian_sample) const
1034+
{
1035+
// map from a gaussian to a uniform distribution
1036+
double uniform_sample = 0.5 *
1037+
(1.0 + std::erf(gaussian_sample / std::sqrt(2.0)));
1038+
int sample_index = 0;
1039+
while(uniform_sample > cumulative_prob_[sample_index]) sample_index++; //TODO: THIS COULD BE DONE IN LOG TIME
1040+
1041+
return sorted_indices_[sample_index];
1042+
}
1043+
10311044
private:
10321045
boost::lagged_fibonacci607 fibo_;
10331046
std::vector<int> sorted_indices_;
1034-
std::vector<double> cum_likelihoods_;
1047+
std::vector<double> cumulative_prob_;
10351048
};
10361049

10371050

10381051

1052+
// the above class should go away
1053+
class DiscreteDistribution
1054+
{
1055+
public:
1056+
template <typename T> DiscreteDistribution(std::vector<T> log_prob)
1057+
{
1058+
uniform_sampler_.seed(RANDOM_SEED);
1059+
1060+
// substract max to avoid numerical issues
1061+
double max = hf::bound_value(log_prob, true);
1062+
for(int i = 0; i < int(log_prob.size()); i++)
1063+
log_prob[i] -= max;
1064+
1065+
// compute probabilities
1066+
std::vector<double> prob(log_prob.size());
1067+
double sum = 0;
1068+
for(int i = 0; i < int(log_prob.size()); i++)
1069+
{
1070+
prob[i] = std::exp(log_prob[i]);
1071+
sum += prob[i];
1072+
}
1073+
for(int i = 0; i < int(prob.size()); i++)
1074+
prob[i] /= sum;
1075+
1076+
// compute the cumulative probability
1077+
cumulative_prob_.resize(prob.size());
1078+
cumulative_prob_[0] = prob[0];
1079+
for(size_t i = 1; i < prob.size(); i++)
1080+
cumulative_prob_[i] = cumulative_prob_[i-1] + prob[i];
1081+
}
1082+
1083+
~DiscreteDistribution() {}
1084+
1085+
int Sample()
1086+
{
1087+
return MapStandardUniform(uniform_sampler_());
1088+
}
1089+
1090+
int MapStandardGaussian(double gaussian_sample) const
1091+
{
1092+
double uniform_sample =
1093+
0.5 * (1.0 + std::erf(gaussian_sample / std::sqrt(2.0)));
1094+
return MapStandardUniform(uniform_sample);
1095+
}
1096+
1097+
int MapStandardUniform(double uniform_sample) const
1098+
{
1099+
std::vector<double>::const_iterator iterator =
1100+
std::lower_bound(cumulative_prob_.begin(),
1101+
cumulative_prob_.end(),
1102+
uniform_sample);
1103+
1104+
return iterator - cumulative_prob_.begin();
1105+
}
1106+
1107+
private:
1108+
boost::lagged_fibonacci607 uniform_sampler_;
1109+
std::vector<double> cumulative_prob_;
1110+
};
1111+
1112+
1113+
1114+
10391115

10401116

10411117

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
/*************************************************************************
2+
This software allows for filtering in high-dimensional observation and
3+
state spaces, as described in
4+
5+
M. Wuthrich, P. Pastor, M. Kalakrishnan, J. Bohg, and S. Schaal.
6+
Probabilistic Object Tracking using a Range Camera
7+
IEEE/RSJ Intl Conf on Intelligent Robots and Systems, 2013
8+
9+
In a publication based on this software pleace cite the above reference.
10+
11+
12+
Copyright (C) 2014 Manuel Wuthrich
13+
14+
This program is free software: you can redistribute it and/or modify
15+
it under the terms of the GNU General Public License as published by
16+
the Free Software Foundation, either version 3 of the License, or
17+
(at your option) any later version.
18+
19+
This program is distributed in the hope that it will be useful,
20+
but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
GNU General Public License for more details.
23+
24+
You should have received a copy of the GNU General Public License
25+
along with this program. If not, see <http://www.gnu.org/licenses/>.
26+
*************************************************************************/
27+
28+
#ifndef POSE_TRACKING_MODELS_OBSERVATION_MODELS_APPROXIMATE_KINECT_PIXEL_OBSERVATION_MODEL_HPP
29+
#define POSE_TRACKING_MODELS_OBSERVATION_MODELS_APPROXIMATE_KINECT_PIXEL_OBSERVATION_MODEL_HPP
30+
31+
#include <cmath>
32+
#include <tuple>
33+
34+
#include <Eigen/Dense>
35+
36+
#include <fast_filtering/distributions/interfaces/evaluation.hpp>
37+
#include <fast_filtering/distributions/exponential_distribution.hpp>
38+
#include <fast_filtering/distributions/uniform_distribution.hpp>
39+
#include <fast_filtering/distributions/truncated_gaussian.hpp>
40+
#include <fast_filtering/utils/helper_functions.hpp>
41+
42+
#include <pose_tracking/models/observation_models/kinect_pixel_observation_model.hpp>
43+
#include <pose_tracking/utils/rigid_body_renderer.hpp>
44+
#include <pose_tracking/utils/hash_mapping.hpp>
45+
46+
#include <boost/unordered_map.hpp>
47+
48+
namespace ff
49+
{
50+
51+
/**
52+
* \class KinectObservationModel
53+
*
54+
* \ingroup distributions
55+
* \ingroup observation_models
56+
*/
57+
template <typename State>
58+
class ApproximateKinectPixelObservationModel:
59+
public GaussianMap<double, Eigen::Matrix<double, 1, 1> >,
60+
public Evaluation<double, double>
61+
{
62+
public:
63+
typedef Eigen::Matrix<double, 1, 1> Noise;
64+
typedef double Scalar;
65+
typedef double Observation;
66+
67+
typedef boost::shared_ptr<RigidBodyRenderer> ObjectRendererPtr;
68+
69+
ApproximateKinectPixelObservationModel(
70+
const ObjectRendererPtr object_renderer,
71+
const Eigen::Matrix3d& camera_matrix,
72+
const size_t n_rows,
73+
const size_t n_cols,
74+
const Scalar sensor_failure_probability = 0.01,
75+
const Scalar object_model_sigma = 0.003,
76+
const Scalar sigma_factor = 0.00142478,
77+
const Scalar half_life_depth = 1.0,
78+
const Scalar max_depth = 6.0,
79+
const Scalar min_depth = 0.0,
80+
const Scalar approximation_depth = 1.5,
81+
const size_t depth_count = 10000,
82+
const size_t occlusion_count = 100)
83+
: object_renderer_(object_renderer),
84+
camera_matrix_(camera_matrix),
85+
n_rows_(n_rows),
86+
n_cols_(n_cols),
87+
predictions_(100), // the size of this vector reflects the number of different
88+
occluded_observation_model_(sensor_failure_probability,
89+
object_model_sigma,
90+
sigma_factor,
91+
half_life_depth,
92+
max_depth),
93+
visible_observation_model_(occluded_observation_model_),
94+
exponential_distribution_(-log(0.5)/half_life_depth, min_depth),
95+
object_model_noise_(0.0, object_model_sigma),
96+
sensor_failure_distribution_(min_depth, max_depth),
97+
sensor_failure_probability_(sensor_failure_probability),
98+
sigma_factor_(sigma_factor),
99+
max_depth_(max_depth),
100+
min_depth_(min_depth),
101+
approximation_depth_(approximation_depth),
102+
occlusion_step_(1.0 / double(occlusion_count - 1)),
103+
depth_step_((max_depth_ - min_depth_) / double(depth_count - 1))
104+
{
105+
for(size_t occlusion_index = 0; occlusion_index < occlusion_count; occlusion_index++)
106+
{
107+
std::vector<double> log_probs(depth_count);
108+
for(size_t depth_index = 0; depth_index < depth_count; depth_index++)
109+
{
110+
Condition(approximation_depth_,
111+
hf::Logit(double(occlusion_index) * occlusion_step_));
112+
log_probs[depth_index] = LogProbability(
113+
min_depth_ + double(depth_index) * depth_step_);
114+
}
115+
samplers_.push_back(hf::DiscreteDistribution(log_probs));
116+
}
117+
}
118+
119+
120+
virtual ~ApproximateKinectPixelObservationModel() {}
121+
122+
virtual Observation MapStandardGaussian(const Noise& sample) const
123+
{
124+
int depth_index = samplers_[occlusion_index_].MapStandardGaussian(sample(0));
125+
126+
return rendered_depth_ - approximation_depth_ + min_depth_
127+
+ depth_step_ * double(depth_index);
128+
}
129+
130+
virtual Scalar Probability(const Observation& observation) const
131+
{
132+
Scalar probability_given_occluded =
133+
occluded_observation_model_.Probability(observation);
134+
135+
Scalar probability_given_visible =
136+
visible_observation_model_.Probability(observation);
137+
138+
return probability_given_occluded * occlusion_probability_ +
139+
probability_given_visible * (1.0 - occlusion_probability_);
140+
}
141+
142+
virtual Scalar LogProbability(const Observation& observation) const
143+
{
144+
return std::log(Probability(observation));
145+
}
146+
147+
virtual void ResetCache()
148+
{
149+
predictions_.clear();
150+
}
151+
152+
virtual void Condition(const State& state,
153+
const Scalar& occlusion,
154+
size_t index)
155+
{
156+
157+
if (predictions_.find(state) == predictions_.end())
158+
{
159+
object_renderer_->state(state);
160+
object_renderer_->Render(camera_matrix_,
161+
n_rows_,
162+
n_cols_,
163+
predictions_[state]);
164+
}
165+
166+
Condition(predictions_[state][index], occlusion);
167+
}
168+
169+
virtual void Condition(const Scalar& rendered_depth,
170+
const Scalar& occlusion)
171+
{
172+
rendered_depth_ = rendered_depth;
173+
occlusion_probability_ = hf::Sigmoid(occlusion);
174+
occlusion_index_ = occlusion_probability_ / occlusion_step_;
175+
occluded_observation_model_.Condition(rendered_depth, true);
176+
visible_observation_model_.Condition(rendered_depth, false);
177+
}
178+
179+
private:
180+
ObjectRendererPtr object_renderer_;
181+
182+
Eigen::Matrix3d camera_matrix_;
183+
size_t n_rows_;
184+
size_t n_cols_;
185+
186+
/**
187+
* Harbors pairs of (intersect_indices, image_prediction).
188+
*/
189+
boost::unordered_map<Eigen::MatrixXd, std::vector<float> > predictions_;
190+
191+
KinectPixelObservationModel occluded_observation_model_;
192+
KinectPixelObservationModel visible_observation_model_;
193+
194+
Scalar rendered_depth_;
195+
Scalar occlusion_probability_;
196+
197+
TruncatedGaussian object_model_noise_;
198+
UniformDistribution uniform_distribution_;
199+
ExponentialDistribution exponential_distribution_;
200+
UniformDistribution sensor_failure_distribution_;
201+
202+
// parameters
203+
const Scalar sensor_failure_probability_, sigma_factor_,
204+
max_depth_, min_depth_, approximation_depth_;
205+
206+
207+
std::vector<hf::DiscreteDistribution> samplers_;
208+
209+
double occlusion_step_;
210+
double depth_step_;
211+
int occlusion_index_;
212+
};
213+
214+
}
215+
216+
217+
218+
#endif

0 commit comments

Comments
 (0)