NASA Astrobee Robot Software  0.19.1
Flight software for the Astrobee robots operating inside the International Space Station.
organized_neighbor2_impl.h
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) 2010-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 the copyright holder(s) 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  * $Id$
37  *
38  */
39 
40 #ifndef POINT_CLOUD_COMMON_ORGANIZED_NEIGHBOR2_IMPL_H_
41 #define POINT_CLOUD_COMMON_ORGANIZED_NEIGHBOR2_IMPL_H_
42 
43 #include <pcl/search/organized.h>
44 #include <pcl/common/eigen.h>
45 #include <pcl/common/time.h>
46 #include <Eigen/Eigenvalues>
47 
48 #include <algorithm>
49 #include <limits>
50 #include <queue>
51 #include <vector>
52 
54 template <typename PointT>
55 int pcl::search::OrganizedNeighbor2<PointT>::radiusSearch(const PointT& query, const double radius,
56  std::vector<int>& k_indices,
57  std::vector<float>& k_sqr_distances,
58  unsigned int max_nn) const {
59  // NAN test
60  assert(isFinite(query) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
61 
62  // search window
63  unsigned left, right, top, bottom;
64  // unsigned x, y, idx;
65  float squared_distance;
66  double squared_radius;
67 
68  k_indices.clear();
69  k_sqr_distances.clear();
70 
71  squared_radius = radius * radius;
72 
73  this->getProjectedRadiusSearchBox(query, static_cast<float>(squared_radius), left, right, top, bottom);
74 
75  // iterate over search box
76  if (max_nn == 0 || max_nn >= static_cast<unsigned int>(input_->points.size()))
77  max_nn = static_cast<unsigned int>(input_->points.size());
78 
79  k_indices.reserve(max_nn);
80  k_sqr_distances.reserve(max_nn);
81 
82  unsigned yEnd = (bottom + 1) * input_->width + right + 1;
83  register unsigned idx = top * input_->width + left;
84  unsigned skip = input_->width - right + left - 1;
85  unsigned xEnd = idx - left + right + 1;
86 
87  for (; xEnd != yEnd; idx += skip, xEnd += input_->width) {
88  for (; idx < xEnd; ++idx) {
89  if (!mask_[idx] || !isFinite(input_->points[idx])) continue;
90 
91  float dist_x = input_->points[idx].x - query.x;
92  float dist_y = input_->points[idx].y - query.y;
93  float dist_z = input_->points[idx].z - query.z;
94  squared_distance = dist_x * dist_x + dist_y * dist_y + dist_z * dist_z;
95  // squared_distance = (input_->points[idx].getVector3fMap () - query.getVector3fMap ()).squaredNorm ();
96  if (squared_distance <= squared_radius) {
97  k_indices.push_back(idx);
98  k_sqr_distances.push_back(squared_distance);
99  // already done ?
100  if (k_indices.size() == max_nn) {
101  if (sorted_results_) this->sortResults(k_indices, k_sqr_distances);
102  return (max_nn);
103  }
104  }
105  }
106  }
107  if (sorted_results_) this->sortResults(k_indices, k_sqr_distances);
108  return (static_cast<int>(k_indices.size()));
109 }
110 
112 template <typename PointT>
113 int pcl::search::OrganizedNeighbor2<PointT>::nearestKSearch(const PointT& query, int k, std::vector<int>& k_indices,
114  std::vector<float>& k_sqr_distances) const {
115  assert(isFinite(query) && "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
116  if (k < 1) {
117  k_indices.clear();
118  k_sqr_distances.clear();
119  return (0);
120  }
121 
122  const Eigen::Vector3f queryvec(query.x, query.y, query.z);
123  // project query point on the image plane
124  const Eigen::Vector2f q = projectPoint(queryvec);
125  int xBegin = static_cast<int>(q[0] + 0.5f);
126  int yBegin = static_cast<int>(q[1] + 0.5f);
127  int xEnd = xBegin + 1; // end is the pixel that is not used anymore, like in iterators
128  int yEnd = yBegin + 1;
129 
130  // the search window. This is supposed to shrink within the iterations
131  unsigned left = 0;
132  unsigned right = input_->width - 1;
133  unsigned top = 0;
134  unsigned bottom = input_->height - 1;
135 
136  std::priority_queue<Entry> results;
137  // std::vector<Entry> k_results;
138  // k_results.reserve (k);
139  // add point laying on the projection of the query point.
140  if (xBegin >= 0 && xBegin < static_cast<int>(input_->width) && yBegin >= 0 &&
141  yBegin < static_cast<int>(input_->height)) {
142  testPoint(query, k, results, yBegin * input_->width + xBegin);
143  } else { // point lys
144  // find the box that touches the image border -> dont waste time evaluating boxes that are completely outside the
145  // image!
146  int dist = std::numeric_limits<int>::max();
147 
148  if (xBegin < 0)
149  dist = -xBegin;
150  else if (xBegin >= static_cast<int>(input_->width))
151  dist = xBegin - static_cast<int>(input_->width);
152 
153  if (yBegin < 0)
154  dist = std::min(dist, -yBegin);
155  else if (yBegin >= static_cast<int>(input_->height))
156  dist = std::min(dist, yBegin - static_cast<int>(input_->height));
157 
158  xBegin -= dist;
159  xEnd += dist;
160 
161  yBegin -= dist;
162  yEnd += dist;
163  }
164 
165  // stop used as isChanged as well as stop.
166  bool stop = false;
167  do {
168  // increment box size
169  --xBegin;
170  ++xEnd;
171  --yBegin;
172  ++yEnd;
173 
174  // the range in x-direction which intersects with the image width
175  int xFrom = xBegin;
176  int xTo = xEnd;
177  clipRange(xFrom, xTo, 0, input_->width);
178 
179  // if x-extend is not 0
180  if (xTo > xFrom) {
181  // if upper line of the rectangle is visible and x-extend is not 0
182  if (yBegin >= 0 && yBegin < static_cast<int>(input_->height)) {
183  int idx = yBegin * input_->width + xFrom;
184  int idxTo = idx + xTo - xFrom;
185  for (; idx < idxTo; ++idx) stop = testPoint(query, k, results, idx) || stop;
186  }
187 
188  // the row yEnd does NOT belong to the box -> last row = yEnd - 1
189  // if lower line of the rectangle is visible
190  if (yEnd > 0 && yEnd <= static_cast<int>(input_->height)) {
191  int idx = (yEnd - 1) * input_->width + xFrom;
192  int idxTo = idx + xTo - xFrom;
193 
194  for (; idx < idxTo; ++idx) stop = testPoint(query, k, results, idx) || stop;
195  }
196 
197  // skip first row and last row (already handled above)
198  int yFrom = yBegin + 1;
199  int yTo = yEnd - 1;
200  clipRange(yFrom, yTo, 0, input_->height);
201 
202  // if we have lines in between that are also visible
203  if (yFrom < yTo) {
204  if (xBegin >= 0 && xBegin < static_cast<int>(input_->width)) {
205  int idx = yFrom * input_->width + xBegin;
206  int idxTo = yTo * input_->width + xBegin;
207 
208  for (; idx < idxTo; idx += input_->width) stop = testPoint(query, k, results, idx) || stop;
209  }
210 
211  if (xEnd > 0 && xEnd <= static_cast<int>(input_->width)) {
212  int idx = yFrom * input_->width + xEnd - 1;
213  int idxTo = yTo * input_->width + xEnd - 1;
214 
215  for (; idx < idxTo; idx += input_->width) stop = testPoint(query, k, results, idx) || stop;
216  }
217  }
218  // stop here means that the k-nearest neighbor changed -> recalculate bounding box of ellipse.
219  if (stop) getProjectedRadiusSearchBox(query, results.top().distance, left, right, top, bottom);
220  }
221  // now we use it as stop flag -> if bounding box is completely within the already examined search box were done!
222  stop = (static_cast<int>(left) >= xBegin && static_cast<int>(left) < xEnd && static_cast<int>(right) >= xBegin &&
223  static_cast<int>(right) < xEnd && static_cast<int>(top) >= yBegin && static_cast<int>(top) < yEnd &&
224  static_cast<int>(bottom) >= yBegin && static_cast<int>(bottom) < yEnd);
225  } while (!stop);
226 
227  k_indices.resize(results.size());
228  k_sqr_distances.resize(results.size());
229  size_t idx = results.size() - 1;
230  while (!results.empty()) {
231  k_indices[idx] = results.top().index;
232  k_sqr_distances[idx] = results.top().distance;
233  results.pop();
234  --idx;
235  }
236 
237  return (static_cast<int>(k_indices.size()));
238 }
239 
241 template <typename PointT>
242 void pcl::search::OrganizedNeighbor2<PointT>::getProjectedRadiusSearchBox(const PointT& point, float squared_radius,
243  unsigned& minX, unsigned& maxX,
244  unsigned& minY, unsigned& maxY) const {
245  const Eigen::Vector3f queryvec(point.x, point.y, point.z);
246  const Eigen::Vector2f q = projectPoint(queryvec);
247 
248  float a = squared_radius * KR_KRT_.coeff(8) - q[2] * q[2];
249  float b = squared_radius * KR_KRT_.coeff(7) - q[1] * q[2];
250  float c = squared_radius * KR_KRT_.coeff(4) - q[1] * q[1];
251  int min, max;
252  // a and c are multiplied by two already => - 4ac -> - ac
253  float det = b * b - a * c;
254  if (det < 0) {
255  minY = 0;
256  maxY = input_->height - 1;
257  } else {
258  float y1 = static_cast<float>((b - sqrt(det)) / a);
259  float y2 = static_cast<float>((b + sqrt(det)) / a);
260 
261  min = std::min(static_cast<int>(floor(y1)), static_cast<int>(floor(y2)));
262  max = std::max(static_cast<int>(ceil(y1)), static_cast<int>(ceil(y2)));
263  minY = static_cast<unsigned>(std::min(static_cast<int>(input_->height) - 1, std::max(0, min)));
264  maxY = static_cast<unsigned>(std::max(std::min(static_cast<int>(input_->height) - 1, max), 0));
265  }
266 
267  b = squared_radius * KR_KRT_.coeff(6) - q[0] * q[2];
268  c = squared_radius * KR_KRT_.coeff(0) - q[0] * q[0];
269 
270  det = b * b - a * c;
271  if (det < 0) {
272  minX = 0;
273  maxX = input_->width - 1;
274  } else {
275  float x1 = static_cast<float>((b - sqrt(det)) / a);
276  float x2 = static_cast<float>((b + sqrt(det)) / a);
277 
278  min = std::min(static_cast<int>(floor(x1)), static_cast<int>(floor(x2)));
279  max = std::max(static_cast<int>(ceil(x1)), static_cast<int>(ceil(x2)));
280  minX = static_cast<unsigned>(std::min(static_cast<int>(input_->width) - 1, std::max(0, min)));
281  maxX = static_cast<unsigned>(std::max(std::min(static_cast<int>(input_->width) - 1, max), 0));
282  }
283 }
284 
286 template <typename PointT>
287 Eigen::Vector2f pcl::search::OrganizedNeighbor2<PointT>::projectPoint(const Eigen::Vector3f& point) const {
288  Eigen::Vector3f projected = intrinsics_matrix_ * point;
289  Eigen::Vector2f q;
290  q.x() = projected[0] / projected[2];
291  q.y() = projected[1] / projected[2];
292  return q;
293 }
294 #define PCL_INSTANTIATE_OrganizedNeighbor2(T) template class PCL_EXPORTS pcl::search::OrganizedNeighbor2<T>;
295 
296 #endif // POINT_CLOUD_COMMON_ORGANIZED_NEIGHBOR2_IMPL_H_
pcl::search::OrganizedNeighbor2::getProjectedRadiusSearchBox
void getProjectedRadiusSearchBox(const PointT &point, float squared_radius, unsigned &minX, unsigned &minY, unsigned &maxX, unsigned &maxY) const
Obtain a search box in 2D from a sphere with a radius in 3D.
Definition: organized_neighbor2_impl.h:242
pcl::search::OrganizedNeighbor2::nearestKSearch
int nearestKSearch(const PointT &p_q, int k, std::vector< int > &k_indices, std::vector< float > &k_sqr_distances) const
Search for the k-nearest neighbors for a given query point.
Definition: organized_neighbor2_impl.h:113
pcl::search::OrganizedNeighbor2::radiusSearch
int radiusSearch(const PointT &p_q, double radius, std::vector< int > &k_indices, std::vector< float > &k_sqr_distances, unsigned int max_nn=0) const
Search for all neighbors of query point that are within a given radius.
Definition: organized_neighbor2_impl.h:55
pcl::search::OrganizedNeighbor2::projectPoint
Eigen::Vector2f projectPoint(const Eigen::Vector3f &p) const
projects a point into the image
Definition: organized_neighbor2_impl.h:287