Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
normal_space.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2009-2011, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 #ifndef PCL_FILTERS_IMPL_NORMAL_SPACE_SAMPLE_H_
39 #define PCL_FILTERS_IMPL_NORMAL_SPACE_SAMPLE_H_
40 
42 
43 #include <vector>
44 #include <list>
45 
47 template<typename PointT, typename NormalT> void
49 {
50  // If sample size is 0 or if the sample size is greater then input cloud size
51  // then return entire copy of cloud
52  if (sample_ >= input_->size ())
53  {
54  output = *input_;
55  return;
56  }
57 
58  // Resize output cloud to sample size
59  output.points.resize (sample_);
60  output.width = sample_;
61  output.height = 1;
62 
63  // allocate memory for the histogram of normals.. Normals will then be sampled from each bin..
64  unsigned int n_bins = binsx_ * binsy_ * binsz_;
65  // list<int> holds the indices of points in that bin.. Using list to avoid repeated resizing of vectors.. Helps when the point cloud is
66  // large..
67  std::vector< std::list <int> > normals_hg;
68  normals_hg.reserve (n_bins);
69  for (unsigned int i = 0; i < n_bins; i++)
70  normals_hg.push_back (std::list<int> ());
71 
72  for (unsigned int i = 0; i < input_normals_->points.size (); i++)
73  {
74  unsigned int bin_number = findBin (input_normals_->points[i].normal, n_bins);
75  normals_hg[bin_number].push_back (i);
76  }
77 
78  // Setting up random access for the list created above.. Maintaining the iterators to individual elements of the list in a vector.. Using
79  // vector now as the size of the list is known..
80  std::vector< std::vector <std::list<int>::iterator> > random_access (normals_hg.size ());
81  for (unsigned int i = 0; i < normals_hg.size (); i++)
82  {
83  random_access.push_back (std::vector< std::list<int>::iterator> ());
84  random_access[i].resize (normals_hg[i].size ());
85 
86  unsigned int j=0;
87  for (std::list<int>::iterator itr = normals_hg[i].begin (); itr != normals_hg[i].end (); itr++, j++)
88  {
89  random_access[i][j] = itr;
90  }
91  }
92  unsigned int* start_index = new unsigned int[normals_hg.size ()];
93  start_index[0] = 0;
94  unsigned int prev_index = start_index[0];
95  for (unsigned int i = 1; i < normals_hg.size (); i++)
96  {
97  start_index[i] = prev_index + static_cast<unsigned int> (normals_hg[i-1].size ());
98  prev_index = start_index[i];
99  }
100 
101  // maintaining flags to check if a point is sampled
102  boost::dynamic_bitset<> is_sampled_flag (input_normals_->points.size ());
103  // maintaining flags to check if all points in the bin are sampled
104  boost::dynamic_bitset<> bin_empty_flag (normals_hg.size ());
105  unsigned int i = 0;
106  while (i < sample_)
107  {
108  // iterating through every bin and picking one point at random, until the required number of points are sampled..
109  for (unsigned int j = 0; j < normals_hg.size (); j++)
110  {
111  unsigned int M = static_cast<unsigned int> (normals_hg[j].size ());
112  if (M == 0 || bin_empty_flag.test (j))// bin_empty_flag(i) is set if all points in that bin are sampled..
113  {
114  continue;
115  }
116 
117  unsigned int pos = 0;
118  unsigned int random_index = 0;
119  //picking up a sample at random from jth bin
120  do
121  {
122  random_index = std::rand () % M;
123  pos = start_index[j] + random_index;
124  } while (is_sampled_flag.test (pos));
125 
126  is_sampled_flag.flip (start_index[j] + random_index);
127 
128  // checking if all points in bin j are sampled..
129  if (isEntireBinSampled (is_sampled_flag, start_index[j], static_cast<unsigned int> (normals_hg[j].size ())))
130  {
131  bin_empty_flag.flip (j);
132  }
133 
134  unsigned int index = *(random_access[j][random_index]);
135  output.points[i] = input_->points[index];
136  i++;
137  if (i == sample_)
138  {
139  break;
140  }
141  }
142  }
143  delete[] start_index;
144 }
145 
147 template<typename PointT, typename NormalT> bool
148 pcl::NormalSpaceSampling<PointT, NormalT>::isEntireBinSampled (boost::dynamic_bitset<> &array, unsigned int start_index, unsigned int length)
149 {
150  bool status = true;
151  for (unsigned int i = start_index; i < start_index + length; i++)
152  {
153  status = status & array.test (i);
154  }
155  return status;
156 }
157 
159 template<typename PointT, typename NormalT> unsigned int
160 pcl::NormalSpaceSampling<PointT, NormalT>::findBin (float *normal, unsigned int)
161 {
162  unsigned int bin_number = 0;
163  // holds the bin numbers for direction cosines in x,y,z directions
164  unsigned int t[3] = {0,0,0};
165 
166  // dcos is the direction cosine.
167  float dcos = 0.0;
168  float bin_size = 0.0;
169  // max_cos and min_cos are the maximum and minimum values of cos(theta) respectively
170  float max_cos = 1.0;
171  float min_cos = -1.0;
172 
173  dcos = cosf (normal[0]);
174  bin_size = (max_cos - min_cos) / static_cast<float> (binsx_);
175 
176  // finding bin number for direction cosine in x direction
177  unsigned int k = 0;
178  for (float i = min_cos; (i + bin_size) < (max_cos - bin_size); i += bin_size , k++)
179  {
180  if (dcos >= i && dcos <= (i+bin_size))
181  {
182  break;
183  }
184  }
185  t[0] = k;
186 
187  dcos = cosf (normal[1]);
188  bin_size = (max_cos - min_cos) / static_cast<float> (binsy_);
189 
190  // finding bin number for direction cosine in y direction
191  k = 0;
192  for (float i = min_cos; (i + bin_size) < (max_cos - bin_size); i += bin_size , k++)
193  {
194  if (dcos >= i && dcos <= (i+bin_size))
195  {
196  break;
197  }
198  }
199  t[1] = k;
200 
201  dcos = cosf (normal[2]);
202  bin_size = (max_cos - min_cos) / static_cast<float> (binsz_);
203 
204  // finding bin number for direction cosine in z direction
205  k = 0;
206  for (float i = min_cos; (i + bin_size) < (max_cos - bin_size); i += bin_size , k++)
207  {
208  if (dcos >= i && dcos <= (i+bin_size))
209  {
210  break;
211  }
212  }
213  t[2] = k;
214 
215  bin_number = t[0] * (binsy_*binsz_) + t[1] * binsz_ + t[2];
216  return bin_number;
217 }
218 
220 template<typename PointT, typename NormalT>
221 void
223 {
224  // If sample size is 0 or if the sample size is greater then input cloud size
225  // then return all indices
226  if (sample_ >= input_->width * input_->height)
227  {
228  indices = *indices_;
229  return;
230  }
231 
232  // Resize output indices to sample size
233  indices.resize (sample_);
234 
235  // allocate memory for the histogram of normals.. Normals will then be sampled from each bin..
236  unsigned int n_bins = binsx_ * binsy_ * binsz_;
237  // list<int> holds the indices of points in that bin.. Using list to avoid repeated resizing of vectors.. Helps when the point cloud is
238  // large..
239  std::vector< std::list <int> > normals_hg;
240  normals_hg.reserve (n_bins);
241  for (unsigned int i = 0; i < n_bins; i++)
242  normals_hg.push_back (std::list<int> ());
243 
244  for (unsigned int i=0; i < input_normals_->points.size (); i++)
245  {
246  unsigned int bin_number = findBin (input_normals_->points[i].normal, n_bins);
247  normals_hg[bin_number].push_back (i);
248  }
249 
250  // Setting up random access for the list created above.. Maintaining the iterators to individual elements of the list in a vector.. Using
251  // vector now as the size of the list is known..
252  std::vector< std::vector <std::list<int>::iterator> > random_access (normals_hg.size ());
253  for (unsigned int i = 0; i < normals_hg.size (); i++)
254  {
255  random_access.push_back (std::vector<std::list<int>::iterator> ());
256  random_access[i].resize (normals_hg[i].size ());
257 
258  unsigned int j = 0;
259  for (std::list<int>::iterator itr = normals_hg[i].begin (); itr != normals_hg[i].end (); itr++, j++)
260  {
261  random_access[i][j] = itr;
262  }
263  }
264  unsigned int* start_index = new unsigned int[normals_hg.size ()];
265  start_index[0] = 0;
266  unsigned int prev_index = start_index[0];
267  for (unsigned int i = 1; i < normals_hg.size (); i++)
268  {
269  start_index[i] = prev_index + static_cast<unsigned int> (normals_hg[i-1].size ());
270  prev_index = start_index[i];
271  }
272 
273  // maintaining flags to check if a point is sampled
274  boost::dynamic_bitset<> is_sampled_flag (input_normals_->points.size ());
275  // maintaining flags to check if all points in the bin are sampled
276  boost::dynamic_bitset<> bin_empty_flag (normals_hg.size ());
277  unsigned int i=0;
278  while (i < sample_)
279  {
280  // iterating through every bin and picking one point at random, until the required number of points are sampled..
281  for (unsigned int j = 0; j < normals_hg.size (); j++)
282  {
283  unsigned int M = static_cast<unsigned int> (normals_hg[j].size ());
284  if (M==0 || bin_empty_flag.test (j)) // bin_empty_flag(i) is set if all points in that bin are sampled..
285  {
286  continue;
287  }
288 
289  unsigned int pos = 0;
290  unsigned int random_index = 0;
291 
292  //picking up a sample at random from jth bin
293  do
294  {
295  random_index = std::rand () % M;
296  pos = start_index[j] + random_index;
297  } while (is_sampled_flag.test (pos));
298 
299  is_sampled_flag.flip (start_index[j] + random_index);
300 
301  // checking if all points in bin j are sampled..
302  if (isEntireBinSampled (is_sampled_flag, start_index[j], static_cast<unsigned int> (normals_hg[j].size ())))
303  {
304  bin_empty_flag.flip (j);
305  }
306 
307  unsigned int index = *(random_access[j][random_index]);
308  indices[i] = index;
309  i++;
310  if (i == sample_)
311  {
312  break;
313  }
314  }
315  }
316  delete[] start_index;
317 }
318 
319 #define PCL_INSTANTIATE_NormalSpaceSampling(T,NT) template class PCL_EXPORTS pcl::NormalSpaceSampling<T,NT>;
320 
321 #endif // PCL_FILTERS_IMPL_NORMAL_SPACE_SAMPLE_H_