Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "CovarianceSampling.h"
00036
00037 #include <vector>
00038 #include <list>
00039 #include <utility>
00040 #include <unordered_map>
00041
00042
00043 #include "Eigen/QR"
00044 #include "Eigen/Eigenvalues"
00045
00046
00047 template <typename T>
00048 CovarianceSamplingDataPointsFilter<T>::CovarianceSamplingDataPointsFilter(const Parameters& params) :
00049 PointMatcher<T>::DataPointsFilter("CovarianceSamplingDataPointsFilter",
00050 CovarianceSamplingDataPointsFilter::availableParameters(), params),
00051 nbSample{Parametrizable::get<std::size_t>("nbSample")}
00052 {
00053 try
00054 {
00055 const std::uint8_t tnm = this->template get<std::uint8_t>("torqueNorm");
00056 normalizationMethod = TorqueNormMethod(tnm);
00057 }
00058 catch (const InvalidParameter& e)
00059 {
00060 normalizationMethod = TorqueNormMethod::Lavg;
00061 }
00062 }
00063
00064 template <typename T>
00065 typename PointMatcher<T>::DataPoints
00066 CovarianceSamplingDataPointsFilter<T>::filter(const DataPoints& input)
00067 {
00068 DataPoints output(input);
00069 inPlaceFilter(output);
00070 return output;
00071 }
00072
00073 template <typename T>
00074 void CovarianceSamplingDataPointsFilter<T>::inPlaceFilter(DataPoints& cloud)
00075 {
00076 const std::size_t featDim(cloud.features.rows());
00077 assert(featDim == 4);
00078
00079
00080 const std::size_t nbPoints = cloud.getNbPoints();
00081 if(nbSample >= nbPoints)
00082 return;
00083
00084
00085 if (!cloud.descriptorExists("normals"))
00086 throw InvalidField("OrientNormalsDataPointsFilter: Error, cannot find normals in descriptors.");
00087
00088 const auto& normals = cloud.getDescriptorViewByName("normals");
00089
00090 std::vector<std::size_t> keepIndexes;
00091 keepIndexes.resize(nbSample);
00092
00094
00095 std::vector<std::size_t> candidates ;
00096 candidates.resize(nbPoints);
00097
00098 for (std::size_t i = 0; i < nbPoints; ++i) candidates[i] = i;
00099
00100 const std::size_t nbCandidates = candidates.size();
00101
00102
00103 Vector3 center;
00104 for(std::size_t i = 0; i < featDim - 1; ++i) center(i) = T(0.);
00105
00106 for (std::size_t i = 0; i < nbCandidates; ++i)
00107 for (std::size_t f = 0; f <= 3; ++f)
00108 center(f) += cloud.features(f,candidates[i]);
00109
00110 for(std::size_t i = 0; i <= 3; ++i) center(i) /= T(nbCandidates);
00111
00112
00113 T Lnorm = 1.0;
00114
00115 if(normalizationMethod == TorqueNormMethod::L1)
00116 {
00117 Lnorm = 1.0;
00118 }
00119 else if(normalizationMethod == TorqueNormMethod::Lavg)
00120 {
00121 Lnorm = 0.0;
00122 for (std::size_t i = 0; i < nbCandidates; ++i)
00123 Lnorm += (cloud.features.col(candidates[i]).head(3) - center).norm();
00124 Lnorm /= nbCandidates;
00125 }
00126 else if(normalizationMethod == TorqueNormMethod::Lmax)
00127 {
00128 const Vector minValues = cloud.features.rowwise().minCoeff();
00129 const Vector maxValues = cloud.features.rowwise().maxCoeff();
00130 const Vector3 radii = maxValues.head(3) - minValues.head(3);
00131
00132 Lnorm = radii.maxCoeff() / 2.;
00133 }
00134
00135
00136 auto computeCovariance = [Lnorm, nbCandidates, &cloud, ¢er, &normals, &candidates](Matrix66 & cov) -> void {
00137
00138 Eigen::Matrix<T, 6, Eigen::Dynamic> F(6, nbCandidates);
00139
00140 for(std::size_t i = 0; i < nbCandidates; ++i)
00141 {
00142 const Vector3 p = cloud.features.col(candidates[i]).head(3) - center;
00143 const Vector3 ni = normals.col(candidates[i]).head(3);
00144
00145
00146 F.template block<3, 1>(0, i) = (1. / Lnorm) * p.cross(ni);
00147
00148 F.template block<3, 1>(3, i) = ni;
00149 }
00150
00151
00152 cov = F * F.transpose();
00153 };
00154
00155 Matrix66 covariance;
00156 computeCovariance(covariance);
00157
00158 Eigen::EigenSolver<Matrix66> solver(covariance);
00159 const Matrix66 eigenVe = solver.eigenvectors().real();
00160 const Vector6 eigenVa = solver.eigenvalues().real();
00161
00163
00164 std::vector<Vector6, Eigen::aligned_allocator<Vector6>> v;
00165 v.resize(nbCandidates);
00166
00167 for(std::size_t i = 0; i < nbCandidates; ++i)
00168 {
00169 const Vector3 p = cloud.features.col(candidates[i]).head(3) - center;
00170 const Vector3 ni = normals.col(candidates[i]).head(3);
00171
00172 v[i].template block<3, 1>(0, 0) = (1. / Lnorm) * p.cross(ni);
00173 v[i].template block<3, 1>(3, 0) = ni;
00174 }
00175
00176
00177 std::vector<std::list<std::pair<int, T>>> L;
00178 L.resize(6);
00179
00180
00181 auto comp = [](const std::pair<int, T>& p1, const std::pair<int, T>& p2) -> bool {
00182 return p1.second > p2.second;
00183 };
00184
00185 for(std::size_t k = 0; k < 6; ++k)
00186 {
00187 for(std::size_t i = 0; i < nbCandidates; ++i )
00188 {
00189 L[k].push_back(std::make_pair(i, std::fabs( v[i].dot(eigenVe.template block<6,1>(0, k)) )));
00190 }
00191
00192 L[k].sort(comp);
00193 }
00194
00195 std::vector<T> t(6, T(0.));
00196 std::vector<bool> sampledPoints(nbCandidates, false);
00197
00199 for(std::size_t i = 0; i < nbSample; ++i)
00200 {
00201
00202
00203
00204
00205 std::size_t k = 0;
00206 for (std::size_t i = 0; i < 6; ++i)
00207 {
00208 if (t[k] > t[i])
00209 k = i;
00210 }
00211
00212 while(sampledPoints[L[k].front().first])
00213 L[k].pop_front();
00214
00215
00216 const std::size_t idToKeep = static_cast<std::size_t>(L[k].front().first);
00217 L[k].pop_front();
00218
00219 sampledPoints[idToKeep] = true;
00220
00221
00222 for (std::size_t k = 0; k < 6; ++k)
00223 {
00224 const T magnitude = v[idToKeep].dot(eigenVe.template block<6, 1>(0, k));
00225 t[k] += (magnitude * magnitude);
00226 }
00227
00228 keepIndexes[i] = candidates[idToKeep];
00229 }
00230
00231
00232
00233 std::unordered_map<std::size_t, std::size_t> mapidx;
00234 std::size_t idx = 0;
00235
00237 for(std::size_t id : keepIndexes)
00238 {
00239
00240 if(id<idx)
00241 id = mapidx[id];
00242
00243 cloud.swapCols(idx, id);
00244
00245 mapidx[idx] = id;
00246
00247 ++idx;
00248 }
00249 cloud.conservativeResize(nbSample);
00250 }
00251
00252
00253
00254 template <typename T>
00255 T CovarianceSamplingDataPointsFilter<T>::computeConditionNumber(const Matrix66 &cov)
00256 {
00257 Vector eigenVa = Vector::Identity(6, 1);
00258
00259 Eigen::EigenSolver<Matrix66> solver(cov);
00260 eigenVa = solver.eigenvalues().real();
00261
00262 return eigenVa.maxCoeff() / eigenVa.minCoeff();
00263 }
00264
00265 template struct CovarianceSamplingDataPointsFilter<float>;
00266 template struct CovarianceSamplingDataPointsFilter<double>;