ed_sensor_integration
fitter.cpp
Go to the documentation of this file.
1 // Generic
2 #include <limits>
3 
4 // Logging
5 #include <ros/console.h>
6 
7 #include "ed/kinect/fitter.h"
8 #include <ed/entity.h>
9 #include <ed/world_model.h>
10 #include <ed/update_request.h>
11 #include <ed/logging.h>
12 #include <geolib/Shape.h>
13 
14 // Image capture
15 #include <rgbd/image.h>
17 #include <rgbd/view.h>
18 
19 // Visualization
20 #include <opencv2/highgui/highgui.hpp>
21 
22 // 2D model creation
23 #include "ed/kinect/mesh_tools.h"
24 
25 // Communication
26 #include <ed_sensor_integration_msgs/ImageBinary.h>
27 
28 #include <sstream>
29 
30 
31 const double ERROR_THRESHOLD = 1e5;
32 
33 
34 struct YawRange
35 {
36  double min, max;
37 };
38 
39 // ----------------------------------------------------------------------------------------------------
40 
41 YawRange computeYawRange(const geo::Pose3D& sensor_pose_xya, const geo::Pose3D& expected_entity_pose, const double& max_yaw_change)
42 {
43  geo::Pose3D expected_pose_SENSOR = sensor_pose_xya.inverse() * expected_entity_pose;
44  double expected_yaw_SENSOR;
45  {
46  tf::Matrix3x3 m;
47  geo::convert(expected_pose_SENSOR.R, m);
48  double roll, pitch;
49  m.getRPY(roll, pitch, expected_yaw_SENSOR);
50  }
51 
52  double min_yaw = expected_yaw_SENSOR - max_yaw_change;
53  double max_yaw = expected_yaw_SENSOR + max_yaw_change;
54  return {min_yaw, max_yaw};
55 }
56 
57 // ----------------------------------------------------------------------------------------------------
58 
60 {
61  // ToDo: make member method? This doesn't make any sense as a separate method
62  // since you need to know the internals of a Shape2D
65 
66  for(uint i = 0; i < shape2d.size(); ++i)
67  {
68  const std::vector<geo::Vec2>& contour = shape2d[i];
69  for(uint j = 0; j < contour.size(); ++j)
70  {
71  const geo::Vec2& p = contour[j];
72  shape_min.x = std::min(shape_min.x, p.x);
73  shape_min.y = std::min(shape_min.y, p.y);
74  shape_max.x = std::max(shape_max.x, p.x);
75  shape_max.y = std::max(shape_max.y, p.y);
76  }
77  }
78 
79  return 0.5 * (shape_min + shape_max);
80 }
81 
82 // ----------------------------------------------------------------------------------------------------
83 
84 Shape2D transformShape2D(const Shape2D& original_shape, const geo::Vec2& transformation)
85 {
86  Shape2D shape2d_transformed = original_shape;
87  for(uint i = 0; i < shape2d_transformed.size(); ++i)
88  {
89  std::vector<geo::Vec2>& contour_transformed = shape2d_transformed[i];
90  for(uint j = 0; j < contour_transformed.size(); ++j)
91  contour_transformed[j] -= transformation;
92  }
93  return shape2d_transformed;
94 }
95 
96 // ----------------------------------------------------------------------------------------------------
97 
98 // Decomposes 'pose' into a (X, Y, YAW) and (Z, ROLL, PITCH) component
99 void decomposePose(const geo::Pose3D& pose, geo::Pose3D& pose_xya, geo::Pose3D& pose_zrp)
100 {
101  tf::Matrix3x3 m;
102  geo::convert(pose.R, m);
103 
104  double roll, pitch, yaw;
105  m.getRPY(roll, pitch, yaw);
106 
107  pose_xya.R.setRPY(0, 0, yaw);
108  pose_xya.t = geo::Vec3(pose.t.x, pose.t.y, 0);
109 
110  pose_zrp = pose_xya.inverse() * pose;
111 }
112 
113 // ----------------------------------------------------------------------------------------------------
114 
115 // Convert a 3D transform with only a x, y and yaw component to a 2D transform
117 {
118  return geo::Transform2(geo::Mat2(pose.R.xx, pose.R.xy, pose.R.yx, pose.R.yy), geo::Vec2(pose.t.x, pose.t.y));
119 }
120 
121 // ----------------------------------------------------------------------------------------------------
122 
124 {
125 public:
126 
128 
130 
131  void update(const geo::Transform2& new_pose, const double& new_error)
132  {
133  pose = new_pose;
134  error = new_error;
135  }
136 
137  double getError(){return error;}
139 
140 private:
142  double error;
143 };
144 
145 // ----------------------------------------------------------------------------------------------------
146 
148 {
149 public:
150 
151  Candidate(std::shared_ptr<BeamModel> beam_model_ptr) : beam_model_ptr_(beam_model_ptr)
152  {
153  test_ranges.resize(beam_model_ptr_->num_beams(), 0.0);
154  }
155  void initialize(const uint i_beam, const double yaw)
156  {
157  beam_index = i_beam;
158  beam_length = beam_model_ptr_->rays()[i_beam].length();
159  beam_direction = beam_model_ptr_->rays()[i_beam] / beam_length;
160  pose.setRotation(yaw);
161  pose.setOrigin(beam_direction * 10); // JL: why this factor 10?
163  }
164 
166 
167  // ToDo: how can we make this private? Use smart pointers as well?
168  // It's not desirable to make the beam model aware of this datastructure
170  double beam_length;
174 
175 private:
177 
178 };
179 
180 // ----------------------------------------------------------------------------------------------------
181 
182 double computeFittingError(const std::vector<double>& test_ranges, const std::vector<double>& sensor_ranges)
183 {
184  int n = 0;
185  double total_error = 0;
186  for(unsigned int i = 0; i < test_ranges.size(); ++i)
187  {
188  double ds = sensor_ranges[i];
189  double dm = test_ranges[i];
190 
191  if (ds <= 0)
192  continue;
193 
194  ++n;
195 
196  if (dm <= 0)
197  {
198  total_error += 0.1;
199  continue;
200  }
201 
202  double diff = std::abs(ds - dm);
203  if (diff < 0.1)
204  total_error += diff;
205  else
206  {
207  if (ds > dm)
208  total_error += 1;
209  else
210  total_error += 0.1;
211  }
212  }
213 
214  double error = total_error / n;
215  return error;
216 }
217 
218 // ----------------------------------------------------------------------------------------------------
219 
220 geo::Pose3D computeFittedPose(const geo::Transform2& pose_sensor, ed::EntityConstPtr entity, const geo::Pose3D& sensor_pose_xya)
221 {
222  geo::Pose3D pose_3d;
223  pose_3d.t = geo::Vec3(pose_sensor.t.x, pose_sensor.t.y, entity->pose().t.z);
224  pose_3d.R = geo::Mat3::identity();
225  pose_3d.R.xx = pose_sensor.R.xx;
226  pose_3d.R.xy = pose_sensor.R.xy;
227  pose_3d.R.yx = pose_sensor.R.yx;
228  pose_3d.R.yy = pose_sensor.R.yy;
229 
230  return sensor_pose_xya * pose_3d;
231 }
232 
233 // ----------------------------------------------------------------------------------------------------
234 
236 {
237  configured_ = false;
238 }
239 
240 // ----------------------------------------------------------------------------------------------------
241 
242 Fitter::Fitter(unsigned int nr_data_points, float fx) :
243  nr_data_points_(nr_data_points)
244 {
245  double w = 2 * nr_data_points / fx;
246  beam_model_.initialize(w, nr_data_points);
247  configured_ = true;
248 }
249 
250 // ----------------------------------------------------------------------------------------------------
251 
253 {
254 }
255 
256 // ----------------------------------------------------------------------------------------------------
257 
258 bool Fitter::estimateEntityPose(const FitterData& data, const ed::WorldModel& world, const ed::UUID& id,
259  const geo::Pose3D& expected_pose, geo::Pose3D& fitted_pose, double max_yaw_change) const
260 {
261  try
262  {
263  return estimateEntityPoseImp(data, world, id, expected_pose, fitted_pose, max_yaw_change);
264  }
265  catch (const FitterError& error)
266  {
267  ROS_ERROR_STREAM("Fitter error: " << error.what());
268  return false;
269  }
270 }
271 
272 // ----------------------------------------------------------------------------------------------------
273 
274 bool Fitter::estimateEntityPoseImp(const FitterData& data, const ed::WorldModel& world, const ed::UUID& id,
275  const geo::Pose3D& expected_pose, geo::Pose3D& fitted_pose, double max_yaw_change) const
276 {
277  const EstimationInputData estimation_input_data = preProcessInputData(world, id, expected_pose, data);
278 
279  // -------------------------------------
280  // Compute yaw range
281  YawRange yaw_range = computeYawRange(data.sensor_pose_xya, expected_pose, max_yaw_change);
282 
283  // -------------------------------------
284  // Fit
285  std::unique_ptr<OptimalFit> current_optimum = findOptimum(estimation_input_data, yaw_range);
286 
287  double error_threshold = ERROR_THRESHOLD;
288  if (current_optimum->getError() > error_threshold)
289  {
290  std::ostringstream errormsg;
291  errormsg << "Error of best fit [" << current_optimum->getError() << "] exceeds threshold [" << error_threshold << "]";
292  throw FitterError(errormsg.str());
293  }
294 
295  // Correct for shape transformation
296  geo::Transform2 best_pose_SENSOR = current_optimum->getPose();
297  best_pose_SENSOR.t += best_pose_SENSOR.R * -estimation_input_data.shape_center;
298 
299  // Convert to 3D Pose
300  fitted_pose = computeFittedPose(best_pose_SENSOR, estimation_input_data.entity, data.sensor_pose_xya);
301 
302  return true;
303 }
304 
305 // ----------------------------------------------------------------------------------------------------
306 
307 EstimationInputData Fitter::preProcessInputData(const ed::WorldModel& world, const ed::UUID& id, const geo::Pose3D& expected_pose, const FitterData& data) const
308 {
309  EstimationInputData result;
310 
311  // Get entity for which to fit the pose
312  result.entity = world.getEntity(id);
313 
314  // -------------------------------------
315  // Get 2D contour
316  const Shape2D& shape2d = get2DShape(result.entity);
317 
318  // -------------------------------------
319  // Determine center of the shape
320  result.shape_center = computeShapeCenter(shape2d);
321 
322  // -------------------------------------
323  // Transform shape2d such that origin is in the center
324  result.shape2d_transformed = transformShape2D(shape2d, result.shape_center);
325 
326  // -------------------------------------
327  // Render world model objects
329  std::vector<int> dummy_identifiers(nr_data_points_, -1);
330  renderWorldModel2D(world, data.sensor_pose_xya, id, result.model_ranges, dummy_identifiers);
331 
332  // -------------------------------------
333  // Calculate the beam which shoots through the expected position of the entity
334  geo::Vec3 expected_pos_sensor = data.sensor_pose_xya.inverse() * expected_pose.t;
335  result.expected_center_beam = beam_model_.CalculateBeam(expected_pos_sensor.x, expected_pos_sensor.y);
336 
337  // ----------------------------------------------------
338  // Check that we can see the shape in its expected pose
339  checkExpectedBeamThroughEntity(result.model_ranges, result.entity, data.sensor_pose_xya, result.expected_center_beam);
340 
341  result.sensor_ranges = data.sensor_ranges;
342  return result;
343 }
344 
345 // ----------------------------------------------------------------------------------------------------
346 
348 {
349  std::unique_ptr<OptimalFit> current_optimum(new OptimalFit);
350  std::shared_ptr<BeamModel> beam_model_ptr = std::make_shared<BeamModel>(beam_model_);
351  Candidate candidate(beam_model_ptr);
352  bool valid_optimum = false;
353 
354  for(uint i_beam = 0; i_beam < nr_data_points_; ++i_beam)
355  {
356  // Iterate over the yaw range
357  for(double yaw = yaw_range.min; yaw < yaw_range.max; yaw += 0.1)
358  {
359  // Initialize candidate solution
360  candidate.initialize(i_beam, yaw);
361 
362  // And render it
363  if (!evaluateCandidate(input_data, candidate))
364  continue;
365 
366  // Calculate error
367  double error = computeFittingError(candidate.test_ranges, input_data.sensor_ranges);
368 
369  // Update optimum
370  if (error < current_optimum->getError())
371  {
372  current_optimum->update(candidate.pose, error);
373  // reject an optimum value found at the boundary of the search space as it is not a global maximum.
374  valid_optimum = !(i_beam==0 || i_beam==nr_data_points_-1);
375  }
376  }
377  }
378  if (valid_optimum)
379  return current_optimum;
380 
381  ROS_ERROR_NAMED("fitter", "optimum is invalid");
382  std::unique_ptr<OptimalFit> invalid_optimum(new OptimalFit);
383  return invalid_optimum;
384 }
385 
386 // ----------------------------------------------------------------------------------------------------
387 
388 bool Fitter::evaluateCandidate(const EstimationInputData &static_data, Candidate& candidate) const
389 {
390  // Render the entity model *exluding* other entities in the world model
391  std::vector<int> dummy_identifiers(nr_data_points_, -1); // ToDo: prevent redeclaration?
392  beam_model_.RenderModel(static_data.shape2d_transformed, candidate.pose, 0, candidate.test_ranges, dummy_identifiers);
393 
394  double ds = static_data.sensor_ranges[candidate.beam_index]; // Transformed sensor reading (distance measured along beam)
395  double dm = candidate.test_ranges[candidate.beam_index]; // Distance along the beam to the candidate entity
396 
397  if (ds <= 0 || dm <= 0)
398  return false;
399 
400  // Correct the entity pose in the direction of the beam
401  candidate.pose.t += candidate.beam_direction * ((ds - dm) * candidate.beam_length); // JL: Why multiply with beam_length (or, at least, 'l')?
402 
403  // Render model on top of the rendered data of the other entities in the world model
404  candidate.test_ranges = static_data.model_ranges;
405  std::vector<int> identifiers(nr_data_points_, 0); // ToDo: prevent redeclaration?
406  beam_model_.RenderModel(static_data.shape2d_transformed, candidate.pose, 1, candidate.test_ranges, identifiers);
407 
408  if (identifiers[static_data.expected_center_beam] != 1) // expected center beam MUST contain the rendered model
409  return false;
410 
411  return true;
412 
413 }
414 
415 // ----------------------------------------------------------------------------------------------------
416 
418 {
419  if (!entity_ptr->visual())
420  throw FitterError("Entity " + entity_ptr->id().str() + " has no shape");
421 
422  EntityRepresentation2D repr_2d = GetOrCreateEntity2D(entity_ptr);
423  if (repr_2d.shape_2d.empty())
424  throw FitterError("No conversion to 2D shape for entity " + entity_ptr->id().str());
425 
426  return repr_2d.shape_2d;
427 }
428 
429 // ----------------------------------------------------------------------------------------------------
430 
431 void Fitter::renderWorldModel2D(const ed::WorldModel& world, const geo::Pose3D& sensor_pose_xya, const ed::UUID& skip_id,
432  std::vector<double>& model_ranges, std::vector<int>& identifiers) const
433 {
434  // ToDo: re-implement: use WM copy and remove robots, furniture object. Render that
435  for(ed::WorldModel::const_iterator it = world.begin(); it != world.end(); ++it)
436  {
437  const ed::EntityConstPtr& e = *it;
438  if (e->id() == skip_id) // Skip entity id that needs to be fitted
439  continue;
440 
441  if (e->hasFlag("self")) // Skip the robot itself
442  continue;
443 
444  std::string id_str = e->id().str();
445  if (id_str.size() >= 6 && id_str.substr(0, 6) == "sergio")
446  continue;
447 
448  if (id_str.size() >= 5 && id_str.substr(0, 5) == "amigo")
449  continue;
450 
451  renderEntity(e, sensor_pose_xya, -1, model_ranges, identifiers);
452  }
453 
454 }
455 
456 // ----------------------------------------------------------------------------------------------------
457 
459  ed::EntityConstPtr entity,
460  const geo::Pose3D& sensor_pose_xya,
461  const int expected_center_beam) const
462 {
463  std::vector<double> expected_ranges(nr_data_points_, 0);
464  expected_ranges = model_ranges;
465  std::vector<int> expected_identifiers(nr_data_points_, 0);
466  renderEntity(entity, sensor_pose_xya, 1, expected_ranges, expected_identifiers);
467  if (expected_center_beam < 0 || expected_center_beam >= static_cast<int>(nr_data_points_))
468  throw FitterError("Expected beam outside of measurement range(" + std::to_string(nr_data_points_) + "), index: " + std::to_string(expected_center_beam));
469  if (expected_identifiers[expected_center_beam] != 1) // expected center beam MUST contain the rendered model
470  throw FitterError("Expected beam does not go through entity");
471 }
472 
473 // ----------------------------------------------------------------------------------------------------
474 
475 void Fitter::configureBeamModel(const image_geometry::PinholeCameraModel& cammodel)
476 {
477  unsigned int nr_beams = std::min(200, cammodel.fullResolution().width); // don't use more data points than the resolution of your camera
478  double fx = cammodel.fx() * nr_beams / cammodel.fullResolution().width; // Reducing nr of data points will require a different focal length
479  double w = 2 * nr_beams / fx; // reverse calculation of the width of the beam model.
480  beam_model_.initialize(w, nr_beams);
481  nr_data_points_ = nr_beams;
482  configured_ = true;
483 }
484 
485 // ----------------------------------------------------------------------------------------------------
486 void Fitter::processSensorData(const rgbd::Image& image, const geo::Pose3D& sensor_pose, FitterData& data) const
487 {
488  data.sensor_pose = sensor_pose;
489  decomposePose(sensor_pose, data.sensor_pose_xya, data.sensor_pose_zrp);
490 
491  const cv::Mat& depth = image.getDepthImage();
492  rgbd::View view(image, depth.cols);
493 
494  std::vector<double>& ranges = data.sensor_ranges;
495 
496  if (ranges.size() != beam_model_.num_beams())
497  ranges.resize(beam_model_.num_beams(), 0);
498 
499  data.fx = beam_model_.fx();
500 
501  for(int x = 0; x < depth.cols; ++x)
502  {
503  for(int y = 0; y < depth.rows; ++y)
504  {
505  float d = depth.at<float>(y, x);
506  if (d == 0 || d != d)
507  continue;
508 
509  geo::Vector3 p_sensor = view.getRasterizer().project2Dto3D(x, y) * d;
510  geo::Vector3 p_floor = data.sensor_pose_zrp * p_sensor;
511 
512  if (p_floor.z < 0.2) // simple floor filter
513  continue;
514 
515  int i = beam_model_.CalculateBeam(p_floor.x, p_floor.y);
516  if (i >= 0 && i < static_cast<int>(ranges.size()))
517  {
518  double& r = ranges[i];
519  if (r == 0 || p_floor.y < r)
520  r = p_floor.y;
521  }
522  }
523  }
524 }
525 
526 // ----------------------------------------------------------------------------------------------------
527 
529 {
531  // ToDo: this does not accomodate for different shape revisions.
532  if (it_model != entity_shapes_.end())
533  return it_model->second;
534 
535  // Decompose entity pose into X Y YAW and Z ROLL PITCH
536  geo::Pose3D pose_xya;
537  geo::Pose3D pose_zrp;
538  decomposePose(e->pose(), pose_xya, pose_zrp);
539 
540  EntityRepresentation2D& entity_model = entity_shapes_[e->id()];
541  dml::project2D(e->visual()->getMesh().getTransformed(pose_zrp), entity_model.shape_2d);
542 
543  return entity_model;
544 }
545 
546 // ----------------------------------------------------------------------------------------------------
547 
548 void Fitter::renderEntity(const ed::EntityConstPtr& e, const geo::Pose3D& sensor_pose_xya, int identifier,
549  std::vector<double>& model_ranges, std::vector<int>& identifiers) const
550 {
551  geo::Transform2 sensor_pose_xya_2d = XYYawToTransform2(sensor_pose_xya);
552 
553  if (model_ranges.size() != beam_model_.num_beams())
554  model_ranges.resize(beam_model_.num_beams(), 0);
555 
556  if (!e->visual() || !e->has_pose())
557  return;
558 
559  // Decompose entity pose into X Y YAW and Z ROLL PITCH
560  geo::Pose3D pose_xya;
561  geo::Pose3D pose_zrp;
562  decomposePose(e->pose(), pose_xya, pose_zrp);
563 
565 
566  geo::Transform2 pose_2d_SENSOR = sensor_pose_xya_2d.inverse() * XYYawToTransform2(pose_xya);
567 
568  beam_model_.RenderModel(e2d.shape_2d, pose_2d_SENSOR, identifier, model_ranges, identifiers);
569 }
570 
571 // ----------------------------------------------------------------------------------------------------
geo::Vector3::y
const real & y() const
geo::Mat3T::identity
static Mat3T identity()
ed::WorldModel::getEntity
EntityConstPtr getEntity(const ed::UUID &id) const
sstream
std::vector::resize
T resize(T... args)
Fitter::renderEntity
void renderEntity(const ed::EntityConstPtr &e, const geo::Pose3D &sensor_pose_xya, int identifier, std::vector< double > &model_ranges, std::vector< int > &identifiers) const
renderEntity renders the entity in 2D using the beam model with the provided (2D) sensor pose....
Definition: fitter.cpp:548
computeFittedPose
geo::Pose3D computeFittedPose(const geo::Transform2 &pose_sensor, ed::EntityConstPtr entity, const geo::Pose3D &sensor_pose_xya)
Definition: fitter.cpp:220
ERROR_THRESHOLD
const double ERROR_THRESHOLD
Definition: fitter.cpp:31
OptimalFit::getPose
geo::Transform2 getPose()
Definition: fitter.cpp:138
std::string
Candidate::test_ranges
std::vector< double > test_ranges
Definition: fitter.cpp:173
std::shared_ptr< BeamModel >
Fitter::preProcessInputData
EstimationInputData preProcessInputData(const ed::WorldModel &world, const ed::UUID &id, const geo::Pose3D &expected_pose, const FitterData &data) const
preProcessInputData pre-processes the inputs for the fitting algorithm, i.e., gets the shape of the e...
Definition: fitter.cpp:307
EstimationInputData::shape_center
geo::Vec2 shape_center
Definition: fitter.h:89
update_request.h
geo::Vec2T::y
T y
BeamModel::RenderModel
void RenderModel(const std::vector< std::vector< geo::Vec2 > > &contours, const geo::Transform2 &pose, int identifier, std::vector< double > &ranges, std::vector< int > &identifiers) const
Definition: beam_model.cpp:28
Fitter::beam_model_
BeamModel beam_model_
Definition: fitter.h:255
std::vector
std::map::find
T find(T... args)
std::vector::size
T size(T... args)
EstimationInputData::entity
ed::EntityConstPtr entity
Definition: fitter.h:87
geo::Transform2T::R
Mat2T< T > R
Fitter::~Fitter
~Fitter()
Definition: fitter.cpp:252
EstimationInputData::sensor_ranges
std::vector< double > sensor_ranges
Definition: fitter.h:92
OptimalFit::update
void update(const geo::Transform2 &new_pose, const double &new_error)
Definition: fitter.cpp:131
Candidate::pose
geo::Transform2 pose
Definition: fitter.cpp:172
geo::Vec3T
Shape.h
geo::Vec2T::x
T x
geo::Transform2T::setRotation
void setRotation(T yaw)
Fitter::nr_data_points_
uint nr_data_points_
Definition: fitter.h:263
FitterError
The FitterError class exception is thrown in case of errors in the fitter algorithm.
Definition: fitter.h:36
EntityRepresentation2D::shape_2d
Shape2D shape_2d
Definition: fitter.h:58
geo::Transform3T
Fitter::estimateEntityPose
bool estimateEntityPose(const FitterData &data, const ed::WorldModel &world, const ed::UUID &id, const geo::Pose3D &expected_pose, geo::Pose3D &fitted_pose, double max_yaw_change=M_PI) const
estimateEntityPose performs the entity pose estimation. Basically, tries to call estimateEntityPoseIm...
Definition: fitter.cpp:258
FitterData
The FitterData struct contains the downprojected (hence 2D) sensor readings as well as the sensor pos...
Definition: fitter.h:68
EntityRepresentation2D
The EntityRepresentation2D struct contains the (downprojected) shape that is used for the fitting.
Definition: fitter.h:55
ed::WorldModel::begin
const_iterator begin() const
Fitter::configured_
bool configured_
Definition: fitter.h:264
BeamModel::initialize
void initialize(double w, unsigned int num_beams)
Definition: beam_model.cpp:16
Candidate::initialize
void initialize(const uint i_beam, const double yaw)
Definition: fitter.cpp:155
YawRange
Definition: fitter.cpp:34
ed::WorldModel::const_iterator
EntityIterator const_iterator
geo::Transform2T::t
Vec2T< T > t
EstimationInputData
The EstimationInputData struct contains processed data from the world model (entity,...
Definition: fitter.h:85
geo::Mat2T::yy
T yy
BeamModel::fx
float fx() const
Definition: beam_model.h:46
Fitter::entity_shapes_
std::map< ed::UUID, EntityRepresentation2D > entity_shapes_
Definition: fitter.h:258
tf_conversions.h
Fitter::checkExpectedBeamThroughEntity
void checkExpectedBeamThroughEntity(const std::vector< double > &model_ranges, ed::EntityConstPtr entity, const geo::Pose3D &sensor_pose_xya, const int expected_center_beam) const
checkExpectedBeamThroughEntity checks if the expected center beam passes through the entity....
Definition: fitter.cpp:458
ed::EntityConstPtr
shared_ptr< const Entity > EntityConstPtr
std::fill
T fill(T... args)
ed::WorldModel::end
const_iterator end() const
Candidate::~Candidate
~Candidate()
Definition: fitter.cpp:165
BeamModel::CalculateBeam
int CalculateBeam(double x, double depth) const
Definition: beam_model.h:19
image
cv::Mat image
geo::Vec3T::y
T y
Candidate
Definition: fitter.cpp:147
geo::Transform3T::inverse
Transform3T inverse() const
geo::Mat2T
rgbd::Image
rgbd::View::getRasterizer
const geo::DepthCamera & getRasterizer() const
image.h
error
std::ostream & error()
Fitter::GetOrCreateEntity2D
EntityRepresentation2D GetOrCreateEntity2D(const ed::EntityConstPtr &e) const
GetOrCreateEntity2D returns the downprojected shape of the entity. If it's already in the cache,...
Definition: fitter.cpp:528
geo::Transform2T
std::to_string
T to_string(T... args)
geo::Transform2
Transform2T< real > Transform2
geo::Mat3T::yy
T yy
OptimalFit
Definition: fitter.cpp:123
geo::Transform3T::t
Vec3T< T > t
YawRange::max
double max
Definition: fitter.cpp:36
OptimalFit::pose
geo::Transform2 pose
Definition: fitter.cpp:141
ed::UUID
geo::Mat3T::xx
T xx
Fitter::findOptimum
std::unique_ptr< OptimalFit > findOptimum(const EstimationInputData &input_data, const YawRange &yaw_range) const
findOptimum finds the 'optimal' fit by evaluating candidates over all beams and over the entire yaw r...
Definition: fitter.cpp:347
geo::Vector3
std::map
geo::DepthCamera::project2Dto3D
geo::Vec3T< T > project2Dto3D(int x, int y) const
geo::Vec3
Vec3T< real > Vec3
ed::WorldModel
geo::Vector3::z
const real & z() const
geo::convert
void convert(const geo::DepthCamera &cam_model, sensor_msgs::CameraInfo &msg)
computeYawRange
YawRange computeYawRange(const geo::Pose3D &sensor_pose_xya, const geo::Pose3D &expected_entity_pose, const double &max_yaw_change)
Definition: fitter.cpp:41
XYYawToTransform2
geo::Transform2 XYYawToTransform2(const geo::Pose3D &pose)
Definition: fitter.cpp:116
decomposePose
void decomposePose(const geo::Pose3D &pose, geo::Pose3D &pose_xya, geo::Pose3D &pose_zrp)
Definition: fitter.cpp:99
std::min
T min(T... args)
geo::Mat2T::xx
T xx
Candidate::beam_length
double beam_length
Definition: fitter.cpp:170
std::string::substr
T substr(T... args)
std::ostringstream
view.h
EstimationInputData::model_ranges
std::vector< double > model_ranges
Definition: fitter.h:91
Fitter::get2DShape
Shape2D get2DShape(ed::EntityConstPtr entity_ptr) const
get2DShape gets the downprojected, 2D shape from an entity
Definition: fitter.cpp:417
world_model.h
OptimalFit::~OptimalFit
~OptimalFit()
Definition: fitter.cpp:129
BeamModel::num_beams
unsigned int num_beams() const
Definition: beam_model.h:45
diff
IMETHOD Twist diff(const Frame &F_a_b1, const Frame &F_a_b2, double dt=1)
limits
Candidate::beam_index
uint beam_index
Definition: fitter.cpp:169
geo::Mat3T::yx
T yx
std::vector::begin
T begin(T... args)
computeShapeCenter
geo::Vec2 computeShapeCenter(const Shape2D &shape2d)
Definition: fitter.cpp:59
geo::Transform3T::R
Mat3T< T > R
Candidate::Candidate
Candidate(std::shared_ptr< BeamModel > beam_model_ptr)
Definition: fitter.cpp:151
fitter.h
geo::Mat2T::xy
T xy
Candidate::beam_model_ptr_
std::shared_ptr< BeamModel > beam_model_ptr_
Definition: fitter.cpp:176
geo::Vector3::x
const real & x() const
geo::Mat2T::yx
T yx
OptimalFit::getError
double getError()
Definition: fitter.cpp:137
std::vector::empty
T empty(T... args)
Fitter::configureBeamModel
void configureBeamModel(const image_geometry::PinholeCameraModel &cammodel)
configure the beam model (nr of data points and focal length) according to the camera you are using.
Definition: fitter.cpp:475
YawRange::min
double min
Definition: fitter.cpp:36
Fitter::estimateEntityPoseImp
bool estimateEntityPoseImp(const FitterData &data, const ed::WorldModel &world, const ed::UUID &id, const geo::Pose3D &expected_pose, geo::Pose3D &fitted_pose, double max_yaw_change) const
estimateEntityPoseImp actual implementation of the entity pose estimation. Preprocess input data iter...
Definition: fitter.cpp:274
dml::project2D
void project2D(const geo::Mesh &mesh, std::vector< std::vector< geo::Vec2 > > &contours)
Definition: mesh_tools.cpp:219
std::ostringstream::str
T str(T... args)
OptimalFit::error
double error
Definition: fitter.cpp:142
Fitter::evaluateCandidate
bool evaluateCandidate(const EstimationInputData &static_data, Candidate &candidate) const
evaluateCandidate renders the model, transform the model along the beam direction to get this distanc...
Definition: fitter.cpp:388
EstimationInputData::shape2d_transformed
Shape2D shape2d_transformed
Definition: fitter.h:88
geo::Transform2T::setOrigin
void setOrigin(const Vec2T< T > &v)
Fitter::processSensorData
void processSensorData(const rgbd::Image &image, const geo::Pose3D &sensor_pose, FitterData &data) const
processSensorData pre-processes sensor data, i.e., performs a downprojection of the input depth image...
Definition: fitter.cpp:486
std::vector::end
T end(T... args)
std::max
T max(T... args)
entity.h
mesh_tools.h
logging.h
EstimationInputData::expected_center_beam
int expected_center_beam
Definition: fitter.h:90
Fitter::renderWorldModel2D
void renderWorldModel2D(const ed::WorldModel &world, const geo::Pose3D &sensor_pose_xya, const ed::UUID &skip_id, std::vector< double > &model_ranges, std::vector< int > &identifiers) const
renderWorldModel2D renders all world model entities
Definition: fitter.cpp:431
OptimalFit::OptimalFit
OptimalFit()
Definition: fitter.cpp:127
transformShape2D
Shape2D transformShape2D(const Shape2D &original_shape, const geo::Vec2 &transformation)
Definition: fitter.cpp:84
std::unique_ptr
computeFittingError
double computeFittingError(const std::vector< double > &test_ranges, const std::vector< double > &sensor_ranges)
Definition: fitter.cpp:182
geo::Mat3T::xy
T xy
std::numeric_limits
geo::Mat3T::setRPY
void setRPY(T roll, T pitch, T yaw)
Candidate::beam_direction
geo::Vec2 beam_direction
Definition: fitter.cpp:171
geo::Transform2T::inverse
Transform2T inverse() const
rgbd::View
geo::Vec3T::x
T x
geo::Vec2T
Fitter::Fitter
Fitter()
Fitter default constructor, must be configured later.
Definition: fitter.cpp:235