4747
4848namespace pcl
4949{
50- /* *
51- * \brief ShapeContext3DEstimation implements the 3D shape context descriptor
52- * based on Frome et al. (ECCV 2004).
53- *
54- * Notes:
55- * - The suggested PointOutT is pcl::ShapeContext1980 (fixed-length descriptor).
56- * - PCL requires one descriptor per input point and descriptors to be a fixed length.
57- * - The original paper suggests multiple azimuth rotations (L rotations). That approach
58- * would expand descriptor length to descriptor_length_ * azimuth_bins_, which breaks
59- * PCL assumptions (fixed size and one-to-one mapping). Therefore the implementation
60- * below uses a deterministic azimuth normalization (shift) that keeps the descriptor
61- * length unchanged while removing the randomness introduced by the random local X axis.
62- */
50+ /* * \brief ShapeContext3DEstimation implements the 3D shape context descriptor as
51+ * described in:
52+ * - Andrea Frome, Daniel Huber, Ravi Kolluri and Thomas Bülow, Jitendra Malik
53+ * Recognizing Objects in Range Data Using Regional Point Descriptors,
54+ * In proceedings of the 8th European Conference on Computer Vision (ECCV),
55+ * Prague, May 11-14, 2004
56+ *
57+ * The suggested PointOutT is pcl::ShapeContext1980
58+ *
59+ * \attention
60+ * The convention for a 3D shape context descriptor is:
61+ * - if a query point's nearest neighbors cannot be estimated, the feature descriptor will be set to NaN (not a number), and the RF to 0
62+ * - it is impossible to estimate a 3D shape context descriptor for a
63+ * point that doesn't have finite 3D coordinates. Therefore, any point
64+ * that contains NaN data on x, y, or z, will have its boundary feature
65+ * property set to NaN.
66+ *
67+ * \author Alessandro Franchi, Samuele Salti, Federico Tombari (original code)
68+ * \author Nizar Sallem (port to PCL)
69+ * \ingroup features
70+ */
6371 template <typename PointInT, typename PointNT, typename PointOutT = pcl::ShapeContext1980>
6472 class ShapeContext3DEstimation : public FeatureFromNormals <PointInT, PointNT, PointOutT>
6573 {
@@ -82,19 +90,20 @@ namespace pcl
8290
8391 /* * \brief Constructor.
8492 * \param[in] random If true the random seed is set to current time, else it is
85- * set to 12345 prior to computing the descriptor (used to select X axis).
93+ * set to 12345 prior to computing the descriptor (used to select X axis)
8694 */
8795 ShapeContext3DEstimation (bool random = false ) :
8896 radii_interval_ (0 ),
8997 theta_divisions_ (0 ),
9098 phi_divisions_ (0 ),
9199 volume_lut_ (0 ),
100+
92101 rng_dist_ (0 .0f , 1 .0f )
93102 {
94103 feature_name_ = " ShapeContext3DEstimation" ;
95104 search_radius_ = 2.5 ;
96105
97- // Initialize RNG: deterministic by default (helps reproducible testing)
106+ // Create a random number generator object
98107 if (random)
99108 {
100109 std::random_device rd;
@@ -106,78 +115,123 @@ namespace pcl
106115
107116 ~ShapeContext3DEstimation () override = default ;
108117
118+ // inline void
119+ // setAzimuthBins (std::size_t bins) { azimuth_bins_ = bins; }
120+
109121 /* * \return the number of bins along the azimuth */
110- inline std::size_t getAzimuthBins () { return (azimuth_bins_); }
122+ inline std::size_t
123+ getAzimuthBins () { return (azimuth_bins_); }
124+
125+ // inline void
126+ // setElevationBins (std::size_t bins) { elevation_bins_ = bins; }
111127
112128 /* * \return The number of bins along the elevation */
113- inline std::size_t getElevationBins () { return (elevation_bins_); }
129+ inline std::size_t
130+ getElevationBins () { return (elevation_bins_); }
131+
132+ // inline void
133+ // setRadiusBins (std::size_t bins) { radius_bins_ = bins; }
114134
115135 /* * \return The number of bins along the radii direction */
116- inline std::size_t getRadiusBins () { return (radius_bins_); }
136+ inline std::size_t
137+ getRadiusBins () { return (radius_bins_); }
117138
118- inline void setMinimalRadius (double radius) { min_radius_ = radius; }
119- inline double getMinimalRadius () { return (min_radius_); }
139+ /* * \brief The minimal radius value for the search sphere (rmin) in the original paper
140+ * \param[in] radius the desired minimal radius
141+ */
142+ inline void
143+ setMinimalRadius (double radius) { min_radius_ = radius; }
144+
145+ /* * \return The minimal sphere radius */
146+ inline double
147+ getMinimalRadius () { return (min_radius_); }
120148
121- inline void setPointDensityRadius (double radius) { point_density_radius_ = radius; }
122- inline double getPointDensityRadius () { return (point_density_radius_); }
149+ /* * \brief This radius is used to compute local point density
150+ * density = number of points within this radius
151+ * \param[in] radius value of the point density search radius
152+ */
153+ inline void
154+ setPointDensityRadius (double radius) { point_density_radius_ = radius; }
155+
156+ /* * \return The point density search radius */
157+ inline double
158+ getPointDensityRadius () { return (point_density_radius_); }
123159
124160 protected:
125- /* * Initialize internal tables (radii intervals, angular divisions, volume LUT). */
126- bool initCompute () override ;
127-
128- /* *
129- * Estimate a descriptor for a given point.
130- * - index: point index to estimate descriptor for
131- * - normals: normals used (precomputed)
132- * - rf: output reference frame (3x3 stored in rf[9]); 3DSC does not define repeatable RF so we set rf=0
133- * - desc: output descriptor (must be descriptor_length_)
134- */
135- bool computePoint (std::size_t index, const pcl::PointCloud<PointNT> &normals, float rf[9 ], std::vector<float > &desc);
161+ /* * \brief Initialize computation by allocating all the intervals and the volume lookup table. */
162+ bool
163+ initCompute () override ;
164+
165+ /* * \brief Estimate a descriptor for a given point.
166+ * \param[in] index the index of the point to estimate a descriptor for
167+ * \param[in] normals a pointer to the set of normals
168+ * \param[out] rf the reference frame
169+ * \param[out] desc the resultant estimated descriptor
170+ * \return true if the descriptor was computed successfully, false if there was an error
171+ * (e.g. the nearest neighbor didn't return any neighbors)
172+ */
173+ bool
174+ computePoint (std::size_t index, const pcl::PointCloud<PointNT> &normals, float rf[9 ], std::vector<float > &desc);
136175
137- /* * Compute feature for all indices (fills output cloud). */
138- void computeFeature (PointCloudOut &output) override ;
176+ /* * \brief Estimate the actual feature.
177+ * \param[out] output the resultant feature
178+ */
179+ void
180+ computeFeature (PointCloudOut &output) override ;
139181
140- /* Lookup / intermediate data */
182+ /* * \brief Values of the radii interval */
141183 std::vector<float > radii_interval_;
184+
185+ /* * \brief Theta divisions interval */
142186 std::vector<float > theta_divisions_;
187+
188+ /* * \brief Phi divisions interval */
143189 std::vector<float > phi_divisions_;
190+
191+ /* * \brief Volumes look up table */
144192 std::vector<float > volume_lut_;
145193
146- /* Histogram bin configuration (defaults chosen to match ShapeContext1980) */
194+ /* * \brief Bins along the azimuth dimension */
147195 std::size_t azimuth_bins_{12 };
196+
197+ /* * \brief Bins along the elevation dimension */
148198 std::size_t elevation_bins_{11 };
199+
200+ /* * \brief Bins along the radius dimension */
149201 std::size_t radius_bins_{15 };
150202
151- /* Parameters */
203+ /* * \brief Minimal radius value */
152204 double min_radius_{0.1 };
205+
206+ /* * \brief Point density radius */
153207 double point_density_radius_{0.2 };
208+
209+ /* * \brief Descriptor length */
154210 std::size_t descriptor_length_{};
155211
156- /* RNG for random local x-axis selection */
212+ /* * \brief Random number generator algorithm. */
157213 std::mt19937 rng_;
158- std::uniform_real_distribution<float > rng_dist_;
159214
160- /* Old (commented) API for L-rotation approach left in file for history; we DO NOT use it.
161- * //void shiftAlongAzimuth (std::size_t block_size, std::vector<float>& desc);
162- */
215+ /* * \brief Random number generator distribution. */
216+ std::uniform_real_distribution<float > rng_dist_;
163217
164- /* *
165- * Our deterministic azimuth normalization:
166- * Rotate azimuth bins so that the azimuth block with the largest accumulated
167- * energy becomes the first block (index 0). This removes randomness introduced
168- * by the local random X axis selection while preserving a fixed descriptor length.
169- *
170- * - Input: desc (size == descriptor_length_)
171- * - Output: desc is circularly shifted in-place so that the dominant azimuth block
172- * is aligned to the start of the descriptor array.
218+ /* \brief Shift computed descriptor "L" times along the azimuthal direction
219+ * \param[in] block_size the size of each azimuthal block
220+ * \param[in] desc at input desc == original descriptor and on output it contains
221+ * shifted descriptor resized descriptor_length_ * azimuth_bins_
173222 */
174- void shiftAlongAzimuth (std::vector<float >& desc) const ;
223+ // void
224+ // shiftAlongAzimuth (std::size_t block_size, std::vector<float>& desc);
175225
176- /* * Return a random float in [0,1) using the internal RNG. */
177- inline float rnd () { return (rng_dist_ (rng_)); }
226+ /* * \brief Boost-based random number generator. */
227+ inline float
228+ rnd ()
229+ {
230+ return (rng_dist_ (rng_));
231+ }
178232 };
179233}
180234
181235#ifdef PCL_NO_PRECOMPILE
182236#include < pcl/features/impl/3dsc.hpp>
183- #endif
237+ #endif
0 commit comments