43 #include "Eigen/Eigenvalues" 67 averageExistingDescriptors(
Parametrizable::
get<bool>(
"averageExistingDescriptors")),
95 const int pointsCount(cloud.
features.cols());
96 const int featDim(cloud.
features.rows());
105 for(
unsigned int i = 0; i < labelDim; ++i)
107 if (insertDim != descDim)
108 throw InvalidField(
"GestaltDataPointsFilter: Error, descriptor labels do not match descriptor data");
112 const int dimNormals(featDim-1);
113 const int dimMeans(featDim-1);
114 const int dimEigValues(featDim-1);
115 const int dimEigVectors((featDim-1)*(featDim-1));
116 const int dimCovariances((featDim-1)*(featDim-1));
117 const int dimGestalt = 32;
120 Labels cloudLabels, timeLabels;
123 cloudLabels.push_back(
Label(
"normals", dimNormals));
125 cloudLabels.push_back(
Label(
"means", dimMeans));
127 cloudLabels.push_back(
Label(
"eigValues", dimEigValues));
129 cloudLabels.push_back(
Label(
"eigVectors", dimEigVectors));
131 cloudLabels.push_back(
Label(
"covariance", dimCovariances));
134 cloudLabels.push_back(
Label(
"gestaltMeans", dimGestalt));
135 cloudLabels.push_back(
Label(
"gestaltVariances", dimGestalt));
136 cloudLabels.push_back(
Label(
"warpedXYZ", 3));
137 cloudLabels.push_back(
Label(
"gestaltShapes", 2));
139 timeLabels.push_back(
Label(
"time", 3));
146 TimeView cloudExistingTimes(cloud.
times.block(0,0,cloud.
times.rows(),cloud.
times.cols()));
172 cloud.
features.rowwise().minCoeff(),
177 fuseRange(buildData, cloud, 0, pointsCount);
183 for (
int i = 0; i < ptsOut; ++i)
194 buildData.
means->col(i) = buildData.
means->col(k);
209 cloud.
features.conservativeResize(Eigen::NoChange, ptsOut);
210 cloud.
descriptors.conservativeResize(Eigen::NoChange, ptsOut);
211 cloud.
times.conservativeResize(Eigen::NoChange, ptsOut);
225 const T minBoundX = minValues.x() /
vSizeX;
226 const T maxBoundX = maxValues.x() /
vSizeX;
227 const T minBoundY = minValues.y() /
vSizeY;
228 const T maxBoundY = maxValues.y() /
vSizeY;
229 const T minBoundZ = minValues.z() /
vSizeZ;
230 const T maxBoundZ = maxValues.z() /
vSizeZ;
234 const unsigned int numDivX = 1 + maxBoundX - minBoundX;
235 const unsigned int numDivY = 1 + maxBoundY - minBoundY;;
236 const unsigned int numDivZ = 1 + maxBoundZ - minBoundZ;
237 const unsigned int numVox = numDivX * numDivY * numDivZ;
244 const int numPoints = last - first;
245 std::vector<unsigned int> indices(numPoints);
250 std::vector<Voxel> voxels;
255 voxels = std::vector<Voxel>(numVox);
257 catch (std::bad_alloc&)
259 throw InvalidParameter((boost::format(
"GestaltDataPointsFilter: Memory allocation error with %1% voxels. Try increasing the voxel dimensions.") % numVox).str());
262 const int featDim(data.
features.rows());
264 for (
int p = 0; p < numPoints; ++p)
266 const unsigned int i = floor(data.
features(0,p)/
vSizeX - minBoundX);
267 const unsigned int j = floor(data.
features(1,p)/
vSizeY- minBoundY);
273 idx = i + j * numDivX + k * numDivX * numDivY;
277 idx = i + j * numDivX;
280 const unsigned int pointsInVox = voxels[idx].numPoints + 1;
282 if (pointsInVox == 1)
284 voxels[idx].firstPoint = p;
287 voxels[idx].numPoints = pointsInVox;
294 std::vector<unsigned int> pointsToKeep;
298 for (
int p = 0; p < numPoints ; ++p)
300 const unsigned int idx = indices[p];
301 const unsigned int firstPoint = voxels[idx].firstPoint;
304 const int randomIndex = std::rand() % numPoints;
305 for (
int f = 0; f < (featDim - 1); ++f)
311 for (
unsigned int idx = 0; idx < numVox; ++idx)
313 const unsigned int numPoints = voxels[idx].numPoints;
314 const unsigned int firstPoint = voxels[idx].firstPoint;
322 pointsToKeep.push_back(firstPoint);
326 const unsigned int nbPointsToKeep(pointsToKeep.size());
329 for(
unsigned int i=0; i<nbPointsToKeep; ++i)
331 const float r = (float)std::rand()/(float)RAND_MAX;
335 const int k = pointsToKeep[i];
348 typedef typename Eigen::Matrix<std::int64_t, Eigen::Dynamic, Eigen::Dynamic>
Int64Matrix;
351 const int inputFeatDim(input.
features.cols());
353 std::vector<int> indicesToKeepStrict;
354 for (
unsigned int i = 0; i < nbIdxToKeep ; ++i)
356 Eigen::Matrix<T,3,1> keyPoint;
360 const T minBoundX = keyPoint(0,0) -
radius;
361 const T maxBoundX = keyPoint(0,0) +
radius;
362 const T minBoundY = keyPoint(1,0) -
radius;
363 const T maxBoundY = keyPoint(1,0) +
radius;
364 const T minBoundZ = keyPoint(2,0) -
radius;
365 const T maxBoundZ = keyPoint(2,0) +
radius;
367 Eigen::Matrix<T,3,1> feature;
368 std::vector<int> goodIndices;
369 for (
int j = 0; j < inputFeatDim; ++j)
372 if(feature(0,0) <= maxBoundX && feature(0,0) >= minBoundX &&
373 feature(1,0) <= maxBoundY && feature(1,0) >= minBoundY &&
374 feature(2,0) <= maxBoundZ && feature(2,0) >= minBoundZ &&
377 goodIndices.push_back(j);
380 const int colCount = goodIndices.size();
388 const int featDim(data.
features.rows());
390 Matrix d(featDim-1, colCount);
391 Int64Matrix t(1, colCount);
393 for (
int j = 0; j < colCount; ++j)
395 d.col(j) = data.
features.block(0,data.
indices[goodIndices[j]],featDim-1, 1);
396 t.col(j) = data.
times.col(data.
indices[goodIndices[j]]);
399 const Vector mean = d.rowwise().sum() /
T(colCount);
400 const Matrix NN = d.colwise() - mean;
401 const std::int64_t minTime = t.minCoeff();
402 const std::int64_t maxTime = t.maxCoeff();
403 const std::int64_t meanTime = t.sum() /
T(colCount);
405 const Matrix C(NN * NN.transpose());
406 Vector eigenVa = Vector::Identity(featDim-1, 1);
407 Matrix eigenVe = Matrix::Identity(featDim-1, featDim-1);
411 if(C.fullPivHouseholderQr().rank()+1 >= featDim-1)
413 const Eigen::EigenSolver<Matrix> solver(C);
414 eigenVa = solver.eigenvalues().real();
415 eigenVe = solver.eigenvectors().real();
423 Eigen::Matrix<T,3,1> normal, newX, newY;
424 Eigen::Matrix<T,3,3> newBasis;
425 double planarity = 0.;
426 double cylindricality = 0.;
431 normal = computeNormal<T>(eigenVa, eigenVe);
435 Vector eigenVaSort = sortEigenValues<T>(eigenVa);
436 planarity = 2 * (eigenVaSort(1) - eigenVaSort(0))/eigenVaSort.sum();
437 cylindricality = (eigenVaSort(2) - eigenVaSort(1))/eigenVaSort.sum();
439 Eigen::Matrix<T,3,1> up, base;
442 newX << normal(0), normal(1), 0;
444 newY = up.cross(newX);
445 newY = newY / newY.norm();
447 newBasis << newX(0), newY(0), up(0),
448 newX(1), newY(1), up(1),
449 newX(2), newY(2), up(2);
458 if(acos(normal.dot(up)) < abs(10 * M_PI/180))
465 for (
int j = 0; j < colCount; ++j)
467 data.
warpedXYZ->col(j) = ((data.
features.block(0,j,3,1) - keyPoint).transpose() * newBasis).transpose();
471 Vector angles(colCount), radii(colCount), heights(colCount);
472 Matrix gestaltMeans(4, 8), gestaltVariances(4, 8), numOfValues(4, 8);
481 const T angularBinWidth = M_PI/4;
482 const T radialBinWidth =
radius/4;
483 Eigen::MatrixXi indices(2, colCount);
484 gestaltMeans = Matrix::Zero(4, 8);
485 gestaltVariances = Matrix::Zero(4, 8);
486 numOfValues = Matrix::Zero(4, 8);
488 for (
int it=0; it < colCount; ++it)
490 indices(0,it) = floor(radii(it)/radialBinWidth);
492 if(indices(0,it) > 3)
495 indices(1,it) = floor(angles(it)/angularBinWidth);
496 if(indices(1,it) > 7)
498 gestaltMeans(indices(0,it), indices(1,it)) += heights(it);
499 ++(numOfValues(indices(0,it), indices(1,it)));
502 for (
int radial=0; radial < 4; ++radial)
504 for (
int angular = 0; angular < 8; ++angular)
506 if (numOfValues(radial, angular) > 0)
508 gestaltMeans(radial, angular) = gestaltMeans(radial, angular)/numOfValues(radial, angular);
512 for (
int it=0; it < colCount; ++it)
514 gestaltVariances(indices(0,it), indices(1,it)) += (heights(it)-gestaltMeans(indices(0,it), indices(1,it))) * (heights(it)-gestaltMeans(indices(0,it), indices(1,it)));
516 for (
int radial=0; radial < 4; ++radial)
518 for (
int angular = 0; angular < 8; ++angular)
521 if (gestaltMeans(radial,angular) == 0 && radial > 0)
523 gestaltMeans(radial, angular) = gestaltMeans(radial-1, angular);
524 gestaltVariances(radial, angular) = gestaltVariances(radial-1, angular);
526 else if (numOfValues(radial, angular) > 0)
528 gestaltVariances(radial, angular) = gestaltVariances(radial, angular)/numOfValues(radial, angular);
536 serialEigVector = serializeEigVec<T>(eigenVe);
539 serialCovVector = serializeEigVec<T>(C);
540 Vector serialGestaltMeans;
541 Vector serialGestaltVariances;
586 const int dim = gestaltFeatures.rows() * gestaltFeatures.cols();
588 for(
int k=0; k < gestaltFeatures.rows(); ++k)
590 output.segment(k*gestaltFeatures.cols(), gestaltFeatures.cols()) =
591 gestaltFeatures.row(k).transpose();
599 const Matrix& points,
const Eigen::Matrix<T,3,1>& keyPoint)
const 601 const unsigned int dim(points.cols());
604 for (
unsigned int i = 0; i <
dim; ++i)
606 angles(i) = atan2(points(0,i), points(1,i));
608 angles(i) += (2 * M_PI);
617 const Matrix& points,
const Eigen::Matrix<T,3,1>& keyPoint)
const 619 const unsigned int dim(points.cols());
622 for (
unsigned int i = 0; i <
dim; ++i)
624 radii(i) = sqrt((points(0,i)) * (points(0,i)) + (points(1,i)) * (points(1,i)));
PointMatcher< T >::Vector Vector
boost::optional< View > eigenVectors
#define LOG_INFO_STREAM(args)
const bool averageExistingDescriptors
void allocateTimes(const Labels &newLabels)
Make sure a vector of time of given names exist.
boost::optional< View > warpedXYZ
Matrix descriptors
descriptors of points in the cloud, might be empty
Eigen::Block< Int64Matrix > TimeView
A view on a time.
ConstView getDescriptorViewByName(const std::string &name) const
Get a const view on a descriptor by name, throw an exception if it does not exist.
const bool keepCovariances
void fuseRange(BuildData &data, DataPoints &input, const int first, const int last) const
GestaltDataPointsFilter(const Parameters ¶ms=Parameters())
The name for a certain number of dim.
virtual DataPoints filter(const DataPoints &input)
PointMatcher< T >::Matrix Matrix
boost::optional< View > eigenValues
boost::optional< View > normals
boost::optional< View > covariance
PointMatcher< T >::DataPoints::InvalidField InvalidField
void buildNew(BuildData &data, const int first, const int last, Vector &&minValues, Vector &&maxValues) const
Functions and classes that are not dependant on scalar type are defined in this namespace.
DataPoints::Labels Labels
Functions and classes that are dependant on scalar type are defined in this templatized class...
const bool keepEigenValues
PM::Int64Matrix Int64Matrix
const bool keepGestaltFeatures
PointMatcher< T >::Vector calculateAngles(const Matrix &points, const Eigen::Matrix< T, 3, 1 > &) const
Parametrizable::Parameters Parameters
PointMatcher< T >::Vector serializeGestaltMatrix(const Matrix &gestaltFeatures) const
const M::mapped_type & get(const M &m, const typename M::key_type &k)
PointMatcher< T >::Vector calculateRadii(const Matrix &points, const Eigen::Matrix< T, 3, 1 > &) const
boost::optional< View > gestaltVariances
const bool keepEigenVectors
The superclass of classes that are constructed using generic parameters. This class provides the para...
Gestalt descriptors filter as described in Bosse & Zlot ICRA 2013.
boost::optional< View > gestaltMeans
boost::optional< View > means
Eigen::Block< Matrix > View
A view on a feature or descriptor.
boost::optional< View > gestaltShapes
Int64Matrix times
time associated to each points, might be empty
Eigen::Matrix< T, Eigen::Dynamic, 1 > Vector
A vector over ScalarType.
Matrix features
features of points in the cloud
PM::DataPointsFilter DataPointsFilter
virtual void inPlaceFilter(DataPoints &cloud)
Parametrizable::InvalidParameter InvalidParameter
void allocateDescriptors(const Labels &newLabels)
Make sure a vector of descriptors of given names exist.
Labels descriptorLabels
labels of descriptors