/* * Software License Agreement (BSD License) * * Point Cloud Library (PCL) - www.pointclouds.org * Copyright (c) 2010-2011, Willow Garage, Inc. * Copyright (c) 2012-, Open Perception, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #include #include #include #include #include #include // for copyPointCloud namespace pcl { namespace keypoints { namespace agast { /** \brief Abstract detector class for AGAST corner point detectors. * * Adapted from the C++ implementation of Elmar Mair * (http://www6.in.tum.de/Main/ResearchAgast). * * \author Stefan Holzer * \ingroup keypoints */ class PCL_EXPORTS AbstractAgastDetector { public: using Ptr = shared_ptr; using ConstPtr = shared_ptr; /** \brief Constructor. * \param[in] width the width of the image to process * \param[in] height the height of the image to process * \param[in] threshold the corner detection threshold * \param[in] bmax the max image value (default: 255) */ AbstractAgastDetector (const std::size_t width, const std::size_t height, const double threshold, const double bmax) : width_ (width) , height_ (height) , threshold_ (threshold) , nr_max_keypoints_ (std::numeric_limits::max ()) , bmax_ (bmax) {} /** \brief Destructor. */ virtual ~AbstractAgastDetector () {} /** \brief Detects corner points. * \param intensity_data * \param output */ void detectKeypoints (const std::vector &intensity_data, pcl::PointCloud &output) const; /** \brief Detects corner points. * \param intensity_data * \param output */ void detectKeypoints (const std::vector &intensity_data, pcl::PointCloud &output) const; /** \brief Applies non-max-suppression. * \param[in] intensity_data the image data * \param[in] input the keypoint positions * \param[out] output the resultant keypoints after non-max-supression */ void applyNonMaxSuppression (const std::vector& intensity_data, const pcl::PointCloud &input, pcl::PointCloud &output); /** \brief Applies non-max-suppression. * \param[in] intensity_data the image data * \param[in] input the keypoint positions * \param[out] output the resultant keypoints after non-max-supression */ void applyNonMaxSuppression (const std::vector& intensity_data, const pcl::PointCloud &input, pcl::PointCloud &output); /** \brief Computes corner score. * \param[in] im the pixels to compute the score at */ virtual int computeCornerScore (const unsigned char* im) const = 0; /** \brief Computes corner score. * \param[in] im the pixels to compute the score at */ virtual int computeCornerScore (const float* im) const = 0; /** \brief Sets the threshold for corner detection. * \param[in] threshold the threshold used for corner detection. */ inline void setThreshold (const double threshold) { threshold_ = threshold; } /** \brief Get the threshold for corner detection, as set by the user. */ inline double getThreshold () { return (threshold_); } /** \brief Sets the maximum number of keypoints to return. The * estimated keypoints are sorted by their internal score. * \param[in] nr_max_keypoints set the maximum number of keypoints to return */ inline void setMaxKeypoints (const unsigned int nr_max_keypoints) { nr_max_keypoints_ = nr_max_keypoints; } /** \brief Get the maximum number of keypoints to return, as set by the user. */ inline unsigned int getMaxKeypoints () { return (nr_max_keypoints_); } /** \brief Detects points of interest (i.e., keypoints) in the given image * \param[in] im the image to detect keypoints in * \param[out] corners_all the resultant set of keypoints detected */ virtual void detect (const unsigned char* im, std::vector > &corners_all) const = 0; /** \brief Detects points of interest (i.e., keypoints) in the given image * \param[in] im the image to detect keypoints in */ virtual void detect (const float* im, std::vector > &) const = 0; protected: /** \brief Structure holding an index and the associated keypoint score. */ struct ScoreIndex { int idx; int score; }; /** \brief Score index comparator. */ struct CompareScoreIndex { /** \brief Comparator * \param[in] i1 the first score index * \param[in] i2 the second score index */ inline bool operator() (const ScoreIndex &i1, const ScoreIndex &i2) { return (i1.score > i2.score); } }; /** \brief Initializes the sample pattern. */ virtual void initPattern () = 0; /** \brief Non-max-suppression helper method. * \param[in] input the keypoint positions * \param[in] scores the keypoint scores computed on the image data * \param[out] output the resultant keypoints after non-max-supression */ void applyNonMaxSuppression (const pcl::PointCloud &input, const std::vector& scores, pcl::PointCloud &output); /** \brief Computes corner scores for the specified points. * \param im * \param corners_all * \param scores */ void computeCornerScores (const unsigned char* im, const std::vector > & corners_all, std::vector & scores) const; /** \brief Computes corner scores for the specified points. * \param im * \param corners_all * \param scores */ void computeCornerScores (const float* im, const std::vector > & corners_all, std::vector & scores) const; /** \brief Width of the image to process. */ std::size_t width_; /** \brief Height of the image to process. */ std::size_t height_; /** \brief Threshold for corner detection. */ double threshold_; /** \brief The maximum number of keypoints to return. */ unsigned int nr_max_keypoints_; /** \brief Max image value. */ double bmax_; }; /** \brief Detector class for AGAST corner point detector (7_12s). * * Adapted from the C++ implementation of Elmar Mair * (http://www6.in.tum.de/Main/ResearchAgast). * * \author Stefan Holzer * \ingroup keypoints */ class PCL_EXPORTS AgastDetector7_12s : public AbstractAgastDetector { public: using Ptr = shared_ptr; using ConstPtr = shared_ptr; /** \brief Constructor. * \param[in] width the width of the image to process * \param[in] height the height of the image to process * \param[in] threshold the corner detection threshold * \param[in] bmax the max image value (default: 255) */ AgastDetector7_12s (const std::size_t width, const std::size_t height, const double threshold, const double bmax = 255) : AbstractAgastDetector (width, height, threshold, bmax) { initPattern (); } /** \brief Destructor. */ ~AgastDetector7_12s () {} /** \brief Computes corner score. * \param im */ int computeCornerScore (const unsigned char* im) const override; /** \brief Computes corner score. * \param im */ int computeCornerScore (const float* im) const override; /** \brief Detects points of interest (i.e., keypoints) in the given image * \param[in] im the image to detect keypoints in * \param[out] corners_all the resultant set of keypoints detected */ void detect (const unsigned char* im, std::vector > &corners_all) const override; /** \brief Detects points of interest (i.e., keypoints) in the given image * \param[in] im the image to detect keypoints in * \param[out] corners_all the resultant set of keypoints detected */ void detect (const float* im, std::vector > &corners_all) const override; protected: /** \brief Initializes the sample pattern. */ void initPattern () override; private: /** \brief Border width. */ static const int border_width_ = 2; // offsets defining the sample pattern std::array offset_; }; /** \brief Detector class for AGAST corner point detector (5_8). * * Adapted from the C++ implementation of Elmar Mair * (http://www6.in.tum.de/Main/ResearchAgast). * * \author Stefan Holzer * \ingroup keypoints */ class PCL_EXPORTS AgastDetector5_8 : public AbstractAgastDetector { public: using Ptr = shared_ptr; using ConstPtr = shared_ptr; /** \brief Constructor. * \param[in] width the width of the image to process * \param[in] height the height of the image to process * \param[in] threshold the corner detection threshold * \param[in] bmax the max image value (default: 255) */ AgastDetector5_8 (const std::size_t width, const std::size_t height, const double threshold, const double bmax = 255) : AbstractAgastDetector (width, height, threshold, bmax) { initPattern (); } /** \brief Destructor. */ ~AgastDetector5_8 () {} /** \brief Computes corner score. * \param im */ int computeCornerScore (const unsigned char* im) const override; /** \brief Computes corner score. * \param im */ int computeCornerScore (const float* im) const override; /** \brief Detects points of interest (i.e., keypoints) in the given image * \param[in] im the image to detect keypoints in * \param[out] corners_all the resultant set of keypoints detected */ void detect (const unsigned char* im, std::vector > &corners_all) const override; /** \brief Detects points of interest (i.e., keypoints) in the given image * \param[in] im the image to detect keypoints in * \param[out] corners_all the resultant set of keypoints detected */ void detect (const float* im, std::vector > &corners_all) const override; protected: /** \brief Initializes the sample pattern. */ void initPattern () override; private: /** \brief Border width. */ static const int border_width_ = 1; // offsets defining the sample pattern std::array offset_; }; /** \brief Detector class for AGAST corner point detector (OAST 9_16). * * Adapted from the C++ implementation of Elmar Mair * (http://www6.in.tum.de/Main/ResearchAgast). * * \author Stefan Holzer * \ingroup keypoints */ class PCL_EXPORTS OastDetector9_16 : public AbstractAgastDetector { public: using Ptr = shared_ptr; using ConstPtr = shared_ptr; /** \brief Constructor. * \param[in] width the width of the image to process * \param[in] height the height of the image to process * \param[in] threshold the corner detection threshold * \param[in] bmax the max image value (default: 255) */ OastDetector9_16 (const std::size_t width, const std::size_t height, const double threshold, const double bmax = 255) : AbstractAgastDetector (width, height, threshold, bmax) { initPattern (); } /** \brief Destructor. */ ~OastDetector9_16 () {} /** \brief Computes corner score. * \param im */ int computeCornerScore (const unsigned char* im) const override; /** \brief Computes corner score. * \param im */ int computeCornerScore (const float* im) const override; /** \brief Detects points of interest (i.e., keypoints) in the given image * \param[in] im the image to detect keypoints in * \param[out] corners_all the resultant set of keypoints detected */ void detect (const unsigned char* im, std::vector > &corners_all) const override; /** \brief Detects points of interest (i.e., keypoints) in the given image * \param[in] im the image to detect keypoints in * \param[out] corners_all the resultant set of keypoints detected */ void detect (const float* im, std::vector > &corners_all) const override; protected: /** \brief Initializes the sample pattern. */ void initPattern () override; private: /** \brief Border width. */ static const int border_width_ = 3; // offsets defining the sample pattern std::array offset_; }; } // namespace agast } // namespace keypoints ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// namespace keypoints { namespace internal { ///////////////////////////////////////////////////////////////////////////////////// template struct AgastApplyNonMaxSuppresion { AgastApplyNonMaxSuppresion ( const std::vector &image_data, const pcl::PointCloud &tmp_cloud, const pcl::keypoints::agast::AbstractAgastDetector::Ptr &detector, pcl::PointCloud &output) { pcl::PointCloud output_temp; detector->applyNonMaxSuppression (image_data, tmp_cloud, output_temp); pcl::copyPointCloud (output_temp, output); } }; ///////////////////////////////////////////////////////////////////////////////////// template <> struct AgastApplyNonMaxSuppresion { AgastApplyNonMaxSuppresion ( const std::vector &image_data, const pcl::PointCloud &tmp_cloud, const pcl::keypoints::agast::AbstractAgastDetector::Ptr &detector, pcl::PointCloud &output) { detector->applyNonMaxSuppression (image_data, tmp_cloud, output); } }; ///////////////////////////////////////////////////////////////////////////////////// template struct AgastDetector { AgastDetector ( const std::vector &image_data, const pcl::keypoints::agast::AbstractAgastDetector::Ptr &detector, pcl::PointCloud &output) { pcl::PointCloud output_temp; detector->detectKeypoints (image_data, output_temp); pcl::copyPointCloud (output_temp, output); } }; ///////////////////////////////////////////////////////////////////////////////////// template <> struct AgastDetector { AgastDetector ( const std::vector &image_data, const pcl::keypoints::agast::AbstractAgastDetector::Ptr &detector, pcl::PointCloud &output) { detector->detectKeypoints (image_data, output); } }; } // namespace agast } // namespace keypoints ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// /** \brief Detects 2D AGAST corner points. Based on the original work and * paper reference by * * \par * Elmar Mair, Gregory D. Hager, Darius Burschka, Michael Suppa, and Gerhard Hirzinger. * Adaptive and generic corner detection based on the accelerated segment test. * In Proceedings of the European Conference on Computer Vision (ECCV'10), September 2010. * * \note This is an abstract base class. All children must implement a detectKeypoints method, based on the type of AGAST keypoint to be used. * * \author Stefan Holzer, Radu B. Rusu * \ingroup keypoints */ template > class AgastKeypoint2DBase : public Keypoint { public: using PointCloudIn = typename Keypoint::PointCloudIn; using PointCloudOut = typename Keypoint::PointCloudOut; using KdTree = typename Keypoint::KdTree; using PointCloudInConstPtr = typename PointCloudIn::ConstPtr; using AgastDetectorPtr = pcl::keypoints::agast::AbstractAgastDetector::Ptr; using Keypoint::name_; using Keypoint::input_; using Keypoint::indices_; using Keypoint::k_; /** \brief Constructor */ AgastKeypoint2DBase () : threshold_ (10) , apply_non_max_suppression_ (true) , bmax_ (255) , nr_max_keypoints_ (std::numeric_limits::max ()) { k_ = 1; } /** \brief Destructor. */ ~AgastKeypoint2DBase () { } /** \brief Sets the threshold for corner detection. * \param[in] threshold the threshold used for corner detection. */ inline void setThreshold (const double threshold) { threshold_ = threshold; } /** \brief Get the threshold for corner detection, as set by the user. */ inline double getThreshold () { return (threshold_); } /** \brief Sets the maximum number of keypoints to return. The * estimated keypoints are sorted by their internal score. * \param[in] nr_max_keypoints set the maximum number of keypoints to return */ inline void setMaxKeypoints (const unsigned int nr_max_keypoints) { nr_max_keypoints_ = nr_max_keypoints; } /** \brief Get the maximum number of keypoints to return, as set by the user. */ inline unsigned int getMaxKeypoints () { return (nr_max_keypoints_); } /** \brief Sets the max image data value (affects how many iterations AGAST does) * \param[in] bmax the max image data value */ inline void setMaxDataValue (const double bmax) { bmax_ = bmax; } /** \brief Get the bmax image value, as set by the user. */ inline double getMaxDataValue () { return (bmax_); } /** \brief Sets whether non-max-suppression is applied or not. * \param[in] enabled determines whether non-max-suppression is enabled. */ inline void setNonMaxSuppression (const bool enabled) { apply_non_max_suppression_ = enabled; } /** \brief Returns whether non-max-suppression is applied or not. */ inline bool getNonMaxSuppression () { return (apply_non_max_suppression_); } inline void setAgastDetector (const AgastDetectorPtr &detector) { detector_ = detector; } inline AgastDetectorPtr getAgastDetector () { return (detector_); } protected: /** \brief Initializes everything and checks whether input data is fine. */ bool initCompute () override; /** \brief Detects the keypoints. * \param[out] output the resultant keypoints */ void detectKeypoints (PointCloudOut &output) override = 0; /** \brief Intensity field accessor. */ IntensityT intensity_; /** \brief Threshold for corner detection. */ double threshold_; /** \brief Determines whether non-max-suppression is activated. */ bool apply_non_max_suppression_; /** \brief Max image value. */ double bmax_; /** \brief The Agast detector to use. */ AgastDetectorPtr detector_; /** \brief The maximum number of keypoints to return. */ unsigned int nr_max_keypoints_; }; /** \brief Detects 2D AGAST corner points. Based on the original work and * paper reference by * * \par * Elmar Mair, Gregory D. Hager, Darius Burschka, Michael Suppa, and Gerhard Hirzinger. * Adaptive and generic corner detection based on the accelerated segment test. * In Proceedings of the European Conference on Computer Vision (ECCV'10), September 2010. * * Code example: * * \code * pcl::PointCloud cloud; * pcl::AgastKeypoint2D agast; * agast.setThreshold (30); * agast.setInputCloud (cloud); * * PointCloud keypoints; * agast.compute (keypoints); * \endcode * * \note The AGAST keypoint type used is 7_12s. * * \author Stefan Holzer, Radu B. Rusu * \ingroup keypoints */ template class AgastKeypoint2D : public AgastKeypoint2DBase > { public: using PointCloudOut = typename Keypoint::PointCloudOut; using Keypoint::name_; using Keypoint::input_; using Keypoint::indices_; using Keypoint::k_; using AgastKeypoint2DBase >::intensity_; using AgastKeypoint2DBase >::threshold_; using AgastKeypoint2DBase >::bmax_; using AgastKeypoint2DBase >::apply_non_max_suppression_; using AgastKeypoint2DBase >::detector_; using AgastKeypoint2DBase >::nr_max_keypoints_; /** \brief Constructor */ AgastKeypoint2D () { name_ = "AgastKeypoint2D"; } /** \brief Destructor. */ ~AgastKeypoint2D () { } protected: /** \brief Detects the keypoints. * \param[out] output the resultant keypoints */ void detectKeypoints (PointCloudOut &output) override; }; /** \brief Detects 2D AGAST corner points. Based on the original work and * paper reference by * * \par * Elmar Mair, Gregory D. Hager, Darius Burschka, Michael Suppa, and Gerhard Hirzinger. * Adaptive and generic corner detection based on the accelerated segment test. * In Proceedings of the European Conference on Computer Vision (ECCV'10), September 2010. * * Code example: * * \code * pcl::PointCloud cloud; * pcl::AgastKeypoint2D agast; * agast.setThreshold (30); * agast.setInputCloud (cloud); * * PointCloud keypoints; * agast.compute (keypoints); * \endcode * * \note This is a specialized version for PointXYZ clouds, and operates on depth (z) as float. The output keypoints are of the PointXY type. * \note The AGAST keypoint type used is 7_12s. * * \author Stefan Holzer, Radu B. Rusu * \ingroup keypoints */ template <> class AgastKeypoint2D : public AgastKeypoint2DBase > { public: /** \brief Constructor */ AgastKeypoint2D () { name_ = "AgastKeypoint2D"; bmax_ = 4; // max data value for an OpenNI camera } /** \brief Destructor. */ ~AgastKeypoint2D () { } protected: /** \brief Detects the keypoints. * \param[out] output the resultant keypoints */ void detectKeypoints (pcl::PointCloud &output) override; }; } #include