Go to the documentation of this file.
5 #include <ros/console.h>
20 #include <opencv2/highgui/highgui.hpp>
26 #include <ed_sensor_integration_msgs/ImageBinary.h>
44 double expected_yaw_SENSOR;
49 m.getRPY(roll, pitch, expected_yaw_SENSOR);
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};
66 for(uint i = 0; i < shape2d.
size(); ++i)
69 for(uint j = 0; j < contour.
size(); ++j)
79 return 0.5 * (shape_min + shape_max);
86 Shape2D shape2d_transformed = original_shape;
87 for(uint i = 0; i < shape2d_transformed.
size(); ++i)
90 for(uint j = 0; j < contour_transformed.
size(); ++j)
91 contour_transformed[j] -= transformation;
93 return shape2d_transformed;
104 double roll, pitch, yaw;
105 m.getRPY(roll, pitch, yaw);
110 pose_zrp = pose_xya.
inverse() * pose;
185 double total_error = 0;
186 for(
unsigned int i = 0; i < test_ranges.
size(); ++i)
188 double ds = sensor_ranges[i];
189 double dm = test_ranges[i];
202 double diff = std::abs(ds - dm);
214 double error = total_error / n;
223 pose_3d.
t =
geo::Vec3(pose_sensor.
t.
x, pose_sensor.
t.
y, entity->pose().t.z);
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;
230 return sensor_pose_xya * pose_3d;
243 nr_data_points_(nr_data_points)
245 double w = 2 * nr_data_points / fx;
267 ROS_ERROR_STREAM(
"Fitter error: " <<
error.what());
288 if (current_optimum->getError() > error_threshold)
291 errormsg <<
"Error of best fit [" << current_optimum->getError() <<
"] exceeds threshold [" << error_threshold <<
"]";
297 best_pose_SENSOR.
t += best_pose_SENSOR.
R * -estimation_input_data.
shape_center;
334 geo::Vec3 expected_pos_sensor = data.sensor_pose_xya.inverse() * expected_pose.
t;
352 bool valid_optimum =
false;
357 for(
double yaw = yaw_range.
min; yaw < yaw_range.
max; yaw += 0.1)
370 if (error < current_optimum->getError())
372 current_optimum->update(candidate.
pose,
error);
379 return current_optimum;
381 ROS_ERROR_NAMED(
"fitter",
"optimum is invalid");
383 return invalid_optimum;
397 if (ds <= 0 || dm <= 0)
419 if (!entity_ptr->visual())
420 throw FitterError(
"Entity " + entity_ptr->id().str() +
" has no shape");
424 throw FitterError(
"No conversion to 2D shape for entity " + entity_ptr->id().str());
438 if (e->id() == skip_id)
441 if (e->hasFlag(
"self"))
445 if (id_str.
size() >= 6 && id_str.
substr(0, 6) ==
"sergio")
448 if (id_str.
size() >= 5 && id_str.
substr(0, 5) ==
"amigo")
451 renderEntity(e, sensor_pose_xya, -1, model_ranges, identifiers);
461 const int expected_center_beam)
const
464 expected_ranges = model_ranges;
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_))
469 if (expected_identifiers[expected_center_beam] != 1)
470 throw FitterError(
"Expected beam does not go through entity");
477 unsigned int nr_beams =
std::min(200, cammodel.fullResolution().width);
478 double fx = cammodel.fx() * nr_beams / cammodel.fullResolution().width;
479 double w = 2 * nr_beams / fx;
488 data.sensor_pose = sensor_pose;
489 decomposePose(sensor_pose, data.sensor_pose_xya, data.sensor_pose_zrp);
491 const cv::Mat& depth =
image.getDepthImage();
501 for(
int x = 0; x < depth.cols; ++x)
503 for(
int y = 0; y < depth.rows; ++y)
505 float d = depth.at<
float>(y, x);
506 if (d == 0 || d != d)
516 if (i >= 0 && i <
static_cast<int>(ranges.
size()))
518 double& r = ranges[i];
519 if (r == 0 || p_floor.
y < r)
533 return it_model->second;
556 if (!e->visual() || !e->has_pose())
EntityConstPtr getEntity(const ed::UUID &id) const
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....
geo::Pose3D computeFittedPose(const geo::Transform2 &pose_sensor, ed::EntityConstPtr entity, const geo::Pose3D &sensor_pose_xya)
const double ERROR_THRESHOLD
geo::Transform2 getPose()
std::vector< double > test_ranges
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...
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
void update(const geo::Transform2 &new_pose, const double &new_error)
The FitterError class exception is thrown in case of errors in the fitter algorithm.
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...
The FitterData struct contains the downprojected (hence 2D) sensor readings as well as the sensor pos...
The EntityRepresentation2D struct contains the (downprojected) shape that is used for the fitting.
const_iterator begin() const
void initialize(double w, unsigned int num_beams)
void initialize(const uint i_beam, const double yaw)
EntityIterator const_iterator
std::map< ed::UUID, EntityRepresentation2D > entity_shapes_
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....
shared_ptr< const Entity > EntityConstPtr
const_iterator end() const
int CalculateBeam(double x, double depth) const
const geo::DepthCamera & getRasterizer() const
EntityRepresentation2D GetOrCreateEntity2D(const ed::EntityConstPtr &e) const
GetOrCreateEntity2D returns the downprojected shape of the entity. If it's already in the cache,...
Transform2T< real > Transform2
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...
geo::Vec3T< T > project2Dto3D(int x, int y) const
void convert(const geo::DepthCamera &cam_model, sensor_msgs::CameraInfo &msg)
YawRange computeYawRange(const geo::Pose3D &sensor_pose_xya, const geo::Pose3D &expected_entity_pose, const double &max_yaw_change)
geo::Transform2 XYYawToTransform2(const geo::Pose3D &pose)
void decomposePose(const geo::Pose3D &pose, geo::Pose3D &pose_xya, geo::Pose3D &pose_zrp)
Shape2D get2DShape(ed::EntityConstPtr entity_ptr) const
get2DShape gets the downprojected, 2D shape from an entity
unsigned int num_beams() const
IMETHOD Twist diff(const Frame &F_a_b1, const Frame &F_a_b2, double dt=1)
geo::Vec2 computeShapeCenter(const Shape2D &shape2d)
Candidate(std::shared_ptr< BeamModel > beam_model_ptr)
std::shared_ptr< BeamModel > beam_model_ptr_
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.
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...
void project2D(const geo::Mesh &mesh, std::vector< std::vector< geo::Vec2 > > &contours)
bool evaluateCandidate(const EstimationInputData &static_data, Candidate &candidate) const
evaluateCandidate renders the model, transform the model along the beam direction to get this distanc...
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...
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
Shape2D transformShape2D(const Shape2D &original_shape, const geo::Vec2 &transformation)
double computeFittingError(const std::vector< double > &test_ranges, const std::vector< double > &sensor_ranges)
void setRPY(T roll, T pitch, T yaw)
Fitter()
Fitter default constructor, must be configured later.