40 #ifndef PCL_SEARCH_IMPL_ORGANIZED_NEIGHBOR_SEARCH_H_
41 #define PCL_SEARCH_IMPL_ORGANIZED_NEIGHBOR_SEARCH_H_
46 #include <Eigen/Eigenvalues>
49 template<
typename Po
intT>
int
52 std::vector<int> &k_indices,
53 std::vector<float> &k_sqr_distances,
54 unsigned int max_nn)
const
57 assert (
isFinite (query) &&
"Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
60 unsigned left, right, top, bottom;
62 float squared_distance;
63 double squared_radius;
66 k_sqr_distances.clear ();
68 squared_radius = radius * radius;
70 this->getProjectedRadiusSearchBox (query, static_cast<float> (squared_radius), left, right, top, bottom);
73 if (max_nn == 0 || max_nn >= static_cast<unsigned int> (input_->points.size ()))
74 max_nn =
static_cast<unsigned int> (input_->points.size ());
76 k_indices.reserve (max_nn);
77 k_sqr_distances.reserve (max_nn);
79 unsigned yEnd = (bottom + 1) * input_->width + right + 1;
80 register unsigned idx = top * input_->width + left;
81 unsigned skip = input_->width - right + left - 1;
82 unsigned xEnd = idx - left + right + 1;
84 for (; xEnd != yEnd; idx += skip, xEnd += input_->width)
86 for (; idx < xEnd; ++idx)
88 if (!mask_[idx] || !
isFinite (input_->points[idx]))
91 squared_distance = (input_->points[idx].getVector3fMap () - query.getVector3fMap ()).squaredNorm ();
92 if (squared_distance <= squared_radius)
94 k_indices.push_back (idx);
95 k_sqr_distances.push_back (squared_distance);
97 if (k_indices.size () == max_nn)
100 this->sortResults (k_indices, k_sqr_distances);
107 this->sortResults (k_indices, k_sqr_distances);
108 return (static_cast<int> (k_indices.size ()));
112 template<
typename Po
intT>
int
115 std::vector<int> &k_indices,
116 std::vector<float> &k_sqr_distances)
const
118 assert (
isFinite (query) &&
"Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
122 k_sqr_distances.clear ();
127 Eigen::Vector3f q = KR_ * query.getVector3fMap () + projection_matrix_.block <3, 1> (0, 3);
128 int xBegin = int(q [0] / q [2] + 0.5f);
129 int yBegin = int(q [1] / q [2] + 0.5f);
130 int xEnd = xBegin + 1;
131 int yEnd = yBegin + 1;
135 unsigned right = input_->width - 1;
137 unsigned bottom = input_->height - 1;
139 std::priority_queue <Entry> results;
144 xBegin < static_cast<int> (input_->width) &&
146 yBegin < static_cast<int> (input_->height))
147 testPoint (query, k, results, yBegin * input_->width + xBegin);
151 int dist = std::numeric_limits<int>::max ();
155 else if (xBegin >= static_cast<int> (input_->width))
156 dist = xBegin -
static_cast<int> (input_->width);
159 dist = std::min (dist, -yBegin);
160 else if (yBegin >= static_cast<int> (input_->height))
161 dist = std::min (dist, yBegin - static_cast<int> (input_->height));
184 clipRange (xFrom, xTo, 0, input_->width);
190 if (yBegin >= 0 && yBegin < static_cast<int> (input_->height))
192 int idx = yBegin * input_->width + xFrom;
193 int idxTo = idx + xTo - xFrom;
194 for (; idx < idxTo; ++idx)
195 stop = testPoint (query, k, results, idx) || stop;
201 if (yEnd > 0 && yEnd <= static_cast<int> (input_->height))
203 int idx = (yEnd - 1) * input_->width + xFrom;
204 int idxTo = idx + xTo - xFrom;
206 for (; idx < idxTo; ++idx)
207 stop = testPoint (query, k, results, idx) || stop;
211 int yFrom = yBegin + 1;
213 clipRange (yFrom, yTo, 0, input_->height);
218 if (xBegin >= 0 && xBegin < static_cast<int> (input_->width))
220 int idx = yFrom * input_->width + xBegin;
221 int idxTo = yTo * input_->width + xBegin;
223 for (; idx < idxTo; idx += input_->width)
224 stop = testPoint (query, k, results, idx) || stop;
227 if (xEnd > 0 && xEnd <= static_cast<int> (input_->width))
229 int idx = yFrom * input_->width + xEnd - 1;
230 int idxTo = yTo * input_->width + xEnd - 1;
232 for (; idx < idxTo; idx += input_->width)
233 stop = testPoint (query, k, results, idx) || stop;
239 getProjectedRadiusSearchBox (query, results.top ().distance, left, right, top, bottom);
243 stop = (
static_cast<int> (left) >= xBegin && static_cast<int> (left) < xEnd &&
244 static_cast<int> (right) >= xBegin && static_cast<int> (right) < xEnd &&
245 static_cast<int> (top) >= yBegin && static_cast<int> (top) < yEnd &&
246 static_cast<int> (bottom) >= yBegin && static_cast<int> (bottom) < yEnd);
251 k_indices.resize (results.size ());
252 k_sqr_distances.resize (results.size ());
253 size_t idx = results.size () - 1;
254 while (!results.empty ())
256 k_indices [idx] = results.top ().index;
257 k_sqr_distances [idx] = results.top ().distance;
262 return (static_cast<int> (k_indices.size ()));
266 template<
typename Po
intT>
void
268 float squared_radius,
272 unsigned &maxY)
const
274 Eigen::Vector3f q = KR_ * point.getVector3fMap () + projection_matrix_.block <3, 1> (0, 3);
276 float a = squared_radius * KR_KRT_.coeff (8) - q [2] * q [2];
277 float b = squared_radius * KR_KRT_.coeff (7) - q [1] * q [2];
278 float c = squared_radius * KR_KRT_.coeff (4) - q [1] * q [1];
281 float det = b * b - a * c;
285 maxY = input_->height - 1;
289 float y1 = (b -
sqrt (det)) / a;
290 float y2 = (b +
sqrt (det)) / a;
292 min = std::min (static_cast<int> (floor (y1)), static_cast<int> (floor (y2)));
293 max = std::max (static_cast<int> (ceil (y1)), static_cast<int> (ceil (y2)));
294 minY =
static_cast<unsigned> (std::min (static_cast<int> (input_->height) - 1, std::max (0, min)));
295 maxY =
static_cast<unsigned> (std::max (std::min (static_cast<int> (input_->height) - 1, max), 0));
298 b = squared_radius * KR_KRT_.coeff (6) - q [0] * q [2];
299 c = squared_radius * KR_KRT_.coeff (0) - q [0] * q [0];
305 maxX = input_->width - 1;
309 float x1 = (b -
sqrt (det)) / a;
310 float x2 = (b +
sqrt (det)) / a;
312 min = std::min (static_cast<int> (floor (x1)), static_cast<int> (floor (x2)));
313 max = std::max (static_cast<int> (ceil (x1)), static_cast<int> (ceil (x2)));
314 minX =
static_cast<unsigned> (std::min (static_cast<int> (input_->width)- 1, std::max (0, min)));
315 maxX =
static_cast<unsigned> (std::max (std::min (static_cast<int> (input_->width) - 1, max), 0));
320 template<
typename Po
intT>
template <
typename MatrixType>
void
323 if (use_upper_triangular && (MatrixType::Flags & Eigen::RowMajorBit) )
325 matrix.coeffRef (4) = matrix.coeff (1);
326 matrix.coeffRef (8) = matrix.coeff (2);
327 matrix.coeffRef (9) = matrix.coeff (6);
328 matrix.coeffRef (12) = matrix.coeff (3);
329 matrix.coeffRef (13) = matrix.coeff (7);
330 matrix.coeffRef (14) = matrix.coeff (11);
334 matrix.coeffRef (1) = matrix.coeff (4);
335 matrix.coeffRef (2) = matrix.coeff (8);
336 matrix.coeffRef (6) = matrix.coeff (9);
337 matrix.coeffRef (3) = matrix.coeff (12);
338 matrix.coeffRef (7) = matrix.coeff (13);
339 matrix.coeffRef (11) = matrix.coeff (14);
344 template<
typename Po
intT>
void
347 Eigen::Matrix3f cam = KR_KRT_ / KR_KRT_.coeff (8);
349 memset (&(camera_matrix.coeffRef (0)), 0,
sizeof (Eigen::Matrix3f::Scalar) * 9);
350 camera_matrix.coeffRef (8) = 1.0;
352 if (camera_matrix.Flags & Eigen::RowMajorBit)
354 camera_matrix.coeffRef (2) = cam.coeff (2);
355 camera_matrix.coeffRef (5) = cam.coeff (5);
356 camera_matrix.coeffRef (4) =
sqrt (cam.coeff (4) - cam.coeff (5) * cam.coeff (5));
357 camera_matrix.coeffRef (1) = (cam.coeff (1) - cam.coeff (2) * cam.coeff (5)) / camera_matrix.coeff (4);
358 camera_matrix.coeffRef (0) =
sqrt (cam.coeff (0) - camera_matrix.coeff (1) * camera_matrix.coeff (1) - cam.coeff (2) * cam.coeff (2));
362 camera_matrix.coeffRef (6) = cam.coeff (2);
363 camera_matrix.coeffRef (7) = cam.coeff (5);
364 camera_matrix.coeffRef (4) =
sqrt (cam.coeff (4) - cam.coeff (5) * cam.coeff (5));
365 camera_matrix.coeffRef (3) = (cam.coeff (1) - cam.coeff (2) * cam.coeff (5)) / camera_matrix.coeff (4);
366 camera_matrix.coeffRef (0) =
sqrt (cam.coeff (0) - camera_matrix.coeff (3) * camera_matrix.coeff (3) - cam.coeff (2) * cam.coeff (2));
371 template<
typename Po
intT>
void
375 typedef double Scalar;
376 projection_matrix_.setZero ();
377 if (input_->height == 1 || input_->width == 1)
379 PCL_ERROR (
"[pcl::%s::estimateProjectionMatrix] Input dataset is not organized!\n", this->getName ().c_str ());
383 const unsigned ySkip = (input_->height >> pyramid_level_);
384 const unsigned xSkip = (input_->width >> pyramid_level_);
385 Eigen::Matrix<Scalar, 4, 4, Eigen::RowMajor> A = Eigen::Matrix<Scalar, 4, 4, Eigen::RowMajor>::Zero ();
386 Eigen::Matrix<Scalar, 4, 4, Eigen::RowMajor>
B = Eigen::Matrix<Scalar, 4, 4, Eigen::RowMajor>::Zero ();
387 Eigen::Matrix<Scalar, 4, 4, Eigen::RowMajor> C = Eigen::Matrix<Scalar, 4, 4, Eigen::RowMajor>::Zero ();
388 Eigen::Matrix<Scalar, 4, 4, Eigen::RowMajor> D = Eigen::Matrix<Scalar, 4, 4, Eigen::RowMajor>::Zero ();
390 for (
unsigned yIdx = 0, idx = 0; yIdx < input_->height; yIdx += ySkip, idx += input_->width * (ySkip - 1))
392 for (
unsigned xIdx = 0; xIdx < input_->width; xIdx += xSkip, idx += xSkip)
397 const PointT& point = input_->points[idx];
400 Scalar xx = point.x * point.x;
401 Scalar xy = point.x * point.y;
402 Scalar xz = point.x * point.z;
403 Scalar yy = point.y * point.y;
404 Scalar yz = point.y * point.z;
405 Scalar zz = point.z * point.z;
406 Scalar xx_yy = xIdx * xIdx + yIdx * yIdx;
408 A.coeffRef (0) += xx;
409 A.coeffRef (1) += xy;
410 A.coeffRef (2) += xz;
411 A.coeffRef (3) += point.x;
413 A.coeffRef (5) += yy;
414 A.coeffRef (6) += yz;
415 A.coeffRef (7) += point.y;
417 A.coeffRef (10) += zz;
418 A.coeffRef (11) += point.z;
419 A.coeffRef (15) += 1.0;
421 B.coeffRef (0) -= xx * xIdx;
422 B.coeffRef (1) -= xy * xIdx;
423 B.coeffRef (2) -= xz * xIdx;
424 B.coeffRef (3) -= point.x *
static_cast<double>(xIdx);
426 B.coeffRef (5) -= yy * xIdx;
427 B.coeffRef (6) -= yz * xIdx;
428 B.coeffRef (7) -= point.y *
static_cast<double>(xIdx);
430 B.coeffRef (10) -= zz * xIdx;
431 B.coeffRef (11) -= point.z *
static_cast<double>(xIdx);
433 B.coeffRef (15) -= xIdx;
435 C.coeffRef (0) -= xx * yIdx;
436 C.coeffRef (1) -= xy * yIdx;
437 C.coeffRef (2) -= xz * yIdx;
438 C.coeffRef (3) -= point.x *
static_cast<double>(yIdx);
440 C.coeffRef (5) -= yy * yIdx;
441 C.coeffRef (6) -= yz * yIdx;
442 C.coeffRef (7) -= point.y *
static_cast<double>(yIdx);
444 C.coeffRef (10) -= zz * yIdx;
445 C.coeffRef (11) -= point.z *
static_cast<double>(yIdx);
447 C.coeffRef (15) -= yIdx;
449 D.coeffRef (0) += xx * xx_yy;
450 D.coeffRef (1) += xy * xx_yy;
451 D.coeffRef (2) += xz * xx_yy;
452 D.coeffRef (3) += point.x * xx_yy;
454 D.coeffRef (5) += yy * xx_yy;
455 D.coeffRef (6) += yz * xx_yy;
456 D.coeffRef (7) += point.y * xx_yy;
458 D.coeffRef (10) += zz * xx_yy;
459 D.coeffRef (11) += point.z * xx_yy;
461 D.coeffRef (15) += xx_yy;
471 Eigen::Matrix<Scalar, 12, 12, Eigen::RowMajor> X = Eigen::Matrix<Scalar, 12, 12, Eigen::RowMajor>::Zero ();
472 X.topLeftCorner<4,4> () = A;
473 X.block<4,4> (0, 8) = B;
474 X.block<4,4> (8, 0) = B;
475 X.block<4,4> (4, 4) = A;
476 X.block<4,4> (4, 8) = C;
477 X.block<4,4> (8, 4) = C;
478 X.block<4,4> (8, 8) = D;
480 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<Scalar, 12, 12, Eigen::RowMajor> > ei_symm(X);
481 Eigen::Matrix<Scalar, 12, 12, Eigen::RowMajor> eigen_vectors = ei_symm.eigenvectors();
484 Eigen::Matrix<Scalar, 1, 1> residual_sqr = eigen_vectors.col (0).transpose () * X * eigen_vectors.col (0);
485 if ( fabs (residual_sqr.coeff (0)) > eps_ * A.coeff (15))
487 PCL_ERROR (
"[pcl::%s::radiusSearch] Input dataset is not from a projective device!\nResidual (MSE) %f, using %d valid points\n", this->getName ().c_str (), residual_sqr.coeff (0) / A.coeff (15),
static_cast<int> (A.coeff (15)));
491 projection_matrix_.coeffRef (0) = static_cast <
float> (eigen_vectors.coeff (0));
492 projection_matrix_.coeffRef (1) = static_cast <
float> (eigen_vectors.coeff (12));
493 projection_matrix_.coeffRef (2) = static_cast <
float> (eigen_vectors.coeff (24));
494 projection_matrix_.coeffRef (3) = static_cast <
float> (eigen_vectors.coeff (36));
495 projection_matrix_.coeffRef (4) = static_cast <
float> (eigen_vectors.coeff (48));
496 projection_matrix_.coeffRef (5) = static_cast <
float> (eigen_vectors.coeff (60));
497 projection_matrix_.coeffRef (6) = static_cast <
float> (eigen_vectors.coeff (72));
498 projection_matrix_.coeffRef (7) = static_cast <
float> (eigen_vectors.coeff (84));
499 projection_matrix_.coeffRef (8) = static_cast <
float> (eigen_vectors.coeff (96));
500 projection_matrix_.coeffRef (9) = static_cast <
float> (eigen_vectors.coeff (108));
501 projection_matrix_.coeffRef (10) = static_cast <
float> (eigen_vectors.coeff (120));
502 projection_matrix_.coeffRef (11) = static_cast <
float> (eigen_vectors.coeff (132));
504 if (projection_matrix_.coeff (0) < 0)
505 projection_matrix_ *= -1.0;
509 KR_ = projection_matrix_.topLeftCorner <3, 3> ();
512 KR_KRT_ = KR_ * KR_.transpose ();
516 template<
typename Po
intT>
bool
519 Eigen::Vector3f projected = KR_ * point.getVector3fMap () + projection_matrix_.block <3, 1> (0, 3);
520 q.
x = projected [0] / projected [2];
521 q.
y = projected [1] / projected [2];
522 return (projected[2] != 0);
524 #define PCL_INSTANTIATE_OrganizedNeighbor(T) template class PCL_EXPORTS pcl::search::OrganizedNeighbor<T>;