5#include "point_cloud/normal_estimator.h"
13#include "common/eigen_utility.h"
14#include "point_cloud/plane_estimator.h"
15#include "geometry/bbox3d.h"
18 namespace point_cloud {
20 n_points_(static_cast<index_t>(points.rows()))
22 , tree_(points, true){}
24 normal_estimator &normal_estimator::estimate_with_knn(rsmesh::index_t k,
double plane_factor_threshold) {
25 return estimate_with_knn(std::vector<index_t>{k}, plane_factor_threshold);
28 normal_estimator &normal_estimator::estimate_with_radius(
double radius,
double plane_factor_threshold) {
29 normals_ = geometry::vectors3d::Zero(n_points_, 3);
32 std::vector<index_t> nn_indices;
33 std::vector<double> nn_distances;
35 for(index_t i = 0; i < n_points_; i ++) {
36 auto p = points_.row(i);
37 std::tie(nn_indices, nn_distances) = tree_.radius_search(p, radius);
38 if(nn_indices.size() < 3) {
42 plane_estimator est(points_(nn_indices, Eigen::all));
44 if(est.plane_factor() >= plane_factor_threshold) {
45 normals_.row(i) = est.plane_normal();
53 normal_estimator& normal_estimator::estimate_with_knn(
const std::vector<index_t> &ks,
54 double plane_factor_threshold) {
55 normals_ = geometry::vectors3d::Zero(n_points_, 3);
57 std::vector<index_t> nn_indices;
58 std::vector<double> nn_distances;
60 std::vector<index_t> ks_sorted(ks);
61 std::sort(ks_sorted.rbegin(), ks_sorted.rend());
62 auto k_max = ks_sorted.front();
64 std::vector<double> plane_factors;
65 std::vector<geometry::vector3d> plane_normals;
67 for(index_t i = 0; i < n_points_; i ++) {
68 auto p = points_.row(i);
70 std::tie(nn_indices, nn_distances) = tree_.knn_search(p, k_max);
72 plane_factors.clear();
73 plane_normals.clear();
75 for(
auto k : ks_sorted) {
77 auto tmp = points_(nn_indices, Eigen::all);
78 plane_estimator est(points_(nn_indices, Eigen::all));
79 plane_factors.push_back(est.plane_factor());
80 plane_normals.push_back(est.plane_normal());
83 auto best = std::distance(plane_factors.begin(),
84 std::max_element(plane_factors.begin(), plane_factors.end()));
86 if (plane_factors.at(best) >= plane_factor_threshold) {
87 normals_.row(i) = plane_normals.at(best);
93 geometry::vectors3d normal_estimator::orient_by_outward_vector(
const geometry::vector3d &v) {
94 if(n_points_ > 0 and normals_.rows() == 0) {
95 throw std::runtime_error(
"Normals have not been estimated yet.");
98 for(index_t i = 0; i < n_points_; i ++) {
99 auto n = normals_.row(i);
111 : first_(first), second_(second), weight_(weight) {}
114 return weight_ < rhs.weight_;
117 [[nodiscard]] index_t first()
const {
return first_;}
119 [[nodiscard]] index_t second()
const {
return second_;}
121 [[nodiscard]]
double weight()
const {
return weight_;}
132 if(n_points_ > 0 and normals_.rows() == 0) {
133 throw std::runtime_error(
"Normals have not been estimated yet.");
136 auto bbox = geometry::bbox3d::from_points(points_);
137 auto center = bbox.center();
140 std::vector<bool> oriented(n_points_,
false);
142 for(index_t i = 0; i < n_points_; i ++) {
143 if(normals_.row(i).isZero()) {
144 oriented.at(i) =
true;
148 std::vector<index_t> indices(n_points_);
149 std::iota(begin(indices), end(indices), 0);
151 std::vector<double> distances(n_points_);
152 for(index_t i = 0; i < n_points_; i ++) {
153 auto p = points_.row(i);
154 distances.at(i) = (p_outer - p).norm();
157 std::sort(begin(indices), end(indices), [&](
int i,
int j) {
158 return distances.at(i) < distances.at(j);
162 auto indices_it = begin(indices);
164 std::priority_queue<weighted_pair> queue;
165 std::vector<index_t> nn_indices;
166 std::vector<double> nn_distances;
168 index_t n_connected_components = 0;
169 while(std::find(begin(oriented), end(oriented),
false) != end(oriented)) {
170 while(oriented.at(*indices_it)) {
174 auto i_closest = *indices_it;
175 auto p_closest = points_.row(i_closest);
176 if(normals_.row(i_closest).dot(p_outer - p_closest) < 0.0) {
177 normals_.row(i_closest) *= -1.0;
179 oriented.at(i_closest) =
true;
181 std::tie(nn_indices, nn_distances) = tree_.knn_search(p_closest, k);
182 for(
auto j : nn_indices) {
187 auto weight = std::abs(normals_.row(i_closest).dot(normals_.row(j)))
188 / (p_closest - points_.row(j)).norm();
189 queue.emplace(i_closest, j, weight);
192 while(!queue.empty()) {
193 auto pair = queue.top();
196 auto i = pair.first();
197 auto j = pair.second();
202 if(normals_.row(i).dot(normals_.row(j)) < 0.0) {
203 normals_.row(j) *= -1.0;
205 oriented.at(j) =
true;
207 auto p = points_.row(j);
208 std::tie(nn_indices, nn_distances) = tree_.knn_search(p, k);
209 for(
auto kk : nn_indices) {
210 if(oriented.at(kk)) {
214 auto weight = std::abs(normals_.row(j).dot(normals_.row(kk)))
215 / (p - points_.row(kk)).norm();
217 queue.emplace(j, kk, weight);
221 n_connected_components ++;
224 std::cout <<
"Number of connected components: " << n_connected_components << std::endl;
Eigen::Matrix< double, Eigen::Dynamic, 3, Eigen::RowMajor > vectors3d
3维向量的集合
本系统的主命名空间,包含了common, examples, fmm, geometry, numeric, point_cloud等子命名空间