rapid
A ROS robotics library.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
pose_estimation.h
Go to the documentation of this file.
1 #ifndef _RAPID_PERCEPTION_POSE_ESTIMATION_H_
2 #define _RAPID_PERCEPTION_POSE_ESTIMATION_H_
3 
4 #include <vector>
5 
6 #include "boost/thread/mutex.hpp"
7 #include "Eigen/Core"
8 #include "Eigen/Geometry"
9 #include "geometry_msgs/Pose.h"
10 #include "pcl/point_cloud.h"
11 #include "pcl/point_types.h"
12 #include "ros/ros.h"
13 #include "visualization_msgs/Marker.h"
14 
15 #include "rapid_msgs/Roi3D.h"
19 
20 namespace rapid {
21 namespace perception {
22 // Finds instances of a given object in a scene. It is designed and tested to
23 // work with single-view point clouds that are voxelized to a resolution of a
24 // 0.5cm.
25 //
26 // In addition to providing an object, you must also provide a region of
27 // interest, represented as a box, around the object. Empty space in your box
28 // matters -- the algorithm will look for that space to be empty when
29 // considering candidate poses for the object.
30 //
31 // Usage:
32 // RandomHeatMapper* heat_mapper = new RandomHeatMapper();
33 // PoseEstimator estimator(heat_mapper);
34 // estimator.set_scene(scene);
35 // estimator.set_object(object, object_roi);
36 //
37 // estimator.set_fitness_threshold(0.0045);
38 // estimator.set_min_results(1); // Overrides the fitness threshold if set.
39 // vector<PoseEstimationMatch> matches;
40 // estimator.Find(&matches);
41 //
42 // There are two ways to use the algorithm. You can ask it to return all matches
43 // whose fitness scores are less than the given fitness threshold (by default,
44 // 0.45cm). Note that the lower the fitness, the better the match.
45 //
46 // You can also ask it to return at least N results, even if some or all of
47 // those results are above the fitness threshold. This is helpful when you
48 // already know from context that N instances of the object are in the scene.
50  public:
51  // Constructs a pose estimator given a heat mapper. We do not take ownership
52  // over the pointer.
54 
55  // Set the scene to search for the object in. We recommend voxelizing it for
56  // speed at the same resolution as the object. A resolution of 0.5cm works
57  // well.
58  //
59  // We assume it has already been filtered for NaNs. The scene should be in the
60  // same frame as the object.
61  void set_scene(pcl::PointCloud<pcl::PointXYZRGB>::Ptr scene);
62 
63  // Set the object to search for. We recommend voxelizing it for speed at the
64  // same resolution as the scene. A resolution of 0.5cm works well.
65  //
66  // We assume it has already been filtered for NaNs. The object should be in
67  // the same frame as the scene.
68  //
69  // The region of interest (ROI) is a box around the object, which indicates
70  // how much empty space around the object you want to enforce. For example, if
71  // the object is a horizontal cross-section of a cylinder, and there's no
72  // empty space on top or bottom, then many such cross-sections may be found on
73  // a single cylinder. However, if the ROI includes empty space above the cross
74  // section, then the algorithm will only find the top-most cross section of
75  // the cylinder (e.g., the cap of a bottle).
76  void set_object(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr& object);
77  void set_roi(const rapid_msgs::Roi3D& roi);
78 
80 
81  // Setters for parameters
82  // num_candidates is the number of samples to initialize ICP at. More
83  // candidates will improve recall but possibly decrease precision, and take
84  // longer. The default value is 100.
85  void set_num_candidates(int val);
86 
87  // sigma_threshold can sometimes help find objects, although we don't
88  // recommend using it as it's not very precise.
89  void set_sigma_threshold(double val);
90 
91  // nms_radius is the radius to look around each match to eliminate worse
92  // matches. Often, many matches will be clustered in the same location, so we
93  // want to consolidate all of them into the single best match in the cluster.
94  // The default value is 0.02.
95  void set_nms_radius(double val);
96 
97  // If the fitness threshold is set, then we return matches whose fitness
98  // values are below the threshold. A higher threshold will lead to higher
99  // recall but lower precision. The default value is 0.0045. It can be
100  // interpreted as the average error distance between points on the object and
101  // points in the scene (within the object's ROI).
102  void set_fitness_threshold(double val);
103 
104  // Sets the minimum number of matches to return, even if some or all of the
105  // matches are above the fitness threshold. This can be helpful if you already
106  // know from context that a match exists. Often, the best match is correct
107  // even though it's above the fitness threshold. The default value is 0.
108  void set_min_results(int val);
109 
110  void set_debug(bool val);
111 
112  // Setters for visualization publishers
113  void set_scene_publisher(const ros::Publisher& pub);
114  void set_object_publisher(const ros::Publisher& pub);
115  void set_candidates_publisher(const ros::Publisher& pub);
116  void set_alignment_publisher(const ros::Publisher& pub);
117  void set_output_publisher(const ros::Publisher& pub);
118  void set_marker_publisher(const ros::Publisher& pub);
119 
120  // Runs the pose estimation algorithm. It will return all matches whose
121  // fitness are below the fitness threshold (lower fitness means a better
122  // match). If min_results is set, it will return at least that many matches,
123  // even if they are above the fitness threshold.
124  void Find(std::vector<PoseEstimationMatch>* matches);
125 
126  private:
127  // Sample the heatmap by importance to generate candidate points.
128  void ComputeCandidates(Eigen::VectorXd& importances,
129  pcl::PointCloud<pcl::PointXYZRGB>::Ptr heatmap,
130  pcl::PointCloud<pcl::PointXYZRGB>::Ptr candidate);
131  // Pick the top candidates from the heat map.
132  void ComputeTopCandidates(Eigen::VectorXd& importances,
133  pcl::PointCloud<pcl::PointXYZRGB>::Ptr heatmap,
134  pcl::PointCloud<pcl::PointXYZRGB>::Ptr candidate);
135  // Initialize and run ICP at each of the candidate points.
136  void RunIcpCandidates(pcl::PointCloud<pcl::PointXYZRGB>::Ptr candidates,
137  std::vector<PoseEstimationMatch>* aligned_objects);
138  void RunIcpCandidateInThread(
139  pcl::PointCloud<pcl::PointXYZRGB>::Ptr candidates, size_t candidate_index,
140  int max_iterations, boost::mutex& output_mutex,
141  std::vector<PoseEstimationMatch>* aligned_objects);
142  // Do non-max suppression on ICP outputs.
143  void NonMaxSuppression(std::vector<PoseEstimationMatch>& aligned_objects,
144  std::vector<int>* deduped_indices);
145  // Filter matches based on score and/or statistical tests.
146  void FilterMatches(const std::vector<PoseEstimationMatch>& aligned_objects,
147  const std::vector<int>& deduped_indices,
148  std::vector<int>* output_indices);
149  void GenerateRotations(std::vector<Eigen::Quaternionf>* rotations);
150 
151  PoseEstimationHeatMapper* heat_mapper_;
152 
153  // Source and target data structures
154  pcl::PointCloud<pcl::PointXYZRGB>::Ptr scene_;
155  pcl::PointCloud<pcl::PointXYZRGB>::Ptr object_;
156  Eigen::Vector3f object_center_; // Approx center point of object.
157  Eigen::Vector3f object_dims_; // Approx x/y/z lengths of bounding box.
158  rapid_msgs::Roi3D object_roi_;
159 
160  // Parameters
161  // Number of candidate samples to consider for ICP.
162  int num_candidates_;
163  // The ICP fitness threshold below which we consider the alignment a positive
164  // match
165  double fitness_threshold_;
166  // The number of standard deviations below the mean fitness with which we'll
167  // accept the best match, if none of the matches are below the fitness
168  // threshold.
169  double sigma_threshold_;
170  // Radius to look for other matches when doing non-max suppression
171  double nms_radius_;
172  // The minimum number of matches to return, regardless of fitness score.
173  int min_results_;
174 
175  bool debug_;
176 
177  // Visualization publishers
178  ros::Publisher scene_pub_;
179  ros::Publisher object_pub_;
180  ros::Publisher candidates_pub_;
181  ros::Publisher alignment_pub_;
182  ros::Publisher output_pub_;
183  ros::Publisher marker_pub_;
184 };
185 } // namespace perception
186 } // namespace rapid
187 
188 #endif // _RAPID_PERCEPTION_POSE_ESTIMATION_H_
void set_roi(const rapid_msgs::Roi3D &roi)
void set_marker_publisher(const ros::Publisher &pub)
void set_object(const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &object)
void set_output_publisher(const ros::Publisher &pub)
void set_scene_publisher(const ros::Publisher &pub)
void set_sigma_threshold(double val)
PoseEstimationHeatMapper * heat_mapper()
void set_scene(pcl::PointCloud< pcl::PointXYZRGB >::Ptr scene)
void set_fitness_threshold(double val)
PoseEstimator(PoseEstimationHeatMapper *heat_mapper)
void set_candidates_publisher(const ros::Publisher &pub)
void set_alignment_publisher(const ros::Publisher &pub)
void Find(std::vector< PoseEstimationMatch > *matches)
void set_object_publisher(const ros::Publisher &pub)