40 #include <unordered_map>
44 #include "Eigen/Eigenvalues"
51 nbSample{Parametrizable::get<std::size_t>(
"nbSample")}
55 const std::uint8_t tnm = this->
template get<std::uint8_t>(
"torqueNorm");
56 normalizationMethod = TorqueNormMethod(tnm);
60 normalizationMethod = TorqueNormMethod::Lavg;
69 inPlaceFilter(output);
76 const std::size_t featDim(cloud.
features.rows());
81 if(nbSample >= nbPoints)
86 throw InvalidField(
"OrientNormalsDataPointsFilter: Error, cannot find normals in descriptors.");
90 std::vector<std::size_t> keepIndexes;
91 keepIndexes.resize(nbSample);
95 std::vector<std::size_t> candidates ;
96 candidates.resize(nbPoints);
98 for (std::size_t i = 0; i < nbPoints; ++i) candidates[i] = i;
100 const std::size_t nbCandidates = candidates.size();
104 for(std::size_t i = 0; i < featDim - 1; ++i) center(i) =
T(0.);
106 for (std::size_t i = 0; i < nbCandidates; ++i)
107 for (std::size_t f = 0; f < 3; ++f)
108 center(f) += cloud.
features(f,candidates[i]);
110 for(std::size_t i = 0; i < 3; ++i) center(i) /=
T(nbCandidates);
115 if(normalizationMethod == TorqueNormMethod::L1)
119 else if(normalizationMethod == TorqueNormMethod::Lavg)
122 for (std::size_t i = 0; i < nbCandidates; ++i)
123 Lnorm += (cloud.
features.col(candidates[i]).head(3) - center).norm();
124 Lnorm /= nbCandidates;
126 else if(normalizationMethod == TorqueNormMethod::Lmax)
130 const Vector3 radii = maxValues.head(3) - minValues.head(3);
132 Lnorm = radii.maxCoeff() / 2.;
136 auto computeCovariance = [Lnorm, nbCandidates, &cloud, ¢er, &normals, &candidates](
Matrix66 & cov) ->
void {
138 Eigen::Matrix<T, 6, Eigen::Dynamic> F(6, nbCandidates);
140 for(std::size_t i = 0; i < nbCandidates; ++i)
142 const Vector3 p = cloud.features.col(candidates[i]).head(3) - center;
143 const Vector3 ni = normals.col(candidates[i]).head(3);
146 F.template block<3, 1>(0, i) = (1. / Lnorm) * p.cross(ni);
148 F.template block<3, 1>(3, i) = ni;
152 cov = F * F.transpose();
156 computeCovariance(covariance);
158 Eigen::EigenSolver<Matrix66> solver(covariance);
159 const Matrix66 eigenVe = solver.eigenvectors().real();
160 const Vector6 eigenVa = solver.eigenvalues().real();
164 std::vector<Vector6, Eigen::aligned_allocator<Vector6>> v;
165 v.resize(nbCandidates);
167 for(std::size_t i = 0; i < nbCandidates; ++i)
169 const Vector3 p = cloud.features.col(candidates[i]).head(3) - center;
170 const Vector3 ni = normals.col(candidates[i]).head(3);
172 v[i].template block<3, 1>(0, 0) = (1. / Lnorm) * p.cross(ni);
173 v[i].template block<3, 1>(3, 0) = ni;
177 std::vector<std::list<std::pair<int, T>>> L;
181 auto comp = [](
const std::pair<int, T>& p1,
const std::pair<int, T>& p2) ->
bool {
182 return p1.second > p2.second;
185 for(std::size_t k = 0; k < 6; ++k)
187 for(std::size_t i = 0; i < nbCandidates; ++i )
189 L[k].push_back(std::make_pair(i, std::fabs( v[i].dot(eigenVe.template block<6,1>(0, k)) )));
195 std::vector<T> t(6,
T(0.));
196 std::vector<bool> sampledPoints(nbCandidates,
false);
199 for(std::size_t i = 0; i < nbSample; ++i)
206 for (std::size_t i = 0; i < 6; ++i)
212 while(sampledPoints[L[k].front().first])
216 const std::size_t idToKeep =
static_cast<std::size_t
>(L[k].front().first);
219 sampledPoints[idToKeep] =
true;
222 for (std::size_t k = 0; k < 6; ++k)
224 const T magnitude = v[idToKeep].dot(eigenVe.template block<6, 1>(0, k));
225 t[k] += (magnitude * magnitude);
228 keepIndexes[i] = candidates[idToKeep];
233 std::unordered_map<std::size_t, std::size_t> mapidx;
237 for(std::size_t
id : keepIndexes)
243 cloud.swapCols(idx,
id);
249 cloud.conservativeResize(nbSample);
254 template <
typename T>
257 Vector eigenVa = Vector::Identity(6, 1);
259 Eigen::EigenSolver<Matrix66> solver(cov);
260 eigenVa = solver.eigenvalues().real();
262 return eigenVa.maxCoeff() / eigenVa.minCoeff();