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.