1 /*
2  * Software License Agreement (BSD License)
3  *
4  *  Copyright (c) 2010, Willow Garage, Inc.
5  *  All rights reserved.
6  *
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions
9  *  are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *   * Neither the name of Willow Garage, Inc. nor the names of its
18  *     contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  *  POSSIBILITY OF SUCH DAMAGE.
33  *
34  */
35 
36 /* \author Bastian Steder */
37 
38 #pragma once
39 
40 #include <pcl/memory.h>
41 #include <pcl/pcl_macros.h>
42 #include <pcl/point_cloud.h>
43 #include <pcl/point_types.h>
44 #include <pcl/keypoints/keypoint.h>
45 
46 namespace pcl {
47 
48 // Forward declarations
49 class RangeImage;
50 class RangeImageBorderExtractor;
51 
52 /** \brief @b NARF (Normal Aligned Radial Feature) keypoints. Input is a range image,
53   *           output the indices of the keypoints
54   * See B. Steder, R. B. Rusu, K. Konolige, and W. Burgard
55   *     Point Feature Extraction on 3D Range Scans Taking into Account Object Boundaries
56   *     In Proc. of the IEEE Int. Conf. on Robotics &Automation (ICRA). 2011.
57   * \author Bastian Steder
58   * \ingroup keypoints
59   */
60 class PCL_EXPORTS NarfKeypoint : public Keypoint<PointWithRange, int>
61 {
62   public:
63     using Ptr = shared_ptr<NarfKeypoint>;
64     using ConstPtr = shared_ptr<const NarfKeypoint>;
65 
66     // =====TYPEDEFS=====
67     using BaseClass = Keypoint<PointWithRange, int>;
68 
69     using PointCloudOut = Keypoint<PointWithRange, int>::PointCloudOut;
70 
71     // =====PUBLIC STRUCTS=====
72     //! Parameters used in this class
73     struct Parameters
74     {
ParametersParameters75       Parameters() : support_size(-1.0f), max_no_of_interest_points(-1), min_distance_between_interest_points(0.25f),
76                      optimal_distance_to_high_surface_change(0.25), min_interest_value(0.45f),
77                      min_surface_change_score(0.2f), optimal_range_image_patch_size(10),
78                      distance_for_additional_points(0.0f), add_points_on_straight_edges(false),
79                      do_non_maximum_suppression(true), no_of_polynomial_approximations_per_point(false),
80                      max_no_of_threads(1), use_recursive_scale_reduction(false),
81                      calculate_sparse_interest_image(true) {}
82 
83       float support_size;  //!< This defines the area 'covered' by an interest point (in meters)
84       int max_no_of_interest_points;  //!< The maximum number of interest points that will be returned
85       float min_distance_between_interest_points;  /**< Minimum distance between maximas
86                                                      *  (this is a factor for support_size, i.e. the distance is
87                                                      *  min_distance_between_interest_points*support_size) */
88       float optimal_distance_to_high_surface_change;  /**< The distance we want keep between keypoints and areas
89                                                         *  of high surface change
90                                                         *  (this is a factor for support_size, i.e., the distance is
91                                                         *  optimal_distance_to_high_surface_change*support_size) */
92       float min_interest_value;  //!< The minimum value to consider a point as an interest point
93       float min_surface_change_score;  //!< The minimum value  of the surface change score to consider a point
94       int optimal_range_image_patch_size;  /**< The size (in pixels) of the image patches from which the interest value
95                                              *  should be computed. This influences, which range image is selected from
96                                              *  the scale space to compute the interest value of a pixel at a certain
97                                              *  distance. */
98       // TODO:
99       float distance_for_additional_points;  /**< All points in this distance to a found maximum, that
100                                                *  are above min_interest_value are also added as interest points
101                                                *  (this is a factor for support_size, i.e. the distance is
102                                                *  distance_for_additional_points*support_size) */
103       bool add_points_on_straight_edges;  /**< If this is set to true, there will also be interest points on
104                                             *   straight edges, e.g., just indicating an area of high surface change */
105       bool do_non_maximum_suppression;  /**< If this is set to false there will be much more points
106                                           *  (can be used to spread points over the whole scene
107                                           *  (combined with a low min_interest_value)) */
108       bool no_of_polynomial_approximations_per_point; /**< If this is >0, the exact position of the interest point is
109                                                            determined using bivariate polynomial approximations of the
110                                                            interest values of the area. */
111       int max_no_of_threads;  //!< The maximum number of threads this code is allowed to use with OPNEMP
112       bool use_recursive_scale_reduction;  /**< Try to decrease runtime by extracting interest points at lower reolution
113                                              *  in areas that contain enough points, i.e., have lower range. */
114       bool calculate_sparse_interest_image;  /**< Use some heuristics to decide which areas of the interest image
115                                                   can be left out to improve the runtime. */
116     };
117 
118     // =====CONSTRUCTOR & DESTRUCTOR=====
119     NarfKeypoint (RangeImageBorderExtractor* range_image_border_extractor=nullptr, float support_size=-1.0f);
120     ~NarfKeypoint ();
121 
122     // =====PUBLIC METHODS=====
123     //! Erase all data calculated for the current range image
124     void
125       clearData ();
126 
127     //! Set the RangeImageBorderExtractor member (required)
128     void
129       setRangeImageBorderExtractor (RangeImageBorderExtractor* range_image_border_extractor);
130 
131     //! Get the RangeImageBorderExtractor member
132     RangeImageBorderExtractor*
getRangeImageBorderExtractor()133       getRangeImageBorderExtractor ()  { return range_image_border_extractor_; }
134 
135     //! Set the RangeImage member of the RangeImageBorderExtractor
136     void
137       setRangeImage (const RangeImage* range_image);
138 
139     /** Extract interest value per image point */
140     float*
getInterestImage()141       getInterestImage () { calculateInterestImage(); return interest_image_;}
142 
143     //! Extract maxima from an interest image
144     const ::pcl::PointCloud<InterestPoint>&
getInterestPoints()145       getInterestPoints () { calculateInterestPoints(); return *interest_points_;}
146 
147     //! Set all points in the image that are interest points to true, the rest to false
148     const std::vector<bool>&
getIsInterestPointImage()149       getIsInterestPointImage () { calculateInterestPoints(); return is_interest_point_image_;}
150 
151     //! Getter for the parameter struct
152     Parameters&
getParameters()153       getParameters () { return parameters_;}
154 
155     //! Getter for the range image of range_image_border_extractor_
156     const RangeImage&
157       getRangeImage ();
158 
159     //! Overwrite the compute function of the base class
160     void
161       compute (PointCloudOut& output);
162 
163   protected:
164     // =====PROTECTED METHODS=====
165     void
166       calculateScaleSpace ();
167     void
168       calculateInterestImage ();
169     void
170       calculateCompleteInterestImage ();
171     void
172       calculateSparseInterestImage ();
173     void
174       calculateInterestPoints ();
175     //void
176       //blurInterestImage ();
177     //! Detect key points
178     void
179       detectKeypoints (PointCloudOut& output) override;
180 
181     // =====PROTECTED MEMBER VARIABLES=====
182     using BaseClass::name_;
183     RangeImageBorderExtractor* range_image_border_extractor_;
184     Parameters parameters_;
185     float* interest_image_;
186     ::pcl::PointCloud<InterestPoint>* interest_points_;
187     std::vector<bool> is_interest_point_image_;
188     std::vector<RangeImage*> range_image_scale_space_;
189     std::vector<RangeImageBorderExtractor*> border_extractor_scale_space_;
190     std::vector<float*> interest_image_scale_space_;
191 };
192 
193 /**
194   * \ingroup keypoints
195   */
196 inline std::ostream&
197   operator << (std::ostream& os, const NarfKeypoint::Parameters& p)
198 {
199   os << PVARC(p.support_size) << PVARC(p.min_distance_between_interest_points)
200      << PVARC(p.min_interest_value) << PVARN(p.distance_for_additional_points);
201   return (os);
202 }
203 
204 }  // end namespace pcl
205