57 const std::size_t nbPts = pts.getNbPoints();
64 #pragma omp parallel for 65 for(std::size_t i = 0; i < nbPts; ++i)
73 #pragma omp parallel for 74 for(std::size_t i = 0; i < nbPts; ++i)
75 tensors(i) = Tensor::Identity();
81 if (not pts.descriptorExists(
"balls"))
82 throw InvalidField(
"TensorVoting<T>::encode: Error, cannot find balls in descriptors.");
84 const auto& balls_ = pts.getDescriptorViewByName(
"balls");
85 #pragma omp parallel for 86 for(std::size_t i = 0; i < nbPts; ++i)
87 tensors(i) = Tensor::Identity() * balls_(0,i);
92 case Encoding::UPLATE:
94 #pragma omp parallel for 95 for(std::size_t i = 0; i < nbPts; ++i)
102 case Encoding::PLATE:
103 case Encoding::SPLATE:
106 if (not pts.descriptorExists(
"plates"))
107 throw InvalidField(
"TensorVoting<T>::encode: Error, cannot find plates in descriptors.");
109 const auto& plates_ = pts.getDescriptorViewByName(
"plates");
110 #pragma omp parallel for 111 for(std::size_t i = 0; i < nbPts; ++i)
113 const Vector3 n1 = plates_.col(i).segment(1,3);
114 const Vector3 n2 = plates_.col(i).tail(3);
116 tensors(i) = (encoding == Encoding::SPLATE ? plates_(0,i) : 1.) * (n1 * n1.transpose() + n2 * n2.transpose());
121 case Encoding::USTICK:
123 #pragma omp parallel for 124 for(std::size_t i = 0; i < nbPts; ++i)
131 case Encoding::STICK:
132 case Encoding::SSTICK:
135 if (not pts.descriptorExists(
"sticks"))
136 throw InvalidField(
"TensorVoting<T>::encode: Error, cannot find sticks in descriptors.");
138 const auto& sticks_ = pts.getDescriptorViewByName(
"sticks");
139 #pragma omp parallel for 140 for(std::size_t i = 0; i < nbPts; ++i)
142 const Vector3 n = sticks_.col(i).tail(3);
143 tensors(i) = (encoding == Encoding::SSTICK ? sticks_(0,i) : 1.) * (n * n.transpose());
148 case Encoding::AWARE_TENSOR:
151 if (not pts.descriptorExists(
"sticks"))
152 throw InvalidField(
"TensorVoting<T>::encode: Error, cannot find sticks in descriptors.");
154 if (not pts.descriptorExists(
"plates"))
155 throw InvalidField(
"TensorVoting<T>::encode: Error, cannot find plates in descriptors.");
157 const auto& sticks_ = pts.getDescriptorViewByName(
"sticks");
158 const auto& plates_ = pts.getDescriptorViewByName(
"plates");
159 #pragma omp parallel for 160 for(std::size_t i = 0; i < nbPts; ++i)
162 const Tensor S = sticks_.col(i).tail(3) * sticks_.col(i).tail(3).transpose();
163 const Tensor P = plates_.col(i).segment(1,3) * plates_.col(i).segment(1,3).transpose() + plates_.col(i).tail(3) * plates_.col(i).tail(3).transpose();
165 tensors(i) = (sticks_(0,i) /
k) * S + (plates_(0,i) /
k) * P;
172 template <
typename T>
175 const std::size_t nbPts =
tensors.rows();
176 #pragma omp parallel for 177 for(std::size_t i = 0; i < nbPts; ++i)
186 template <
typename T>
214 template <
typename T>
217 const std::size_t nbPts = pts.getNbPoints();
219 const Tensor I = Tensor::Identity();
223 for(std::size_t voter = 0; voter < nbPts; ++voter)
225 for(std::size_t j = 0; j <
k ; j++)
230 if(votee ==
Index(voter))
continue;
232 const Vector3 v = pts.features.col(votee).head(3) - pts.features.col(voter).head(3);
233 const T normDist = v.norm()/
sigma;
235 if(normDist > 0. and normDist < 3.)
237 const Tensor vv = v * v.transpose();
238 const T normVv = vv.norm();
251 template <
typename T>
255 if (not pts.descriptorExists(
"sticks"))
256 throw InvalidField(
"TensorVoting<T>::stickVote: Error, cannot find sticks in descriptors.");
258 const auto& sticks_ = pts.getDescriptorViewByName(
"sticks");
260 const std::size_t nbPts = pts.getNbPoints();
264 for(std::size_t voter = 0; voter < nbPts; ++voter)
266 Vector3 vn = sticks_.col(voter).tail(3).normalized();
267 const Vector3 O = pts.features.col(voter).head(3);
269 for(std::size_t j = 0; j <
k ; j++)
274 if(votee ==
Index(voter))
continue;
276 Vector3 v = pts.features.col(votee).head(3) - O;
278 const T normDist = v.norm()/
sigma;
280 if(normDist > 0. and normDist < 3.)
284 const T vvn = v.dot(vn);
285 if(vvn < 0.) vn *= -1.;
287 const T theta = std::asin(vvn);
290 if (std::fabs(theta) <= M_PI / 4. or std::fabs(theta) >= 3. * M_PI / 4.)
293 Vector3 vt = vn.cross(v.cross(vn)).normalized();
295 const T vvt = v.dot(vt);
296 if(vvt < 0.) vt *= -1.;
299 const Vector3 vc = vn * std::cos(2. * theta) - vt * std::sin(2. * theta);
311 template <
typename T>
315 if (not pts.descriptorExists(
"plates"))
316 throw InvalidField(
"TensorVoting<T>::stickVote: Error, cannot find plates in descriptors.");
318 const auto& plates_ = pts.getDescriptorViewByName(
"plates");
320 const std::size_t nbPts = pts.getNbPoints();
324 for(std::size_t voter = 0; voter < nbPts; ++voter)
326 Matrix U(3,2); U << plates_.col(voter).segment(1,3), plates_.col(voter).tail(3);
327 const Matrix Ns = U*U.transpose();
329 for(std::size_t d = 0; d <= 1 ; ++d)
331 Vector3 vn = Ns.col(d).normalized();
332 const Vector3 O = pts.features.col(voter).head(3);
334 for(std::size_t j = 0; j <
k ; j++)
339 if(votee ==
Index(voter))
continue;
341 Vector3 v = pts.features.col(votee).head(3) - O;
343 const T normDist = v.norm()/
sigma;
345 if(normDist > 0. and normDist < 3.)
349 const T vvn = v.dot(vn);
350 if(vvn < 0.) vn *= -1.;
352 const T theta = std::asin(vvn);
355 if (std::fabs(theta) <= M_PI / 4. or std::fabs(theta) >= 3. * M_PI / 4.)
358 Vector3 vt = vn.cross(v.cross(vn)).normalized();
360 const T vvt = v.dot(vt);
361 if(vvt < 0.) vt *= -1.;
363 const Vector3 vc = vn * std::cos(2. * theta) - vt * std::sin(2. * theta);
380 template <
typename T>
383 const std::size_t nbPts = pts.getNbPoints();
388 encode(pts, Encoding::ZERO);
390 #pragma omp parallel for 391 for(std::size_t votee = 0; votee < nbPts; ++votee)
393 const Vector3 x_i = pts.features.col(votee).head(3);
395 for(std::size_t j = 0; j <
k ; j++)
400 if(voter ==
Index(votee))
continue;
402 const Vector3 x_j = pts.features.col(voter).head(3);
405 const T normDist = r_ij.norm() /
sigma;
407 if(normDist > 0. and normDist < 3.)
411 const Tensor rrt = r_ij * r_ij.transpose();
412 const Tensor R_ij = (Tensor::Identity() - 2. * rrt);
413 const Tensor Rp_ij = (Tensor::Identity() - .5 * rrt) * R_ij;
417 const Tensor S_ij = c_ij * R_ij * K(voter) * Rp_ij;
426 template <
typename T>
429 const std::size_t nbPts =
tensors.rows();
435 #pragma omp parallel for 436 for(std::size_t i = 0; i < nbPts; ++i)
438 Eigen::SelfAdjointEigenSolver<Tensor> solver(
tensors(i));
440 const Matrix33 eigenVe = solver.eigenvectors();
441 const Vector3 eigenVa = solver.eigenvalues().array().abs();
444 int lambda1_idx;
const T lambda1 = eigenVa.maxCoeff(&lambda1_idx);
445 int lambda3_idx;
const T lambda3 = eigenVa.minCoeff(&lambda3_idx);
446 const int lambda2_idx = (0+1+2) - (lambda1_idx + lambda3_idx);
447 const T lambda2 = eigenVa(lambda2_idx);
451 if(not (lambda1 >= lambda2 and lambda2 >= lambda3) or lambda2_idx > 2. or lambda2_idx < 0.)
469 sparseBall(i).tail(3) = eigenVe.col(lambda2_idx);
473 template <
typename T>
476 const std::size_t nbPts =
tensors.rows();
482 normals = PM::Matrix::Zero(3, nbPts);
483 tangents = PM::Matrix::Zero(3, nbPts);
485 sticks = PM::Matrix::Zero(4, nbPts);
486 plates = PM::Matrix::Zero(7, nbPts);
487 balls = PM::Matrix::Zero(1, nbPts);
489 #pragma omp parallel for 490 for(std::size_t i = 0; i < nbPts; i++)
509 template <
typename T>
512 const std::size_t nbPts = pts.getNbPoints();
514 if(
k >= nbPts)
k = nbPts - 1;
516 std::shared_ptr<NNS>
knn(
518 (
k<30? NNS::SearchType::KDTREE_LINEAR_HEAP : NNS::SearchType::KDTREE_TREE_HEAP)
522 indices = IndexMatrix::Zero(
k, nbPts);
523 dist = Matrix::Zero(
k, nbPts);
static NearestNeighbourSearch * create(const CloudType &cloud, const Index dim=std::numeric_limits< Index >::max(), const SearchType preferedType=KDTREE_LINEAR_HEAP, const unsigned creationOptionFlags=0, const Parameters &additionalParameters=Parameters())
static const char encoding[]
void stickVote(const DP &pts, bool doKnn=true)
void encode(const DP &pts, Encoding encoding=Encoding::UBALL)
TensorVoting(T sigma_=T(0.2), std::size_t k_=50)
Eigen::Matrix< T, 3, 3 > Matrix33
void plateVote(const DP &pts, bool doKnn=true)
SparseTensors sparsePlate
typename PM::Matrix Matrix
static T eta(const T vv, const T sigma, const T vvn)
void refine(const DP &pts)
void disableBallComponent()
typename DP::InvalidField InvalidField
SparseTensors sparseStick
Eigen::Matrix< T, 3, 3 > Tensor
Eigen::Matrix< Tensor, Eigen::Dynamic, 1 > Tensors
static T sradial(const T z)
static T cij(const T vv, const T sigma)
static constexpr Index InvalidIndex
Eigen::Matrix< T, 3, 1 > Vector3
The superclass of classes that are constructed using generic parameters. This class provides the para...
void cfvote(const DP &pts, bool doKnn=true)
typename PM::DataPoints DP
typename NNS::Index Index
void computeKnn(const DP &pts)
void vote(const DP &pts)
Voting methods.
void ballVote(const DP &pts, bool doKnn=true)