OctreeGrid.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 "OctreeGrid.h"
00036 
00037 #include <limits>
00038 
00039 //Define Visitor classes to apply processing
00040 template<typename T>
00041 OctreeGridDataPointsFilter<T>::FirstPtsSampler::FirstPtsSampler(DataPoints& dp) 
00042         : idx{0}, pts(dp) 
00043 {
00044 }
00045 
00046 template <typename T>
00047 template<std::size_t dim>
00048 bool OctreeGridDataPointsFilter<T>::FirstPtsSampler::operator()(Octree_<T,dim>& oc)
00049 {
00050         if(oc.isLeaf() and not oc.isEmpty())
00051         {                       
00052                 auto* data = oc.getData();      
00053                 const auto& d = (*data)[0];
00054                 
00055                 std::size_t j = d;
00056                 
00057                 //retrieve index from lookup table if sampling in already switched element
00058                 if(std::size_t(d)<idx)
00059                         j = mapidx[d];
00060                         
00061                 //Switch columns j and idx
00062                 pts.swapCols(idx, j);
00063                                 
00064                 //Maintain new index position   
00065                 mapidx[idx] = j;
00066                 //Update index
00067                 ++idx;          
00068         }
00069         
00070         return true;
00071 }
00072  
00073 template <typename T>
00074 bool OctreeGridDataPointsFilter<T>::FirstPtsSampler::finalize()
00075 {
00076         //Resize point cloud
00077         pts.conservativeResize(idx);
00078         //Reset param
00079         idx=0;
00080         return true;
00081 }
00082 
00083 
00084 template<typename T>
00085 OctreeGridDataPointsFilter<T>::RandomPtsSampler::RandomPtsSampler(DataPoints& dp) 
00086         : OctreeGridDataPointsFilter<T>::FirstPtsSampler{dp}, seed{1}
00087 {
00088         std::srand(seed);
00089 }
00090 template<typename T>
00091 OctreeGridDataPointsFilter<T>::RandomPtsSampler::RandomPtsSampler(
00092         DataPoints& dp, const std::size_t seed_
00093 ): OctreeGridDataPointsFilter<T>::FirstPtsSampler{dp}, seed{seed_}
00094 {
00095         std::srand(seed);
00096 }
00097 template<typename T>
00098 template<std::size_t dim>
00099 bool OctreeGridDataPointsFilter<T>::RandomPtsSampler::operator()(Octree_<T,dim>& oc)
00100 {
00101         if(oc.isLeaf() and not oc.isEmpty())
00102         {                       
00103                 auto* data = oc.getData();
00104                 const std::size_t nbData = (*data).size() - 1;
00105                 const std::size_t randId = 
00106                         static_cast<std::size_t>( nbData * 
00107                                 (static_cast<float>(std::rand()/static_cast<float>(RAND_MAX))));
00108                                 
00109                 const auto& d = (*data)[randId];
00110                 
00111                 std::size_t j = d;
00112                 
00113                 //retrieve index from lookup table if sampling in already switched element
00114                 if(std::size_t(d)<idx)
00115                         j = mapidx[d];
00116                         
00117                 //Switch columns j and idx
00118                 pts.swapCols(idx, j);   
00119                 
00120                 //Maintain new index position   
00121                 mapidx[idx] = j;
00122                 //Update index
00123                 ++idx;          
00124         }
00125         
00126         return true;
00127 }
00128         
00129 template<typename T>
00130 bool OctreeGridDataPointsFilter<T>::RandomPtsSampler::finalize()
00131 {
00132         bool ret = FirstPtsSampler::finalize();
00133         //Reset seed
00134         std::srand(seed);
00135         
00136         return ret;                     
00137 }
00138 
00139 template<typename T>
00140 OctreeGridDataPointsFilter<T>::CentroidSampler::CentroidSampler(DataPoints& dp)  
00141         : OctreeGridDataPointsFilter<T>::FirstPtsSampler{dp}
00142 {
00143 }
00144         
00145 template<typename T>
00146 template<std::size_t dim>
00147 bool OctreeGridDataPointsFilter<T>::CentroidSampler::operator()(Octree_<T,dim>& oc)
00148 {
00149         if(oc.isLeaf() and not oc.isEmpty())
00150         {                       
00151                 const int featDim(pts.features.rows());
00152                 const int descDim(pts.descriptors.rows());
00153                 const int timeDim(pts.times.rows());
00154                 
00155                 auto* data = oc.getData();
00156                 const std::size_t nbData = (*data).size();
00157                         
00158                 const auto& d = (*data)[0]; //get first data
00159                 std::size_t j = d; //j contains real index of first point
00160                 
00161                 //retrieve index from lookup table if sampling in already switched element
00162                 if(std::size_t(d)<idx)
00163                         j = mapidx[d];
00164                 
00165                 //We sum all the data in the first data
00166                 for(std::size_t id=1;id<nbData;++id)
00167                 {
00168                         //get current idx
00169                         const auto& curId = (*data)[id];
00170                         std::size_t i = curId; //i contains real index
00171                         
00172                         //retrieve index from lookup table if sampling in already switched element
00173                         if(std::size_t(curId)<idx)
00174                                 i = mapidx[curId];
00175                         
00176                         for (int f = 0; f < (featDim - 1); ++f)
00177                                 pts.features(f,j) += pts.features(f,i);
00178                         
00179                         if (pts.descriptors.cols() > 0)
00180                                 for (int d = 0; d < descDim; ++d)
00181                                         pts.descriptors(d,j) += pts.descriptors(d,i);
00182                         
00183                         if (pts.times.cols() > 0)
00184                                 for (int t = 0; t < timeDim; ++t)
00185                                         pts.times(t,j) += pts.times(t,i);       
00186                 }
00187                 
00188                 // Normalize sums to get centroid (average)
00189                 for (int f = 0; f < (featDim - 1); ++f)
00190                         pts.features(f,j) /= T(nbData);
00191                 
00192                 if (pts.descriptors.cols() > 0)
00193                         for (int d = 0; d < descDim; ++d)
00194                                 pts.descriptors(d,j) /= T(nbData);
00195                 
00196                 if (pts.times.cols() > 0)
00197                         for (int t = 0; t < timeDim; ++t)
00198                                 pts.times(t,j) /= T(nbData);    
00199                                                                 
00200                 //Switch columns j and idx
00201                 pts.swapCols(idx, j);
00202                 
00203                 //Maintain new index position   
00204                 mapidx[idx] = j;
00205                 //Update index
00206                 ++idx;          
00207         }
00208         
00209         return true;
00210 }
00211 template<typename T>
00212 OctreeGridDataPointsFilter<T>::MedoidSampler::MedoidSampler(DataPoints& dp)  
00213         : OctreeGridDataPointsFilter<T>::FirstPtsSampler{dp}
00214 {
00215 }
00216         
00217 template<typename T>
00218 template<std::size_t dim>
00219 bool OctreeGridDataPointsFilter<T>::MedoidSampler::operator()(Octree_<T,dim>& oc)
00220 {
00221         if(oc.isLeaf() and not oc.isEmpty())
00222         {               
00223                 auto* data = oc.getData();
00224                 const std::size_t nbData = (*data).size();
00225 
00226                 auto dist = [](const typename Octree_<T,dim>::Point& p1, const typename Octree_<T,dim>::Point& p2) -> T {               
00227                                 return (p1 - p2).norm();                
00228                         };
00229                         
00230                 //Build centroid
00231                 typename Octree_<T,dim>::Point center;
00232                 for(std::size_t i=0;i<dim;++i) center(i)=T(0.);
00233                 
00234                 for(std::size_t id=0;id<nbData;++id)
00235                 {
00236                         //get current idx
00237                         const auto& curId = (*data)[id];
00238                         std::size_t i = curId; //i contains real index
00239                         
00240                         //retrieve index from lookup table if sampling in already switched element
00241                         if(std::size_t(curId)<idx)
00242                                 i = mapidx[curId];
00243                         
00244                         for (std::size_t f = 0; f < dim; ++f)
00245                                 center(f) += pts.features(f,i); 
00246                 }
00247                 for(std::size_t i=0;i<dim;++i) center(i)/=T(nbData);
00248                 
00249                 //Get the closest point from the center 
00250                 T minDist = std::numeric_limits<T>::max();
00251                 std::size_t medId = 0;
00252                         
00253                 for(std::size_t id=0;id<nbData;++id)
00254                 {
00255                         //get current idx
00256                         const auto curId = (*data)[id];
00257                         std::size_t i = curId; //i contains real index
00258                         
00259                         //retrieve index from lookup table if sampling in already switched element
00260                         if(std::size_t(curId)<idx)
00261                                 i = mapidx[curId];
00262                                 
00263                         const T curDist = dist(pts.features.col(i).head(dim), center);
00264                         if(curDist<minDist)
00265                         {
00266                                 minDist = curDist;
00267                                 medId=i;
00268                         }
00269                 }
00270                                 
00271                 //Switch columns j and idx
00272                 pts.swapCols(idx, medId);
00273         
00274                 //Maintain new index position   
00275                 mapidx[idx] = medId;
00276         
00277                 //Update index
00278                 ++idx;          
00279         }
00280 
00281         return true;
00282 }
00283 
00284 // OctreeGridDataPointsFilter
00285 template <typename T>
00286 OctreeGridDataPointsFilter<T>::OctreeGridDataPointsFilter(const Parameters& params) :
00287         PointMatcher<T>::DataPointsFilter("OctreeGridDataPointsFilter", 
00288                 OctreeGridDataPointsFilter::availableParameters(), params),
00289         buildParallel{Parametrizable::get<bool>("buildParallel")},
00290         maxPointByNode{Parametrizable::get<std::size_t>("maxPointByNode")},
00291         maxSizeByNode{Parametrizable::get<T>("maxSizeByNode")}
00292 {
00293         try 
00294         {
00295                 const int sm = this->template get<int>("samplingMethod");
00296                 samplingMethod = SamplingMethod(sm);
00297         }
00298         catch (const InvalidParameter& e) 
00299         {
00300                 samplingMethod = SamplingMethod::FIRST_PTS;
00301         }
00302 }
00303 
00304 template <typename T>
00305 typename PointMatcher<T>::DataPoints
00306 OctreeGridDataPointsFilter<T>::filter(const DataPoints& input)
00307 {
00308         DataPoints output(input);
00309         inPlaceFilter(output);
00310         return output;
00311 }
00312 
00313 template <typename T>
00314 void OctreeGridDataPointsFilter<T>::inPlaceFilter(DataPoints& cloud)
00315 {
00316         const std::size_t featDim = cloud.features.rows();
00317         
00318         assert(featDim == 4 or featDim == 3);
00319 
00320         if(featDim==3) //2D case
00321                 this->sample<2>(cloud);
00322                 
00323         else if(featDim==4) //3D case
00324                 this->sample<3>(cloud);
00325 }
00326 
00327 template<typename T>
00328 template<std::size_t dim>
00329 void OctreeGridDataPointsFilter<T>::sample(DataPoints& cloud)
00330 {
00331         Octree_<T,dim> oc;
00332         
00333         oc.build(cloud, maxPointByNode, maxSizeByNode, buildParallel);
00334         
00335         switch(samplingMethod)
00336         {
00337                 case SamplingMethod::FIRST_PTS:
00338                 {
00339                         FirstPtsSampler sampler(cloud);
00340                         oc.visit(sampler);
00341                         sampler.finalize();
00342                         break;
00343                 }
00344                 case SamplingMethod::RAND_PTS:
00345                 {
00346                         RandomPtsSampler sampler(cloud); //FIXME: add seed parameter
00347                         oc.visit(sampler);
00348                         sampler.finalize();
00349                         break;
00350                 }
00351                 case SamplingMethod::CENTROID:
00352                 {
00353                         CentroidSampler sampler(cloud);
00354                         oc.visit(sampler);
00355                         sampler.finalize();
00356                         break;
00357                 }
00358                 case SamplingMethod::MEDOID:
00359                 {
00360                         MedoidSampler sampler(cloud);
00361                         oc.visit(sampler);
00362                         sampler.finalize();
00363                         break;
00364                 }
00365         }
00366 }
00367 
00368 
00369 template struct OctreeGridDataPointsFilter<float>;
00370 template struct OctreeGridDataPointsFilter<double>;


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