Skip to content

Commit 5e0cb7d

Browse files
Merge pull request #3862 from SergioRAgostinho/normalspace
NormalSpaceSampling - fix bucket assignment, remove use of raw distribution pointer, unit-test rewriting
2 parents 727712c + e490001 commit 5e0cb7d

File tree

3 files changed

+47
-97
lines changed

3 files changed

+47
-97
lines changed

filters/include/pcl/filters/impl/normal_space.hpp

Lines changed: 11 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,7 @@ pcl::NormalSpaceSampling<PointT, NormalT>::initCompute ()
5959
return false;
6060
}
6161

62-
boost::mt19937 rng (static_cast<unsigned int> (seed_));
63-
boost::uniform_int<unsigned int> uniform_distrib (0, unsigned (input_->size ()));
64-
delete rng_uniform_distribution_;
65-
rng_uniform_distribution_ = new boost::variate_generator<boost::mt19937, boost::uniform_int<unsigned int> > (rng, uniform_distrib);
66-
62+
rng_.seed (seed_);
6763
return (true);
6864
}
6965

@@ -83,66 +79,12 @@ pcl::NormalSpaceSampling<PointT, NormalT>::isEntireBinSampled (boost::dynamic_bi
8379

8480
///////////////////////////////////////////////////////////////////////////////
8581
template<typename PointT, typename NormalT> unsigned int
86-
pcl::NormalSpaceSampling<PointT, NormalT>::findBin (const float *normal, unsigned int)
82+
pcl::NormalSpaceSampling<PointT, NormalT>::findBin (const float *normal)
8783
{
88-
unsigned int bin_number = 0;
89-
// Holds the bin numbers for direction cosines in x,y,z directions
90-
unsigned int t[3] = {0,0,0};
91-
92-
// dcos is the direction cosine.
93-
float dcos = 0.0;
94-
float bin_size = 0.0;
95-
// max_cos and min_cos are the maximum and minimum values of std::cos(theta) respectively
96-
float max_cos = 1.0;
97-
float min_cos = -1.0;
98-
99-
// dcos = std::cos (normal[0]);
100-
dcos = normal[0];
101-
bin_size = (max_cos - min_cos) / static_cast<float> (binsx_);
102-
103-
// Finding bin number for direction cosine in x direction
104-
unsigned int k = 0;
105-
for (float i = min_cos; (i + bin_size) < (max_cos - bin_size); i += bin_size , k++)
106-
{
107-
if (dcos >= i && dcos <= (i+bin_size))
108-
{
109-
break;
110-
}
111-
}
112-
t[0] = k;
113-
114-
// dcos = std::cos (normal[1]);
115-
dcos = normal[1];
116-
bin_size = (max_cos - min_cos) / static_cast<float> (binsy_);
117-
118-
// Finding bin number for direction cosine in y direction
119-
k = 0;
120-
for (float i = min_cos; (i + bin_size) < (max_cos - bin_size); i += bin_size , k++)
121-
{
122-
if (dcos >= i && dcos <= (i+bin_size))
123-
{
124-
break;
125-
}
126-
}
127-
t[1] = k;
128-
129-
// dcos = std::cos (normal[2]);
130-
dcos = normal[2];
131-
bin_size = (max_cos - min_cos) / static_cast<float> (binsz_);
132-
133-
// Finding bin number for direction cosine in z direction
134-
k = 0;
135-
for (float i = min_cos; (i + bin_size) < (max_cos - bin_size); i += bin_size , k++)
136-
{
137-
if (dcos >= i && dcos <= (i+bin_size))
138-
{
139-
break;
140-
}
141-
}
142-
t[2] = k;
143-
144-
bin_number = t[0] * (binsy_*binsz_) + t[1] * binsz_ + t[2];
145-
return bin_number;
84+
const unsigned ix = static_cast<unsigned> (std::round (0.5f * (binsx_ - 1.f) * (normal[0] + 1.f)));
85+
const unsigned iy = static_cast<unsigned> (std::round (0.5f * (binsy_ - 1.f) * (normal[1] + 1.f)));
86+
const unsigned iz = static_cast<unsigned> (std::round (0.5f * (binsz_ - 1.f) * (normal[2] + 1.f)));
87+
return ix * (binsy_*binsz_) + iy * binsz_ + iz;
14688
}
14789

14890
///////////////////////////////////////////////////////////////////////////////
@@ -169,10 +111,10 @@ pcl::NormalSpaceSampling<PointT, NormalT>::applyFilter (std::vector<int> &indice
169111
for (unsigned int i = 0; i < n_bins; i++)
170112
normals_hg.emplace_back();
171113

172-
for (std::vector<int>::const_iterator it = indices_->begin (); it != indices_->end (); ++it)
114+
for (const auto index : *indices_)
173115
{
174-
unsigned int bin_number = findBin (input_normals_->points[*it].normal, n_bins);
175-
normals_hg[bin_number].push_back (*it);
116+
unsigned int bin_number = findBin ((*input_normals_)[index].normal);
117+
normals_hg[bin_number].push_back (index);
176118
}
177119

178120

@@ -213,11 +155,12 @@ pcl::NormalSpaceSampling<PointT, NormalT>::applyFilter (std::vector<int> &indice
213155

214156
unsigned int pos = 0;
215157
unsigned int random_index = 0;
158+
std::uniform_int_distribution<unsigned> rng_uniform_distribution (0u, M - 1u);
216159

217160
// Picking up a sample at random from jth bin
218161
do
219162
{
220-
random_index = static_cast<unsigned int> ((*rng_uniform_distribution_) () % M);
163+
random_index = rng_uniform_distribution (rng_);
221164
pos = start_index[j] + random_index;
222165
} while (is_sampled_flag.test (pos));
223166

filters/include/pcl/filters/normal_space.h

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939

4040
#include <pcl/filters/boost.h>
4141
#include <pcl/filters/filter_indices.h>
42+
4243
#include <ctime>
4344
#include <climits>
45+
#include <random> // std::mt19937
4446

4547
namespace pcl
4648
{
@@ -77,17 +79,10 @@ namespace pcl
7779
, binsy_ ()
7880
, binsz_ ()
7981
, input_normals_ ()
80-
, rng_uniform_distribution_ (nullptr)
8182
{
8283
filter_name_ = "NormalSpaceSampling";
8384
}
8485

85-
/** \brief Destructor. */
86-
~NormalSpaceSampling ()
87-
{
88-
delete rng_uniform_distribution_;
89-
}
90-
9186
/** \brief Set number of indices to be sampled.
9287
* \param[in] sample the number of sample indices
9388
*/
@@ -176,10 +171,9 @@ namespace pcl
176171
private:
177172
/** \brief Finds the bin number of the input normal, returns the bin number
178173
* \param[in] normal the input normal
179-
* \param[in] nbins total number of bins
180174
*/
181175
unsigned int
182-
findBin (const float *normal, unsigned int nbins);
176+
findBin (const float *normal);
183177

184178
/** \brief Checks of the entire bin is sampled, returns true or false
185179
* \param[out] array flag which says whether a point is sampled or not
@@ -189,8 +183,8 @@ namespace pcl
189183
bool
190184
isEntireBinSampled (boost::dynamic_bitset<> &array, unsigned int start_index, unsigned int length);
191185

192-
/** \brief Uniform random distribution. */
193-
boost::variate_generator<boost::mt19937, boost::uniform_int<std::uint32_t> > *rng_uniform_distribution_;
186+
/** \brief Random engine */
187+
std::mt19937 rng_;
194188
};
195189
}
196190

test/filters/test_sampling.cpp

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -105,31 +105,44 @@ TEST (CovarianceSampling, Filters)
105105
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
106106
TEST (NormalSpaceSampling, Filters)
107107
{
108+
// pcl::Normal is not precompiled by default so we use PointNormal
109+
auto cloud = pcl::make_shared<PointCloud<PointNormal>> ();
110+
// generate 16 points (8 unique) with unit norm
111+
cloud->reserve (16);
112+
// ensure that the normals have unit norm
113+
const auto value = std::sqrt(1/3.f);
114+
for (int unique = 0; unique < 8; ++unique) {
115+
const auto i = ((unique % 2) < 1) ? -1 : 1; // points alternate sign
116+
const auto j = ((unique % 4) < 2) ? -1 : 1; // 2 points negative, 2 positive
117+
const auto k = ((unique % 8) < 4) ? -1 : 1; // first 4 points negative, rest positive
118+
for (int duplicate = 0; duplicate < 2; ++duplicate) {
119+
cloud->emplace_back (0.f, 0.f, 0.f, i * value, j * value, k * value);
120+
}
121+
}
122+
108123
NormalSpaceSampling<PointNormal, PointNormal> normal_space_sampling;
109-
normal_space_sampling.setInputCloud (cloud_walls_normals);
110-
normal_space_sampling.setNormals (cloud_walls_normals);
111-
normal_space_sampling.setBins (4, 4, 4);
124+
normal_space_sampling.setInputCloud (cloud);
125+
normal_space_sampling.setNormals (cloud);
126+
normal_space_sampling.setBins (2, 2, 2);
112127
normal_space_sampling.setSeed (0);
113-
normal_space_sampling.setSample (static_cast<unsigned int> (cloud_walls_normals->size ()) / 4);
128+
normal_space_sampling.setSample (8);
114129

115-
IndicesPtr walls_indices (new std::vector<int> ());
130+
IndicesPtr walls_indices = pcl::make_shared<Indices> ();
116131
normal_space_sampling.filter (*walls_indices);
117132

118-
CovarianceSampling<PointNormal, PointNormal> covariance_sampling;
119-
covariance_sampling.setInputCloud (cloud_walls_normals);
120-
covariance_sampling.setNormals (cloud_walls_normals);
121-
covariance_sampling.setIndices (walls_indices);
122-
covariance_sampling.setNumberOfSamples (0);
123-
double cond_num_walls_sampled = covariance_sampling.computeConditionNumber ();
124-
133+
// The orientation space of the normals is divided into 2x2x2 buckets
134+
// points are samples arbitrarily from each bucket in succession until the
135+
// requested number of samples is met. This means we expect to see only one index
136+
// for every two elements in the original array e.g. 0, 3, 4, 6, etc...
137+
// if 0 is sampled, index 1 can no longer be there and so forth
138+
std::array<std::set<index_t>, 8> buckets;
139+
for (const auto index : *walls_indices)
140+
buckets[index/2].insert (index);
125141

126-
EXPECT_NEAR (33.04893, cond_num_walls_sampled, 1e-1);
127142

128-
EXPECT_EQ (1412, (*walls_indices)[0]);
129-
EXPECT_EQ (1943, (*walls_indices)[walls_indices->size () / 4]);
130-
EXPECT_EQ (2771, (*walls_indices)[walls_indices->size () / 2]);
131-
EXPECT_EQ (3215, (*walls_indices)[walls_indices->size () * 3 / 4]);
132-
EXPECT_EQ (2503, (*walls_indices)[walls_indices->size () - 1]);
143+
EXPECT_EQ (8u, walls_indices->size ());
144+
for (const auto& bucket : buckets)
145+
EXPECT_EQ (1u, bucket.size ());
133146
}
134147

135148
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)