Point Cloud Library (PCL)  1.7.2
correspondence_rejection.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2011, Willow Garage, Inc.
6  * Copyright (c) 2012-, Open Perception, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id$
38  *
39  */
40 
41 #ifndef PCL_REGISTRATION_CORRESPONDENCE_REJECTION_H_
42 #define PCL_REGISTRATION_CORRESPONDENCE_REJECTION_H_
43 
44 #include <pcl/registration/correspondence_types.h>
45 #include <pcl/registration/correspondence_sorting.h>
46 #include <pcl/console/print.h>
47 #include <pcl/common/transforms.h>
48 #include <pcl/point_cloud.h>
49 #include <pcl/search/kdtree.h>
50 
51 namespace pcl
52 {
53  namespace registration
54  {
55  /** @b CorrespondenceRejector represents the base class for correspondence rejection methods
56  * \author Dirk Holz
57  * \ingroup registration
58  */
60  {
61  public:
62  typedef boost::shared_ptr<CorrespondenceRejector> Ptr;
63  typedef boost::shared_ptr<const CorrespondenceRejector> ConstPtr;
64 
65  /** \brief Empty constructor. */
67  : rejection_name_ ()
69  {}
70 
71  /** \brief Empty destructor. */
73 
74  /** \brief Provide a pointer to the vector of the input correspondences.
75  * \param[in] correspondences the const boost shared pointer to a correspondence vector
76  */
77  virtual inline void
79  {
80  input_correspondences_ = correspondences;
81  };
82 
83  /** \brief Get a pointer to the vector of the input correspondences.
84  * \return correspondences the const boost shared pointer to a correspondence vector
85  */
88 
89  /** \brief Run correspondence rejection
90  * \param[out] correspondences Vector of correspondences that have not been rejected.
91  */
92  inline void
94  {
96  return;
97 
98  applyRejection (correspondences);
99  }
100 
101  /** \brief Get a list of valid correspondences after rejection from the original set of correspondences.
102  * Pure virtual. Compared to \a getCorrespondences this function is
103  * stateless, i.e., input correspondences do not need to be provided beforehand,
104  * but are directly provided in the function call.
105  * \param[in] original_correspondences the set of initial correspondences given
106  * \param[out] remaining_correspondences the resultant filtered set of remaining correspondences
107  */
108  virtual inline void
109  getRemainingCorrespondences (const pcl::Correspondences& original_correspondences,
110  pcl::Correspondences& remaining_correspondences) = 0;
111 
112  /** \brief Determine the indices of query points of
113  * correspondences that have been rejected, i.e., the difference
114  * between the input correspondences (set via \a setInputCorrespondences)
115  * and the given correspondence vector.
116  * \param[in] correspondences Vector of correspondences after rejection
117  * \param[out] indices Vector of query point indices of those correspondences
118  * that have been rejected.
119  */
120  inline void
122  std::vector<int>& indices)
123  {
125  {
126  PCL_WARN ("[pcl::registration::%s::getRejectedQueryIndices] Input correspondences not set (lookup of rejected correspondences _not_ possible).\n", getClassName ().c_str ());
127  return;
128  }
129 
130  pcl::getRejectedQueryIndices(*input_correspondences_, correspondences, indices);
131  }
132 
133  /** \brief Get a string representation of the name of this class. */
134  inline const std::string&
135  getClassName () const { return (rejection_name_); }
136 
137 
138  /** \brief See if this rejector requires source points */
139  virtual bool
141  { return (false); }
142 
143  /** \brief Abstract method for setting the source cloud */
144  virtual void
146  {
147  PCL_WARN ("[pcl::registration::%s::setSourcePoints] This class does not require an input source cloud", getClassName ().c_str ());
148  }
149 
150  /** \brief See if this rejector requires source normals */
151  virtual bool
153  { return (false); }
154 
155  /** \brief Abstract method for setting the source normals */
156  virtual void
158  {
159  PCL_WARN ("[pcl::registration::%s::setSourceNormals] This class does not require input source normals", getClassName ().c_str ());
160  }
161  /** \brief See if this rejector requires a target cloud */
162  virtual bool
164  { return (false); }
165 
166  /** \brief Abstract method for setting the target cloud */
167  virtual void
169  {
170  PCL_WARN ("[pcl::registration::%s::setTargetPoints] This class does not require an input target cloud", getClassName ().c_str ());
171  }
172 
173  /** \brief See if this rejector requires target normals */
174  virtual bool
176  { return (false); }
177 
178  /** \brief Abstract method for setting the target normals */
179  virtual void
181  {
182  PCL_WARN ("[pcl::registration::%s::setTargetNormals] This class does not require input target normals", getClassName ().c_str ());
183  }
184 
185  protected:
186 
187  /** \brief The name of the rejection method. */
188  std::string rejection_name_;
189 
190  /** \brief The input correspondences. */
192 
193  /** \brief Abstract rejection method. */
194  virtual void
195  applyRejection (Correspondences &correspondences) = 0;
196  };
197 
198  /** @b DataContainerInterface provides a generic interface for computing correspondence scores between correspondent
199  * points in the input and target clouds
200  * \ingroup registration
201  */
203  {
204  public:
206  virtual double getCorrespondenceScore (int index) = 0;
207  virtual double getCorrespondenceScore (const pcl::Correspondence &) = 0;
208  };
209 
210  /** @b DataContainer is a container for the input and target point clouds and implements the interface
211  * to compute correspondence scores between correspondent points in the input and target clouds
212  * \ingroup registration
213  */
214  template <typename PointT, typename NormalT = pcl::PointNormal>
216  {
218  typedef typename PointCloud::Ptr PointCloudPtr;
219  typedef typename PointCloud::ConstPtr PointCloudConstPtr;
220 
221  typedef typename pcl::search::KdTree<PointT>::Ptr KdTreePtr;
222 
224  typedef typename Normals::Ptr NormalsPtr;
225  typedef typename Normals::ConstPtr NormalsConstPtr;
226 
227  public:
228 
229  /** \brief Empty constructor. */
230  DataContainer (bool needs_normals = false)
231  : input_ ()
232  , input_transformed_ ()
233  , target_ ()
234  , input_normals_ ()
235  , input_normals_transformed_ ()
236  , target_normals_ ()
237  , tree_ (new pcl::search::KdTree<PointT>)
238  , class_name_ ("DataContainer")
239  , needs_normals_ (needs_normals)
240  , target_cloud_updated_ (true)
241  , force_no_recompute_ (false)
242  {
243  }
244 
245  /** \brief Empty destructor */
246  virtual ~DataContainer () {}
247 
248  /** \brief Provide a source point cloud dataset (must contain XYZ
249  * data!), used to compute the correspondence distance.
250  * \param[in] cloud a cloud containing XYZ data
251  */
252  PCL_DEPRECATED ("[pcl::registration::DataContainer::setInputCloud] setInputCloud is deprecated. Please use setInputSource instead.")
253  void
254  setInputCloud (const PointCloudConstPtr &cloud);
255 
256  /** \brief Get a pointer to the input point cloud dataset target. */
257  PCL_DEPRECATED ("[pcl::registration::DataContainer::getInputCloud] getInputCloud is deprecated. Please use getInputSource instead.")
258  PointCloudConstPtr const
259  getInputCloud ();
260 
261  /** \brief Provide a source point cloud dataset (must contain XYZ
262  * data!), used to compute the correspondence distance.
263  * \param[in] cloud a cloud containing XYZ data
264  */
265  inline void
266  setInputSource (const PointCloudConstPtr &cloud)
267  {
268  input_ = cloud;
269  }
270 
271  /** \brief Get a pointer to the input point cloud dataset target. */
272  inline PointCloudConstPtr const
273  getInputSource () { return (input_); }
274 
275  /** \brief Provide a target point cloud dataset (must contain XYZ
276  * data!), used to compute the correspondence distance.
277  * \param[in] target a cloud containing XYZ data
278  */
279  inline void
280  setInputTarget (const PointCloudConstPtr &target)
281  {
282  target_ = target;
283  target_cloud_updated_ = true;
284  }
285 
286  /** \brief Get a pointer to the input point cloud dataset target. */
287  inline PointCloudConstPtr const
288  getInputTarget () { return (target_); }
289 
290  /** \brief Provide a pointer to the search object used to find correspondences in
291  * the target cloud.
292  * \param[in] tree a pointer to the spatial search object.
293  * \param[in] force_no_recompute If set to true, this tree will NEVER be
294  * recomputed, regardless of calls to setInputTarget. Only use if you are
295  * confident that the tree will be set correctly.
296  */
297  inline void
298  setSearchMethodTarget (const KdTreePtr &tree,
299  bool force_no_recompute = false)
300  {
301  tree_ = tree;
302  if (force_no_recompute)
303  {
304  force_no_recompute_ = true;
305  }
306  target_cloud_updated_ = true;
307  }
308 
309  /** \brief Set the normals computed on the input point cloud
310  * \param[in] normals the normals computed for the input cloud
311  */
312  inline void
313  setInputNormals (const NormalsConstPtr &normals) { input_normals_ = normals; }
314 
315  /** \brief Get the normals computed on the input point cloud */
316  inline NormalsConstPtr
317  getInputNormals () { return (input_normals_); }
318 
319  /** \brief Set the normals computed on the target point cloud
320  * \param[in] normals the normals computed for the input cloud
321  */
322  inline void
323  setTargetNormals (const NormalsConstPtr &normals) { target_normals_ = normals; }
324 
325  /** \brief Get the normals computed on the target point cloud */
326  inline NormalsConstPtr
327  getTargetNormals () { return (target_normals_); }
328 
329  /** \brief Get the correspondence score for a point in the input cloud
330  * \param[in] index index of the point in the input cloud
331  */
332  inline double
334  {
335  if ( target_cloud_updated_ && !force_no_recompute_ )
336  {
337  tree_->setInputCloud (target_);
338  }
339  std::vector<int> indices (1);
340  std::vector<float> distances (1);
341  if (tree_->nearestKSearch (input_->points[index], 1, indices, distances))
342  return (distances[0]);
343  else
344  return (std::numeric_limits<double>::max ());
345  }
346 
347  /** \brief Get the correspondence score for a given pair of correspondent points
348  * \param[in] corr Correspondent points
349  */
350  inline double
352  {
353  // Get the source and the target feature from the list
354  const PointT &src = input_->points[corr.index_query];
355  const PointT &tgt = target_->points[corr.index_match];
356 
357  return ((src.getVector4fMap () - tgt.getVector4fMap ()).squaredNorm ());
358  }
359 
360  /** \brief Get the correspondence score for a given pair of correspondent points based on
361  * the angle betweeen the normals. The normmals for the in put and target clouds must be
362  * set before using this function
363  * \param[in] corr Correspondent points
364  */
365  inline double
367  {
368  //assert ( (input_normals_->points.size () != 0) && (target_normals_->points.size () != 0) && "Normals are not set for the input and target point clouds");
369  assert (input_normals_ && target_normals_ && "Normals are not set for the input and target point clouds");
370  const NormalT &src = input_normals_->points[corr.index_query];
371  const NormalT &tgt = target_normals_->points[corr.index_match];
372  return (double ((src.normal[0] * tgt.normal[0]) + (src.normal[1] * tgt.normal[1]) + (src.normal[2] * tgt.normal[2])));
373  }
374 
375  private:
376  /** \brief The input point cloud dataset */
377  PointCloudConstPtr input_;
378 
379  /** \brief The input transformed point cloud dataset */
380  PointCloudPtr input_transformed_;
381 
382  /** \brief The target point cloud datase. */
383  PointCloudConstPtr target_;
384 
385  /** \brief Normals to the input point cloud */
386  NormalsConstPtr input_normals_;
387 
388  /** \brief Normals to the input point cloud */
389  NormalsPtr input_normals_transformed_;
390 
391  /** \brief Normals to the target point cloud */
392  NormalsConstPtr target_normals_;
393 
394  /** \brief A pointer to the spatial search object. */
395  KdTreePtr tree_;
396 
397  /** \brief The name of the rejection method. */
398  std::string class_name_;
399 
400  /** \brief Should the current data container use normals? */
401  bool needs_normals_;
402 
403  /** \brief Variable that stores whether we have a new target cloud, meaning we need to pre-process it again.
404  * This way, we avoid rebuilding the kd-tree */
405  bool target_cloud_updated_;
406 
407  /** \brief A flag which, if set, means the tree operating on the target cloud
408  * will never be recomputed*/
409  bool force_no_recompute_;
410 
411 
412 
413  /** \brief Get a string representation of the name of this class. */
414  inline const std::string&
415  getClassName () const { return (class_name_); }
416  };
417  }
418 }
419 
420 #include <pcl/registration/impl/correspondence_rejection.hpp>
421 
422 #endif /* PCL_REGISTRATION_CORRESPONDENCE_REJECTION_H_ */
423