Apollo  6.0
Open source self driving car software
voxel_grid_covariance_hdmap.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2017 The Apollo Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16 
17 /*
18  * Software License Agreement (BSD License)
19  *
20  * Point Cloud Library (PCL) - www.pointclouds.org
21  * Copyright (c) 2010-2011, Willow Garage, Inc.
22  * Copyright (c) 2012-, Open Perception, Inc.
23  *
24  * All rights reserved.
25  *
26  * Redistribution and use in source and binary forms, with or without
27  * modification, are permitted provided that the following conditions
28  * are met:
29  *
30  * * Redistributions of source code must retain the above copyright
31  * notice, this list of conditions and the following disclaimer.
32  * * Redistributions in binary form must reproduce the above
33  * copyright notice, this list of conditions and the following
34  * disclaimer in the documentation and/or other materials provided
35  * with the distribution.
36  * * Neither the name of the copyright holder(s) nor the names of its
37  * contributors may be used to endorse or promote products derived
38  * from this software without specific prior written permission.
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
43  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
44  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
45  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
46  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
48  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
50  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
51  * POSSIBILITY OF SUCH DAMAGE.
52  *
53  * $Id$
54  *
55  */
56 
57 #pragma once
58 
59 #include <cmath> // for std::isfinite
60 #include <limits>
61 #include <map>
62 #include <vector>
63 
64 #include "pcl/common/common.h"
65 #include "pcl/filters/voxel_grid.h"
66 #include "pcl/kdtree/kdtree_flann.h"
67 
68 namespace apollo {
69 namespace localization {
70 namespace msf {
71 
72 template <typename PointT>
73 class VoxelGridCovariance : public pcl::VoxelGrid<PointT> {
74  public:
75  enum LeafType { FEW, BAD, PLANE, LINE };
76 
77  protected:
78  using pcl::VoxelGrid<PointT>::filter_name_;
79  using pcl::VoxelGrid<PointT>::getClassName;
80  using pcl::VoxelGrid<PointT>::input_;
81  using pcl::VoxelGrid<PointT>::indices_;
82  using pcl::VoxelGrid<PointT>::filter_limit_negative_;
83  using pcl::VoxelGrid<PointT>::filter_limit_min_;
84  using pcl::VoxelGrid<PointT>::filter_limit_max_;
85  using pcl::VoxelGrid<PointT>::filter_field_name_;
86 
87  using pcl::VoxelGrid<PointT>::downsample_all_data_;
88  using pcl::VoxelGrid<PointT>::leaf_layout_;
89  using pcl::VoxelGrid<PointT>::save_leaf_layout_;
90  using pcl::VoxelGrid<PointT>::leaf_size_;
91  using pcl::VoxelGrid<PointT>::min_b_;
92  using pcl::VoxelGrid<PointT>::max_b_;
93  using pcl::VoxelGrid<PointT>::inverse_leaf_size_;
94  using pcl::VoxelGrid<PointT>::div_b_;
95  using pcl::VoxelGrid<PointT>::divb_mul_;
96 
97  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
98  typedef typename pcl::PointCloud<PointT> PointCloud;
99  typedef typename PointCloud::Ptr PointCloudPtr;
100  typedef typename PointCloud::ConstPtr PointCloudConstPtr;
101 
102  public:
103  typedef boost::shared_ptr<pcl::VoxelGrid<PointT>> Ptr;
104  typedef boost::shared_ptr<const pcl::VoxelGrid<PointT>> ConstPtr;
105 
106  struct Leaf {
107  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
109  : nr_points_(0),
110  mean_(Eigen::Vector3d::Zero()),
111  centroid(),
112  cov_(Eigen::Matrix3d::Identity()),
113  icov_(Eigen::Matrix3d::Zero()),
114  evecs_(Eigen::Matrix3d::Identity()),
115  evals_(Eigen::Vector3d::Zero()) {}
116 
117  // Get the voxel covariance.
118  Eigen::Matrix3d GetCov() const { return cov_; }
119 
120  // Get the inverse of the voxel covariance.
121  Eigen::Matrix3d GetInverseCov() const { return icov_; }
122 
123  // Get the voxel centroid.
124  Eigen::Vector3d GetMean() const { return mean_; }
125 
126  // Get the eigen vectors of the voxel covariance.
127  Eigen::Matrix3d GetEvecs() const { return evecs_; }
128 
129  // Get the eigen values of the voxel covariance.
130  Eigen::Vector3d GetEvals() const { return evals_; }
131 
132  // Get the number of points contained by this voxel.
133  int GetPointCount() const { return nr_points_; }
134 
135  // Number of points contained by voxel.
137 
138  // 3D voxel centroid.
140 
141  // voxel centroid.
142  Eigen::VectorXf centroid;
143 
144  // Voxel covariance matrix.
146 
147  // Inverse of voxel covariance matrix.
149 
150  // Eigen vectors of voxel covariance matrix.
152 
153  // Eigen values of voxel covariance matrix.
155 
156  pcl::PointCloud<PointT> cloud_;
158  };
159  // Pointer to VoxelGridCovariance leaf structure.
160  typedef Leaf* LeafPtr;
161  // Const pointer to VoxelGridCovariance leaf structure.
162  typedef const Leaf* LeafConstPtr;
163 
164  public:
166  : searchable_(true),
167  min_points_per_voxel_(6),
168  min_covar_eigvalue_mult_(0.01),
169  leaves_(),
170  voxel_centroids_(),
171  voxel_centroidsleaf_indices_(),
172  kdtree_() {
173  downsample_all_data_ = false;
174  save_leaf_layout_ = false;
175  leaf_size_.setZero();
176  min_b_.setZero();
177  max_b_.setZero();
178  filter_name_ = "VoxelGridCovariance";
179  }
180 
181  // Set the minimum number of points required for a cell.
182  inline void SetMinPointPerVoxel(int min_points_per_voxel) {
183  if (min_points_per_voxel > 2) {
184  min_points_per_voxel_ = min_points_per_voxel;
185  } else {
186  PCL_WARN("%s, Covariance need 3 pts, set min_pt_per_vexel to 3",
187  this->getClassName().c_str());
188  min_points_per_voxel_ = 3;
189  }
190  }
191 
192  // Get the minimum number of points required for a cell to be used.
193  inline int GetMinPointPerVoxel() { return min_points_per_voxel_; }
194 
195  // Set the minimum allowable ratio for eigenvalues
196  inline void SetCovEigValueInflationRatio(double min_covar_eigvalue_mult) {
197  min_covar_eigvalue_mult_ = min_covar_eigvalue_mult;
198  }
199  // Get the minimum allowable ratio
201  return min_covar_eigvalue_mult_;
202  }
203 
204  // Filter cloud and initializes voxel structure.
205  inline void Filter(PointCloudPtr output, bool searchable = false) {
206  searchable_ = searchable;
207  ApplyFilter(output);
208  voxel_centroids_ = PointCloudPtr(new PointCloud(*output));
209  if (searchable_ && voxel_centroids_->size() > 0) {
210  kdtree_.setInputCloud(voxel_centroids_);
211  }
212  }
213 
214  // Initializes voxel structure.
215  inline void Filter(bool searchable = false) {
216  searchable_ = searchable;
217  voxel_centroids_ = PointCloudPtr(new PointCloud);
218  ApplyFilter(voxel_centroids_);
219  if (searchable_ && voxel_centroids_->size() > 0) {
220  kdtree_.setInputCloud(voxel_centroids_);
221  }
222  }
223 
224  // Get the voxel containing point p.
225  inline LeafConstPtr GetLeaf(int index) {
226  typename std::map<size_t, Leaf>::iterator leaf_iter = leaves_.find(index);
227  if (leaf_iter != leaves_.end()) {
228  LeafConstPtr ret(&(leaf_iter->second));
229  return ret;
230  } else {
231  return nullptr;
232  }
233  }
234 
235  // Get the voxel containing point p.
236  inline LeafConstPtr GetLeaf(const PointT& p) {
237  // Generate index associated with p
238  int ijk0 = static_cast<int>(floor(p.x * inverse_leaf_size_[0]) - min_b_[0]);
239  int ijk1 = static_cast<int>(floor(p.y * inverse_leaf_size_[1]) - min_b_[1]);
240  int ijk2 = static_cast<int>(floor(p.z * inverse_leaf_size_[2]) - min_b_[2]);
241 
242  // Compute the centroid leaf index
243  int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
244 
245  // Find leaf associated with index
246  typename std::map<size_t, Leaf>::iterator leaf_iter = leaves_.find(idx);
247  if (leaf_iter != leaves_.end()) {
248  // If such a leaf exists return the pointer to the leaf structure
249  LeafConstPtr ret(&(leaf_iter->second));
250  return ret;
251  } else {
252  return nullptr;
253  }
254  }
255 
256  // Get the voxel containing point p.
257  inline LeafConstPtr GetLeaf(const Eigen::Vector3f& p) {
258  // Generate index associated with p
259  int ijk0 =
260  static_cast<int>(floor(p[0] * inverse_leaf_size_[0]) - min_b_[0]);
261  int ijk1 =
262  static_cast<int>(floor(p[1] * inverse_leaf_size_[1]) - min_b_[1]);
263  int ijk2 =
264  static_cast<int>(floor(p[2] * inverse_leaf_size_[2]) - min_b_[2]);
265 
266  // Compute the centroid leaf index
267  int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
268 
269  // Find leaf associated with index
270  typename std::map<size_t, Leaf>::iterator leaf_iter = leaves_.find(idx);
271  if (leaf_iter != leaves_.end()) {
272  // If such a leaf exists return the pointer to the leaf structure
273  LeafConstPtr ret(&(leaf_iter->second));
274  return ret;
275  } else {
276  return nullptr;
277  }
278  }
279 
280  // Get the leaf structure map.
281  inline std::map<size_t, Leaf>& GetLeaves() { return leaves_; }
282 
283  private:
284  // Filter cloud and initializes voxel structure.
285  void ApplyFilter(PointCloudPtr output) {
286  voxel_centroidsleaf_indices_.clear();
287 
288  // Has the input dataset been set already?
289  if (!input_) {
290  PCL_WARN("[%s::ApplyFilter] No input dataset given!\n",
291  getClassName().c_str());
292  output->width = output->height = 0;
293  output->points.clear();
294  return;
295  }
296 
297  output->height = 1;
298  output->is_dense = true;
299  output->points.clear();
300 
301  Eigen::Vector4f min_p, max_p;
302  // Get the minimum and maximum dimensions
303  if (!filter_field_name_.empty()) {
304  pcl::getMinMax3D<PointT>(input_, filter_field_name_,
305  static_cast<float>(filter_limit_min_),
306  static_cast<float>(filter_limit_max_), min_p,
307  max_p, filter_limit_negative_);
308  } else {
309  pcl::getMinMax3D<PointT>(*input_, min_p, max_p);
310  }
311  // Check that the leaf size is not too small.
312  int64_t dx =
313  static_cast<int64_t>((max_p[0] - min_p[0]) * inverse_leaf_size_[0]) + 1;
314  int64_t dy =
315  static_cast<int64_t>((max_p[1] - min_p[1]) * inverse_leaf_size_[1]) + 1;
316  int64_t dz =
317  static_cast<int64_t>((max_p[2] - min_p[2]) * inverse_leaf_size_[2]) + 1;
318 
319  if ((dx * dy * dz) > std::numeric_limits<int32_t>::max()) {
320  PCL_WARN(
321  "[%s::ApplyFilter] leaf size is too small. Integer indices would "
322  "overflow.",
323  getClassName().c_str());
324  output->clear();
325  return;
326  }
327  // Compute the minimum and maximum bounding box values
328  min_b_[0] = static_cast<int>(floor(min_p[0] * inverse_leaf_size_[0]));
329  max_b_[0] = static_cast<int>(floor(max_p[0] * inverse_leaf_size_[0]));
330  min_b_[1] = static_cast<int>(floor(min_p[1] * inverse_leaf_size_[1]));
331  max_b_[1] = static_cast<int>(floor(max_p[1] * inverse_leaf_size_[1]));
332  min_b_[2] = static_cast<int>(floor(min_p[2] * inverse_leaf_size_[2]));
333  max_b_[2] = static_cast<int>(floor(max_p[2] * inverse_leaf_size_[2]));
334 
335  // Compute the number of divisions needed along all axis
336  div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones();
337  div_b_[3] = 0;
338  // Clear the leaves
339  leaves_.clear();
340  // Set up the division multiplier
341  divb_mul_ = Eigen::Vector4i(1, div_b_[0], div_b_[0] * div_b_[1], 0);
342  int centroid_size = 4;
343  if (downsample_all_data_) {
344  centroid_size = boost::mpl::size<FieldList>::value;
345  }
346  // ---[ RGB special case
347  std::vector<pcl::PCLPointField> fields;
348  int rgba_index = -1;
349  rgba_index = pcl::getFieldIndex(*input_, "rgb", fields);
350  if (rgba_index == -1) {
351  rgba_index = pcl::getFieldIndex(*input_, "rgba", fields);
352  }
353  if (rgba_index >= 0) {
354  rgba_index = fields[rgba_index].offset;
355  centroid_size += 4;
356  }
357  // If we don't want to process the entire cloud,
358  // but rather filter points far away from the viewpoint first.
359  if (!filter_field_name_.empty()) {
360  // Get the distance field index
361  std::vector<pcl::PCLPointField> fields;
362  int distance_idx =
363  pcl::getFieldIndex(*input_, filter_field_name_, fields);
364  if (distance_idx == -1) {
365  PCL_WARN(
366  "[pcl::%s::ApplyFilter] Invalid filter field name. Index is %d.\n",
367  getClassName().c_str(), distance_idx);
368  return;
369  }
370  // First pass: go over all points and insert them into the right leaf
371  for (size_t cp = 0; cp < input_->points.size(); ++cp) {
372  if (!input_->is_dense) {
373  // Check if the point is invalid
374  if (!std::isfinite(input_->points[cp].x) ||
375  !std::isfinite(input_->points[cp].y) ||
376  !std::isfinite(input_->points[cp].z)) {
377  continue;
378  }
379  }
380  // Get the distance value
381  const uint8_t* pt_data =
382  reinterpret_cast<const uint8_t*>(&input_->points[cp]);
383  float distance_value = 0.0f;
384  memcpy(&distance_value, pt_data + fields[distance_idx].offset,
385  sizeof(float));
386 
387  if (filter_limit_negative_) {
388  // Use a threshold for cutting out points which inside the interval
389  if ((distance_value < filter_limit_max_) &&
390  (distance_value > filter_limit_min_)) {
391  continue;
392  }
393  } else {
394  // Use a threshold for cutting out points which are too close/far away
395  if ((distance_value > filter_limit_max_) ||
396  (distance_value < filter_limit_min_)) {
397  continue;
398  }
399  }
400 
401  int ijk0 = static_cast<int>(
402  floor(input_->points[cp].x * inverse_leaf_size_[0]) -
403  static_cast<float>(min_b_[0]));
404  int ijk1 = static_cast<int>(
405  floor(input_->points[cp].y * inverse_leaf_size_[1]) -
406  static_cast<float>(min_b_[1]));
407  int ijk2 = static_cast<int>(
408  floor(input_->points[cp].z * inverse_leaf_size_[2]) -
409  static_cast<float>(min_b_[2]));
410  // Compute the centroid leaf index
411  int idx =
412  ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
413 
414  Leaf& leaf = leaves_[idx];
415  if (leaf.nr_points_ == 0) {
416  leaf.centroid.resize(centroid_size);
417  leaf.centroid.setZero();
418  }
419 
421  leaf.cloud_.points.push_back(input_->points[cp]);
422 
423  Eigen::Vector3d pt3d(input_->points[cp].x, input_->points[cp].y,
424  input_->points[cp].z);
425  // Accumulate point sum for centroid calculation
426  leaf.mean_ += pt3d;
427  // Accumulate x*xT for single pass covariance calculation
428  leaf.cov_ += pt3d * pt3d.transpose();
429 
430  // Do we need to process all the fields?
431  if (!downsample_all_data_) {
432  Eigen::Vector4f pt(input_->points[cp].x, input_->points[cp].y,
433  input_->points[cp].z, 0);
434  leaf.centroid.template head<4>() += pt;
435  } else {
436  // Copy all the fields
437  Eigen::VectorXf centroid = Eigen::VectorXf::Zero(centroid_size);
438  pcl::for_each_type<FieldList>(pcl::NdCopyPointEigenFunctor<PointT>(
439  input_->points[cp], centroid));
440  // ---[ RGB special case
441  if (rgba_index >= 0) {
442  // Fill r/g/b data, assuming that the order is BGRA
443  const pcl::RGB& rgb = *reinterpret_cast<const pcl::RGB*>(
444  reinterpret_cast<const char*>(&input_->points[cp]) +
445  rgba_index);
446  centroid[centroid_size - 4] = rgb.a;
447  centroid[centroid_size - 3] = rgb.r;
448  centroid[centroid_size - 2] = rgb.g;
449  centroid[centroid_size - 1] = rgb.b;
450  }
451  leaf.centroid += centroid;
452  }
453  ++leaf.nr_points_;
454  }
455  } else { // No distance filtering, process all data
456  // First pass: go over all points and insert them into the right leaf
457  for (size_t cp = 0; cp < input_->points.size(); ++cp) {
458  if (!input_->is_dense) {
459  // Check if the point is invalid
460  if (!std::isfinite(input_->points[cp].x) ||
461  !std::isfinite(input_->points[cp].y) ||
462  !std::isfinite(input_->points[cp].z)) {
463  continue;
464  }
465  }
466  int ijk0 = static_cast<int>(
467  floor(input_->points[cp].x * inverse_leaf_size_[0]) -
468  static_cast<float>(min_b_[0]));
469  int ijk1 = static_cast<int>(
470  floor(input_->points[cp].y * inverse_leaf_size_[1]) -
471  static_cast<float>(min_b_[1]));
472  int ijk2 = static_cast<int>(
473  floor(input_->points[cp].z * inverse_leaf_size_[2]) -
474  static_cast<float>(min_b_[2]));
475 
476  // Compute the centroid leaf index
477  int idx =
478  ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
479 
480  // int idx = (((input_->points[cp].getArray4fmap () *
481  // inverse_leaf_size_).template cast<int> ()).matrix ()
482  // - min_b_).dot (divb_mul_);
483 
484  Leaf& leaf = leaves_[idx];
485  if (leaf.nr_points_ == 0) {
486  leaf.centroid.resize(centroid_size);
487  leaf.centroid.setZero();
488  }
489 
491  leaf.cloud_.points.push_back(input_->points[cp]);
492 
493  Eigen::Vector3d pt3d(input_->points[cp].x, input_->points[cp].y,
494  input_->points[cp].z);
495  // Accumulate point sum for centroid calculation
496  leaf.mean_ += pt3d;
497  // Accumulate x*xT for single pass covariance calculation
498  leaf.cov_ += pt3d * pt3d.transpose();
499 
500  // Do we need to process all the fields?
501  if (!downsample_all_data_) {
502  Eigen::Vector4f pt(input_->points[cp].x, input_->points[cp].y,
503  input_->points[cp].z, 0);
504  leaf.centroid.template head<4>() += pt;
505  } else {
506  // Copy all the fields
507  Eigen::VectorXf centroid = Eigen::VectorXf::Zero(centroid_size);
508  pcl::for_each_type<FieldList>(pcl::NdCopyPointEigenFunctor<PointT>(
509  input_->points[cp], centroid));
510  // ---[ RGB special case
511  if (rgba_index >= 0) {
512  // Fill r/g/b data, assuming that the order is BGRA
513  const pcl::RGB& rgb = *reinterpret_cast<const pcl::RGB*>(
514  reinterpret_cast<const char*>(&input_->points[cp]) +
515  rgba_index);
516  centroid[centroid_size - 4] = rgb.a;
517  centroid[centroid_size - 3] = rgb.r;
518  centroid[centroid_size - 2] = rgb.g;
519  centroid[centroid_size - 1] = rgb.b;
520  }
521  leaf.centroid += centroid;
522  }
523  ++leaf.nr_points_;
524  }
525  }
526 
527  // Second pass: go over all leaves and compute centroids and covariance
528  output->points.reserve(leaves_.size());
529  if (searchable_) {
530  voxel_centroidsleaf_indices_.reserve(leaves_.size());
531  }
532  int cp = 0;
533  if (save_leaf_layout_) {
534  leaf_layout_.resize(div_b_[0] * div_b_[1] * div_b_[2], -1);
535  }
536  // Eigen values and vectors calculated to prevent near singluar matrices
537  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigensolver;
538  Eigen::Matrix3d eigen_val;
539  Eigen::Vector3d pt_sum;
540 
541  // Eigen values less than a threshold of max eigen value are
542  // inflated to a set fraction of the max eigen value.
543  double min_covar_eigvalue;
544 
545  for (typename std::map<size_t, Leaf>::iterator it = leaves_.begin();
546  it != leaves_.end(); ++it) {
547  // Normalize the centroid
548  Leaf& leaf = it->second;
549 
550  // Normalize the centroid
551  leaf.centroid /= static_cast<float>(leaf.nr_points_);
552  // Point sum used for single pass covariance calculation
553  pt_sum = leaf.mean_;
554  // Normalize mean
555  leaf.mean_ /= leaf.nr_points_;
556 
557  if (leaf.nr_points_ >= min_points_per_voxel_) {
558  if (save_leaf_layout_) {
559  leaf_layout_[it->first] = cp++;
560  }
561  output->push_back(PointT());
562  // Do we need to process all the fields?
563  if (!downsample_all_data_) {
564  output->points.back().x = leaf.centroid[0];
565  output->points.back().y = leaf.centroid[1];
566  output->points.back().z = leaf.centroid[2];
567  } else {
568  pcl::for_each_type<FieldList>(pcl::NdCopyEigenPointFunctor<PointT>(
569  leaf.centroid, output->back()));
570  // ---[ RGB special case
571  if (rgba_index >= 0) {
572  pcl::RGB& rgb = *reinterpret_cast<pcl::RGB*>(
573  reinterpret_cast<char*>(&output->points.back()) + rgba_index);
574  rgb.a = static_cast<uint8_t>(leaf.centroid[centroid_size - 4]);
575  rgb.r = static_cast<uint8_t>(leaf.centroid[centroid_size - 3]);
576  rgb.g = static_cast<uint8_t>(leaf.centroid[centroid_size - 2]);
577  rgb.b = static_cast<uint8_t>(leaf.centroid[centroid_size - 1]);
578  }
579  }
580 
581  // Stores the voxel indice for fast access searching
582  if (searchable_) {
583  voxel_centroidsleaf_indices_.push_back(static_cast<int>(it->first));
584  }
585 
586  // Single pass covariance calculation
587  leaf.cov_ = (leaf.cov_ - 2 * (pt_sum * leaf.mean_.transpose())) /
588  leaf.nr_points_ +
589  leaf.mean_ * leaf.mean_.transpose();
590  leaf.cov_ *= (leaf.nr_points_ - 1.0) / leaf.nr_points_;
591 
592  // Normalize Eigen Val such that max no more than 100x min.
593  eigensolver.compute(leaf.cov_);
594  eigen_val = eigensolver.eigenvalues().asDiagonal();
595  leaf.evecs_ = eigensolver.eigenvectors();
596 
597  if (eigen_val(0, 0) < 0 || eigen_val(1, 1) < 0 ||
598  eigen_val(2, 2) <= 0) {
599  leaf.nr_points_ = -1;
600  continue;
601  }
602 
603  // Avoids matrices near singularities (eq 6.11)[Magnusson 2009]
604  min_covar_eigvalue = min_covar_eigvalue_mult_ * eigen_val(2, 2);
605  if (eigen_val(0, 0) < min_covar_eigvalue) {
606  eigen_val(0, 0) = min_covar_eigvalue;
607  if (eigen_val(1, 1) < min_covar_eigvalue) {
608  eigen_val(1, 1) = min_covar_eigvalue;
609  }
610  leaf.cov_ = leaf.evecs_ * eigen_val * leaf.evecs_.inverse();
611  }
612  leaf.evals_ = eigen_val.diagonal();
613 
614  leaf.icov_ = leaf.cov_.inverse();
615  if (leaf.icov_.maxCoeff() == std::numeric_limits<float>::infinity() ||
616  leaf.icov_.minCoeff() == -std::numeric_limits<float>::infinity()) {
617  leaf.nr_points_ = -1;
618  }
619  }
620  }
621  output->width = static_cast<uint32_t>(output->points.size());
622  }
623 
624  // Flag to determine if voxel structure is searchable. */
625  bool searchable_;
626 
627  // Minimum points contained with in a voxel to allow it to be usable.
628  int min_points_per_voxel_;
629 
630  // Minimum allowable ratio between eigenvalues.
631  double min_covar_eigvalue_mult_;
632 
633  // Voxel structure containing all leaf nodes.
634  std::map<size_t, Leaf> leaves_;
635 
636  /* Point cloud containing centroids of voxels
637  * containing at least minimum number of points. */
638  PointCloudPtr voxel_centroids_;
639 
640  /* Indices of leaf structurs associated with each point in
641  * \ref _voxel_centroids (used for searching). */
642  std::vector<int> voxel_centroidsleaf_indices_;
643 
644  // KdTree used for searching.
645  pcl::KdTreeFLANN<PointT> kdtree_;
646 };
647 
648 } // namespace msf
649 } // namespace localization
650 } // namespace apollo
int nr_points_
Definition: voxel_grid_covariance_hdmap.h:136
boost::shared_ptr< pcl::VoxelGrid< PointT > > Ptr
Definition: voxel_grid_covariance_hdmap.h:103
Definition: voxel_grid_covariance_hdmap.h:75
VoxelGridCovariance()
Definition: voxel_grid_covariance_hdmap.h:165
Eigen::Vector3f Vector3f
Definition: base_map_fwd.h:29
Eigen::Vector3d mean_
Definition: voxel_grid_covariance_hdmap.h:139
PlanningContext is the runtime context in planning. It is persistent across multiple frames...
Definition: atomic_hash_map.h:25
void SetMinPointPerVoxel(int min_points_per_voxel)
Definition: voxel_grid_covariance_hdmap.h:182
void Filter(bool searchable=false)
Definition: voxel_grid_covariance_hdmap.h:215
Leaf * LeafPtr
Definition: voxel_grid_covariance_hdmap.h:160
Eigen::Matrix3d cov_
Definition: voxel_grid_covariance_hdmap.h:145
Eigen::Matrix3d icov_
Definition: voxel_grid_covariance_hdmap.h:148
Eigen::Matrix3d evecs_
Definition: voxel_grid_covariance_hdmap.h:151
Eigen::Vector3d GetEvals() const
Definition: voxel_grid_covariance_hdmap.h:130
Eigen::Vector3d Vector3d
Definition: frame_transform.h:27
const Leaf * LeafConstPtr
Definition: voxel_grid_covariance_hdmap.h:162
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Leaf()
Definition: voxel_grid_covariance_hdmap.h:108
LeafType
Definition: voxel_grid_covariance_hdmap.h:75
int GetMinPointPerVoxel()
Definition: voxel_grid_covariance_hdmap.h:193
Definition: voxel_grid_covariance_hdmap.h:106
Definition: voxel_grid_covariance_hdmap.h:75
std::map< size_t, Leaf > & GetLeaves()
Definition: voxel_grid_covariance_hdmap.h:281
LeafConstPtr GetLeaf(const Eigen::Vector3f &p)
Definition: voxel_grid_covariance_hdmap.h:257
Eigen::Vector3d GetMean() const
Definition: voxel_grid_covariance_hdmap.h:124
LeafConstPtr GetLeaf(const PointT &p)
Definition: voxel_grid_covariance_hdmap.h:236
Eigen::VectorXf centroid
Definition: voxel_grid_covariance_hdmap.h:142
boost::shared_ptr< const pcl::VoxelGrid< PointT > > ConstPtr
Definition: voxel_grid_covariance_hdmap.h:104
Eigen::Matrix3d GetEvecs() const
Definition: voxel_grid_covariance_hdmap.h:127
void SetCovEigValueInflationRatio(double min_covar_eigvalue_mult)
Definition: voxel_grid_covariance_hdmap.h:196
pcl::traits::fieldList< PointT >::type FieldList
Definition: voxel_grid_covariance_hdmap.h:97
Definition: voxel_grid_covariance_hdmap.h:75
double GetCovEigValueInflationRatio()
Definition: voxel_grid_covariance_hdmap.h:200
int GetPointCount() const
Definition: voxel_grid_covariance_hdmap.h:133
void Filter(PointCloudPtr output, bool searchable=false)
Definition: voxel_grid_covariance_hdmap.h:205
LeafType type_
Definition: voxel_grid_covariance_hdmap.h:157
apollo::cyber::base::std value
PointCloud::Ptr PointCloudPtr
Definition: voxel_grid_covariance_hdmap.h:99
Eigen::Vector3d evals_
Definition: voxel_grid_covariance_hdmap.h:154
pcl::PointCloud< PointT > PointCloud
Definition: voxel_grid_covariance_hdmap.h:98
Eigen::Matrix3d GetInverseCov() const
Definition: voxel_grid_covariance_hdmap.h:121
LeafConstPtr GetLeaf(int index)
Definition: voxel_grid_covariance_hdmap.h:225
PointCloud::ConstPtr PointCloudConstPtr
Definition: voxel_grid_covariance_hdmap.h:100
Eigen::Matrix3d GetCov() const
Definition: voxel_grid_covariance_hdmap.h:118
Definition: voxel_grid_covariance_hdmap.h:75
pcl::PointCloud< PointT > cloud_
Definition: voxel_grid_covariance_hdmap.h:156
Eigen::Matrix3d Matrix3d
Definition: base_map_fwd.h:33
Definition: voxel_grid_covariance_hdmap.h:73