43 #include "Eigen/Eigenvalues" 56 PointMatcher<T>::DataPointsFilter(
"GestaltDataPointsFilter",
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);
220 BuildData& data,
const int first,
const int last,
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());
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);
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 Matrix 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())
geometry_msgs::TransformStamped t
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.
Functions and classes that are dependant on scalar type are defined in this templatized class...
const bool keepEigenValues
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)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
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
INLINE Rall1d< T, V, S > acos(const Rall1d< T, V, S > &x)
INLINE Rall1d< T, V, S > abs(const Rall1d< T, V, S > &x)
Eigen::Block< Matrix > View
A view on a feature or descriptor.
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
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
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