Apollo 11.0
自动驾驶开放平台
voxel_grid_covariance_hdmap.h
浏览该文件的文档.
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
68namespace apollo {
69namespace localization {
70namespace msf {
71
72template <typename PointT>
73class 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.
139 Eigen::Vector3d mean_;
140
141 // voxel centroid.
142 Eigen::VectorXf centroid;
143
144 // Voxel covariance matrix.
145 Eigen::Matrix3d cov_;
146
147 // Inverse of voxel covariance matrix.
148 Eigen::Matrix3d icov_;
149
150 // Eigen vectors of voxel covariance matrix.
151 Eigen::Matrix3d evecs_;
152
153 // Eigen values of voxel covariance matrix.
154 Eigen::Vector3d evals_;
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
void SetCovEigValueInflationRatio(double min_covar_eigvalue_mult)
void Filter(PointCloudPtr output, bool searchable=false)
boost::shared_ptr< const pcl::VoxelGrid< PointT > > ConstPtr
boost::shared_ptr< pcl::VoxelGrid< PointT > > Ptr
class register implement
Definition arena_queue.h:37