Gestalt.cpp
Go to the documentation of this file.
00001 // kate: replace-tabs off; indent-width 4; indent-mode normal
00002 // vim: ts=4:sw=4:noexpandtab
00003 /*
00004 
00005 Copyright (c) 2010--2018,
00006 François Pomerleau and Stephane Magnenat, ASL, ETHZ, Switzerland
00007 You can contact the authors at <f dot pomerleau at gmail dot com> and
00008 <stephane at magnenat dot net>
00009 
00010 All rights reserved.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014     * Redistributions of source code must retain the above copyright
00015       notice, this list of conditions and the following disclaimer.
00016     * Redistributions in binary form must reproduce the above copyright
00017       notice, this list of conditions and the following disclaimer in the
00018       documentation and/or other materials provided with the distribution.
00019     * Neither the name of the <organization> nor the
00020       names of its contributors may be used to endorse or promote products
00021       derived from this software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00026 DISCLAIMED. IN NO EVENT SHALL ETH-ASL BE LIABLE FOR ANY
00027 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00028 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00030 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00031 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 #include "Gestalt.h"
00036 
00037 #include "utils.h"
00038 
00039 #include <cmath>
00040 
00041 // Eigenvalues
00042 #include "Eigen/QR"
00043 #include "Eigen/Eigenvalues"
00044 
00045 #include "PointMatcherPrivate.h"
00046 
00047 #include <vector>
00048 
00050 
00051 // GestaltDataPointsFilter
00052 
00053 // Constructor
00054 template<typename T>
00055 GestaltDataPointsFilter<T>::GestaltDataPointsFilter(const Parameters& params):
00056         PointMatcher<T>::DataPointsFilter("GestaltDataPointsFilter", 
00057                 GestaltDataPointsFilter::availableParameters(), params),
00058         ratio(Parametrizable::get<T>("ratio")),
00059         radius(Parametrizable::get<T>("radius")),
00060         knn(Parametrizable::get<int>("knn")),
00061         vSizeX(Parametrizable::get<T>("vSizeX")),
00062         vSizeY(Parametrizable::get<T>("vSizeY")),
00063         vSizeZ(Parametrizable::get<T>("vSizeZ")),
00064         maxBoxDim(Parametrizable::get<T>("maxBoxDim")),
00065         maxTimeWindow(Parametrizable::get<T>("maxTimeWindow")),
00066         keepMeans(Parametrizable::get<bool>("keepMeans")),
00067         averageExistingDescriptors(Parametrizable::get<bool>("averageExistingDescriptors")),
00068         keepNormals(Parametrizable::get<bool>("keepNormals")),
00069         keepEigenValues(Parametrizable::get<bool>("keepEigenValues")),
00070         keepEigenVectors(Parametrizable::get<bool>("keepEigenVectors")),
00071         keepCovariances(Parametrizable::get<bool>("keepCovariances")),
00072         keepGestaltFeatures(Parametrizable::get<bool>("keepGestaltFeatures"))
00073 {
00074 }
00075 
00076 // Compute
00077 template<typename T>
00078 typename PointMatcher<T>::DataPoints
00079 GestaltDataPointsFilter<T>::filter(const DataPoints& input)
00080 {
00081   DataPoints output(input);
00082   inPlaceFilter(output);
00083   return output;
00084 }
00085 
00086 // In-place filter
00087 template<typename T>
00088 void GestaltDataPointsFilter<T>::inPlaceFilter(DataPoints& cloud)
00089 {
00090   typedef typename DataPoints::View View;
00091   typedef typename DataPoints::Label Label;
00092   typedef typename DataPoints::Labels Labels;
00093   typedef typename DataPoints::TimeView TimeView;
00094 
00095   const int pointsCount(cloud.features.cols());
00096   const int featDim(cloud.features.rows());
00097   const int descDim(cloud.descriptors.rows());
00098   const unsigned int labelDim(cloud.descriptorLabels.size());
00099 
00100   int insertDim(0);
00101   if (averageExistingDescriptors)
00102   {
00103     // TODO: this should be in the form of an assert
00104     // Validate descriptors and labels
00105     for(unsigned int i = 0; i < labelDim; ++i)
00106       insertDim += cloud.descriptorLabels[i].span;
00107     if (insertDim != descDim)
00108       throw InvalidField("GestaltDataPointsFilter: Error, descriptor labels do not match descriptor data");
00109   }
00110 
00111   // Compute space requirement for new descriptors
00112   const int dimNormals(featDim-1);
00113   const int dimMeans(featDim-1);
00114   const int dimEigValues(featDim-1);
00115   const int dimEigVectors((featDim-1)*(featDim-1));
00116   const int dimCovariances((featDim-1)*(featDim-1));
00117   const int dimGestalt = 32;
00118 
00119   // Allocate space for new descriptors
00120   Labels cloudLabels, timeLabels;
00121 
00122   if (keepNormals)
00123     cloudLabels.push_back(Label("normals", dimNormals));
00124   if (keepMeans)
00125     cloudLabels.push_back(Label("means", dimMeans));
00126   if (keepEigenValues)
00127     cloudLabels.push_back(Label("eigValues", dimEigValues));
00128   if (keepEigenVectors)
00129     cloudLabels.push_back(Label("eigVectors", dimEigVectors));
00130   if (keepCovariances)
00131     cloudLabels.push_back(Label("covariance", dimCovariances));
00132   if (keepGestaltFeatures) 
00133   {
00134     cloudLabels.push_back(Label("gestaltMeans", dimGestalt));
00135     cloudLabels.push_back(Label("gestaltVariances", dimGestalt));
00136     cloudLabels.push_back(Label("warpedXYZ", 3));
00137     cloudLabels.push_back(Label("gestaltShapes", 2));
00138   }
00139   timeLabels.push_back(Label("time", 3));
00140 
00141   cloud.allocateDescriptors(cloudLabels);
00142   cloud.allocateTimes(timeLabels);
00143 
00144   // we keep build data on stack for reentrant behaviour
00145   View cloudExistingDescriptors(cloud.descriptors.block(0,0,cloud.descriptors.rows(),cloud.descriptors.cols()));
00146   TimeView cloudExistingTimes(cloud.times.block(0,0,cloud.times.rows(),cloud.times.cols()));
00147   BuildData buildData(cloud.features, cloud.descriptors, cloud.times);
00148 
00149   // get views
00150   if (keepNormals)
00151     buildData.normals = cloud.getDescriptorViewByName("normals");
00152   if(keepMeans)
00153     buildData.means = cloud.getDescriptorViewByName("means");
00154   if (keepEigenValues)
00155     buildData.eigenValues = cloud.getDescriptorViewByName("eigValues");
00156   if (keepEigenVectors)
00157     buildData.eigenVectors = cloud.getDescriptorViewByName("eigVectors");
00158   if (keepCovariances)
00159     buildData.covariance = cloud.getDescriptorViewByName("covariance");
00160   if (keepGestaltFeatures) 
00161   {
00162     buildData.gestaltMeans = cloud.getDescriptorViewByName("gestaltMeans");
00163     buildData.gestaltVariances = cloud.getDescriptorViewByName("gestaltVariances");
00164     buildData.warpedXYZ = cloud.getDescriptorViewByName("warpedXYZ");
00165     buildData.gestaltShapes = cloud.getDescriptorViewByName("gestaltShapes");
00166   }
00167   // build the new point cloud
00168   buildNew(
00169       buildData,
00170       0,
00171       pointsCount,
00172       cloud.features.rowwise().minCoeff(),
00173       cloud.features.rowwise().maxCoeff()
00174   );
00175 
00176   // buildData.indicesToKeep contains all the indices where we want Gestalt features at
00177   fuseRange(buildData, cloud, 0, pointsCount);
00178 
00179   // Bring the data we keep to the front of the arrays then
00180   // wipe the leftover unused space.
00181   std::sort(buildData.indicesToKeep.begin(), buildData.indicesToKeep.end());
00182   const int ptsOut = buildData.indicesToKeep.size();
00183   for (int i = 0; i < ptsOut; ++i)
00184   {
00185     const int k = buildData.indicesToKeep[i];
00186     assert(i <= k);
00187     cloud.features.col(i) = cloud.features.col(k);
00188     cloud.times.col(i) = cloud.times.col(k);
00189     if (cloud.descriptors.rows() != 0)
00190       cloud.descriptors.col(i) = cloud.descriptors.col(k);
00191     if(keepNormals)
00192       buildData.normals->col(i) = buildData.normals->col(k);
00193     if(keepMeans)
00194       buildData.means->col(i) = buildData.means->col(k);
00195     if(keepEigenValues)
00196       buildData.eigenValues->col(i) = buildData.eigenValues->col(k);
00197     if(keepEigenVectors)
00198       buildData.eigenVectors->col(i) = buildData.eigenVectors->col(k);
00199     if(keepCovariances)
00200       buildData.covariance->col(i) = buildData.covariance->col(k);
00201     if(keepGestaltFeatures) 
00202     {
00203       buildData.gestaltMeans->col(i) = buildData.gestaltMeans->col(k);
00204       buildData.gestaltVariances->col(i) = buildData.gestaltVariances->col(k);
00205       buildData.warpedXYZ->col(i) = buildData.warpedXYZ->col(k);
00206       buildData.gestaltShapes->col(i) = buildData.gestaltShapes->col(k);
00207     }
00208   }
00209   cloud.features.conservativeResize(Eigen::NoChange, ptsOut);
00210   cloud.descriptors.conservativeResize(Eigen::NoChange, ptsOut);
00211   cloud.times.conservativeResize(Eigen::NoChange, ptsOut);
00212   // warning if some points were dropped
00213   if(buildData.unfitPointsCount != 0)
00214     LOG_INFO_STREAM("  GestaltDataPointsFilter - Could not compute normal for " << buildData.unfitPointsCount << " pts.");
00215 }
00216 
00217 #include "VoxelGrid.h"
00218 template<typename T>
00219 void GestaltDataPointsFilter<T>::buildNew(
00220         BuildData& data, const int first, const int last, 
00221         Vector&& minValues, Vector&& maxValues) const
00222 {
00223         using Voxel = typename VoxelGridDataPointsFilter<T>::Voxel;
00224 
00225   const T minBoundX = minValues.x() / vSizeX;
00226   const T maxBoundX = maxValues.x() / vSizeX;
00227   const T minBoundY = minValues.y() / vSizeY;
00228   const T maxBoundY = maxValues.y() / vSizeY;
00229   const T minBoundZ = minValues.z() / vSizeZ;
00230   const T maxBoundZ = maxValues.z() / vSizeZ;
00231 
00232   // number of divisions is total size / voxel size voxels of equal length + 1
00233   // with remaining space
00234   const unsigned int numDivX = 1 + maxBoundX - minBoundX;
00235   const unsigned int numDivY = 1 + maxBoundY - minBoundY;;
00236   const unsigned int numDivZ = 1 + maxBoundZ - minBoundZ;
00237   const unsigned int numVox = numDivX * numDivY * numDivZ;
00238 
00239   // Assume point cloud is randomly ordered
00240   // compute a linear index of the following type
00241   // i, j, k are the component indices
00242   // nx, ny number of divisions in x and y components
00243   // idx = i + j * nx + k * nx * ny
00244   const int numPoints = last - first;
00245   std::vector<unsigned int> indices(numPoints);
00246 
00247   // vector to hold the first point in a voxel
00248   // this point will be ovewritten in the input cloud with
00249   // the output value
00250   std::vector<Voxel> voxels;
00251 
00252   // try allocating vector. If too big return error
00253   try 
00254   {
00255     voxels = std::vector<Voxel>(numVox);
00256   } 
00257   catch (std::bad_alloc&) 
00258   {
00259     throw InvalidParameter((boost::format("GestaltDataPointsFilter: Memory allocation error with %1% voxels.  Try increasing the voxel dimensions.") % numVox).str());
00260   }
00261 
00262   const int featDim(data.features.rows());
00263 
00264   for (int p = 0; p < numPoints; ++p)
00265   {
00266     const unsigned int i = floor(data.features(0,p)/vSizeX - minBoundX);
00267     const unsigned int j = floor(data.features(1,p)/vSizeY- minBoundY);
00268     unsigned int k = 0;
00269     unsigned int idx;
00270     if ( featDim == 4 )
00271     {
00272       k = floor(data.features(2,p)/vSizeZ - minBoundZ);
00273       idx = i + j * numDivX + k * numDivX * numDivY;
00274     }
00275     else
00276     {
00277       idx = i + j * numDivX;
00278     }
00279 
00280     const unsigned int pointsInVox = voxels[idx].numPoints + 1;
00281 
00282     if (pointsInVox == 1)
00283     {
00284       voxels[idx].firstPoint = p;
00285     }
00286 
00287     voxels[idx].numPoints = pointsInVox;
00288 
00289     indices[p] = idx;
00290 
00291   }
00292 
00293   // store which points contain voxel position
00294   std::vector<unsigned int> pointsToKeep;
00295 
00296   // take centers of voxels for now
00297   // Todo revert to random point selection within cell
00298   for (int p = 0; p < numPoints ; ++p)
00299   {
00300     const unsigned int idx = indices[p];
00301     const unsigned int firstPoint = voxels[idx].firstPoint;
00302 
00303     // Choose random point in voxel
00304     const int randomIndex = std::rand() % numPoints;
00305     for (int f = 0; f < (featDim - 1); ++f)
00306     {
00307       data.features(f,firstPoint) = data.features(f,randomIndex);
00308     }
00309   }
00310 
00311   for (unsigned int idx = 0; idx < numVox; ++idx)
00312   {
00313     const unsigned int numPoints = voxels[idx].numPoints;
00314     const unsigned int firstPoint = voxels[idx].firstPoint;
00315 
00316     if (numPoints > 0)
00317     {
00318       // get back voxel indices in grid format
00319       // If we are in the last division, the voxel is smaller in size
00320       // We adjust the center as from the end of the last voxel to the bounding area
00321 
00322       pointsToKeep.push_back(firstPoint);
00323     }
00324   }
00325 
00326         const unsigned int nbPointsToKeep(pointsToKeep.size());
00327   // now the keypoints are in pointsToKeep
00328   // downsample with ratio
00329   for(unsigned int i=0; i<nbPointsToKeep; ++i)
00330   {
00331     const float r = (float)std::rand()/(float)RAND_MAX;
00332     if(r < ratio)
00333     {
00334       // Keep points with their descriptors
00335       const int k = pointsToKeep[i];
00336       // Mark the indices which will be part of the final data
00337       data.indicesToKeep.push_back(k);
00338     }
00339   }
00340 }
00341 
00342 template<typename T>
00343 void GestaltDataPointsFilter<T>::fuseRange(
00344         BuildData& data, DataPoints& input, const int first, const int last) const
00345 {
00346   using namespace PointMatcherSupport;
00347   
00348   typedef typename Eigen::Matrix<std::int64_t, Eigen::Dynamic, Eigen::Dynamic> Int64Matrix;
00349 
00350   const unsigned int nbIdxToKeep(data.indicesToKeep.size());
00351   const int inputFeatDim(input.features.cols());
00352   
00353   std::vector<int> indicesToKeepStrict;
00354   for (unsigned int i = 0; i < nbIdxToKeep ; ++i) 
00355   {
00356     Eigen::Matrix<T,3,1> keyPoint;
00357     keyPoint = input.features.col(data.indicesToKeep[i]);
00358 
00359     // Define a search box around each keypoint to search for nearest neighbours.
00360     const T minBoundX = keyPoint(0,0) - radius;
00361     const T maxBoundX = keyPoint(0,0) + radius;
00362     const T minBoundY = keyPoint(1,0) - radius;
00363     const T maxBoundY = keyPoint(1,0) + radius;
00364     const T minBoundZ = keyPoint(2,0) - radius;
00365     const T maxBoundZ = keyPoint(2,0) + radius;
00366     // iterate over data and find in- / outliers
00367     Eigen::Matrix<T,3,1> feature;
00368     std::vector<int> goodIndices;
00369     for (int j = 0; j < inputFeatDim; ++j) 
00370     {
00371       feature = input.features.col(j);
00372       if(feature(0,0) <= maxBoundX && feature(0,0) >= minBoundX &&
00373           feature(1,0) <= maxBoundY && feature(1,0) >= minBoundY &&
00374           feature(2,0) <= maxBoundZ && feature(2,0) >= minBoundZ &&
00375           keyPoint != feature) 
00376       {
00377         goodIndices.push_back(j);
00378       }
00379     }
00380     const int colCount = goodIndices.size();
00381     // if empty neighbourhood unfit the point
00382     if (colCount == 0) 
00383     {
00384       ++(data.unfitPointsCount);
00385       continue;
00386     }
00387     
00388     const int featDim(data.features.rows());
00389     
00390     Matrix d(featDim-1, colCount);
00391     Int64Matrix t(1, colCount);
00392 
00393     for (int j = 0; j < colCount; ++j) 
00394     {
00395       d.col(j) = data.features.block(0,data.indices[goodIndices[j]],featDim-1, 1);
00396       t.col(j) = data.times.col(data.indices[goodIndices[j]]);
00397     }
00398 
00399     const Vector mean = d.rowwise().sum() / T(colCount);
00400     const Matrix NN = d.colwise() - mean;
00401     const std::int64_t minTime = t.minCoeff();
00402     const std::int64_t maxTime = t.maxCoeff();
00403     const std::int64_t meanTime = t.sum() / T(colCount);
00404     // compute covariance
00405     const Matrix C(NN * NN.transpose());
00406     Vector eigenVa = Vector::Identity(featDim-1, 1);
00407     Matrix eigenVe = Matrix::Identity(featDim-1, featDim-1);
00408     // Ensure that the matrix is suited for eigenvalues calculation
00409     if(keepNormals || keepEigenValues || keepEigenVectors || keepCovariances || keepGestaltFeatures)
00410     {
00411       if(C.fullPivHouseholderQr().rank()+1 >= featDim-1)
00412       {
00413         const Eigen::EigenSolver<Matrix> solver(C);
00414         eigenVa = solver.eigenvalues().real();
00415         eigenVe = solver.eigenvectors().real();
00416       }
00417       else
00418       {
00419         data.unfitPointsCount += colCount;
00420         continue;
00421       }
00422     }
00423     Eigen::Matrix<T,3,1> normal, newX, newY;
00424     Eigen::Matrix<T,3,3> newBasis;
00425     double planarity = 0.;
00426                 double cylindricality = 0.;
00427 
00428     if(keepNormals || keepGestaltFeatures) 
00429     {
00430       // calculate orientation of NN
00431       normal = computeNormal<T>(eigenVa, eigenVe);
00432 
00433       if(keepGestaltFeatures) 
00434       {
00435         Vector eigenVaSort = sortEigenValues<T>(eigenVa);
00436         planarity = 2 * (eigenVaSort(1) - eigenVaSort(0))/eigenVaSort.sum();
00437         cylindricality = (eigenVaSort(2) - eigenVaSort(1))/eigenVaSort.sum();
00438         // project normal on horizontal plane
00439         Eigen::Matrix<T,3,1> up, base;
00440         up << 0,0,1;
00441         base << 1,0,0;
00442         newX << normal(0), normal(1), 0;
00443         newX.normalize();
00444         newY = up.cross(newX);
00445         newY = newY / newY.norm();
00446         // form a new basis with world z-axis and projected x & y-axis
00447         newBasis << newX(0), newY(0), up(0),
00448             newX(1), newY(1), up(1),
00449             newX(2), newY(2), up(2);
00450 
00451         // discard keypoints with high planarity
00452         if(planarity > 0.9) 
00453         {
00454           data.unfitPointsCount += colCount;
00455           continue;
00456         }
00457         // discard keypoints with normal too close to vertical
00458         if(acos(normal.dot(up)) < abs(10 * M_PI/180)) 
00459         {
00460           data.unfitPointsCount += colCount;
00461           continue;
00462         }
00463 
00464         // define features in new basis that is oriented with the covariance
00465         for (int j = 0; j < colCount; ++j) 
00466         {
00467           data.warpedXYZ->col(j) = ((data.features.block(0,j,3,1) - keyPoint).transpose() * newBasis).transpose();
00468         }
00469       }
00470     }
00471     Vector angles(colCount), radii(colCount), heights(colCount);
00472     Matrix gestaltMeans(4, 8), gestaltVariances(4, 8), numOfValues(4, 8);
00473     if(keepGestaltFeatures) 
00474     {
00475       // calculate the polar coordinates of points
00476       angles = GestaltDataPointsFilter::calculateAngles(*data.warpedXYZ, keyPoint);
00477       radii = GestaltDataPointsFilter::calculateRadii(*data.warpedXYZ, keyPoint);
00478       heights = data.warpedXYZ->row(2);
00479 
00480       // sort points into Gestalt bins
00481       const T angularBinWidth = M_PI/4;
00482       const T radialBinWidth = radius/4;
00483       Matrix indices(2, colCount);
00484       gestaltMeans = Matrix::Zero(4, 8);
00485       gestaltVariances = Matrix::Zero(4, 8);
00486       numOfValues = Matrix::Zero(4, 8);
00487 
00488       for (int it=0; it < colCount; ++it) 
00489       {
00490         indices(0,it) = floor(radii(it)/radialBinWidth);
00491         // if value exceeds borders of bin -> put in outmost bin
00492         if(indices(0,it) > 3)
00493           // this case should never happen - just in case
00494           indices(0,it) = 3;
00495         indices(1,it) = floor(angles(it)/angularBinWidth);
00496         if(indices(1,it) > 7)
00497           indices(1,it) = 7;
00498         gestaltMeans(indices(0,it), indices(1,it)) += heights(it);
00499         ++(numOfValues(indices(0,it), indices(1,it)));
00500       }
00501 
00502       for (int radial=0; radial < 4; ++radial) 
00503       {
00504         for (int angular = 0; angular < 8; ++angular) 
00505         {
00506           if (numOfValues(radial, angular) > 0) 
00507           {
00508             gestaltMeans(radial, angular) = gestaltMeans(radial, angular)/numOfValues(radial, angular);
00509           }
00510         }
00511       }
00512       for (int it=0; it < colCount; ++it) 
00513       {
00514         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)));
00515       }
00516       for (int radial=0; radial < 4; ++radial) 
00517       {
00518         for (int angular = 0; angular < 8; ++angular) 
00519         {
00520           // if bins are == 0 -> propagate with value in bin closer to keypoint
00521           if (gestaltMeans(radial,angular) == 0 && radial > 0) 
00522           {
00523             gestaltMeans(radial, angular) = gestaltMeans(radial-1, angular);
00524             gestaltVariances(radial, angular) = gestaltVariances(radial-1, angular);
00525           } 
00526           else if (numOfValues(radial, angular) > 0) 
00527           {
00528             gestaltVariances(radial, angular) = gestaltVariances(radial, angular)/numOfValues(radial, angular);
00529           }
00530         }
00531       }
00532     }
00533     
00534     Vector serialEigVector;
00535     if(keepEigenVectors)
00536       serialEigVector = serializeEigVec<T>(eigenVe);
00537     Vector serialCovVector;
00538     if(keepCovariances)
00539       serialCovVector = serializeEigVec<T>(C);
00540     Vector serialGestaltMeans;
00541     Vector serialGestaltVariances;
00542     if(keepGestaltFeatures) 
00543     {
00544       serialGestaltMeans = GestaltDataPointsFilter::serializeGestaltMatrix(gestaltMeans);
00545       serialGestaltVariances = GestaltDataPointsFilter::serializeGestaltMatrix(gestaltVariances);
00546     }
00547     // some safety check
00548     if(data.descriptors.rows() != 0)
00549       assert(data.descriptors.cols() != 0);
00550 
00551     // write the updated times: min, max, mean
00552     data.times(0, data.indicesToKeep[i]) = minTime;
00553     data.times(1, data.indicesToKeep[i]) = maxTime;
00554     data.times(2, data.indicesToKeep[i]) = meanTime;
00555 
00556     // Build new descriptors
00557     if(keepNormals)
00558       data.normals->col(data.indicesToKeep[i]) = normal;
00559     if(keepMeans)
00560       data.means->col(data.indicesToKeep[i]) = mean;
00561     if(keepEigenValues)
00562       data.eigenValues->col(data.indicesToKeep[i]) = eigenVa;
00563     if(keepEigenVectors)
00564       data.eigenVectors->col(data.indicesToKeep[i]) = serialEigVector;
00565     if(keepCovariances)
00566       data.covariance->col(data.indicesToKeep[i]) = serialCovVector;
00567     if(keepGestaltFeatures) 
00568     {
00569       // preserve gestalt features
00570       data.gestaltMeans->col(data.indicesToKeep[i]) = serialGestaltMeans;
00571       data.gestaltVariances->col(data.indicesToKeep[i]) = serialGestaltVariances;
00572       (*data.gestaltShapes)(0,data.indicesToKeep[i]) = planarity;
00573       (*data.gestaltShapes)(1,data.indicesToKeep[i]) = cylindricality;
00574     }
00575     // all went well so far - so keep this keypoint
00576     indicesToKeepStrict.push_back(data.indicesToKeep[i]);
00577   }
00578   data.indicesToKeep = indicesToKeepStrict;
00579 }
00580 
00581 template<typename T>
00582 typename PointMatcher<T>::Vector
00583 GestaltDataPointsFilter<T>::serializeGestaltMatrix(const Matrix& gestaltFeatures) const
00584 {
00585   // serialize the gestalt descriptors
00586   const int dim = gestaltFeatures.rows() * gestaltFeatures.cols();
00587   Vector output(dim);
00588   for(int k=0; k < gestaltFeatures.rows(); ++k)
00589   {
00590     output.segment(k*gestaltFeatures.cols(), gestaltFeatures.cols()) =
00591         gestaltFeatures.row(k).transpose();
00592   }
00593   return output;
00594 }
00595 
00596 template<typename T>
00597 typename PointMatcher<T>::Vector
00598 GestaltDataPointsFilter<T>::calculateAngles(
00599         const Matrix& points, const Eigen::Matrix<T,3,1>& keyPoint) const
00600 {
00601         const unsigned int dim(points.cols());
00602   Vector angles(dim);
00603   
00604   for (unsigned int i = 0; i < dim; ++i) 
00605   {
00606     angles(i) = atan2(points(0,i), points(1,i));
00607     if (angles(i) < 0)
00608       angles(i) += (2 * M_PI);
00609   }
00610 
00611   return angles;
00612 }
00613 
00614 template<typename T>
00615 typename PointMatcher<T>::Vector
00616 GestaltDataPointsFilter<T>::calculateRadii(
00617         const Matrix& points, const Eigen::Matrix<T,3,1>& keyPoint) const
00618 {
00619         const unsigned int dim(points.cols());
00620   Vector radii(dim);
00621 
00622   for (unsigned int i = 0; i < dim; ++i) 
00623   {
00624     radii(i) = sqrt((points(0,i)) * (points(0,i)) + (points(1,i)) * (points(1,i)));
00625   }
00626   return radii;
00627 }
00628 
00629 template struct GestaltDataPointsFilter<float>;
00630 template struct GestaltDataPointsFilter<double>;


libpointmatcher
Author(s):
autogenerated on Thu Jun 20 2019 19:51:29