PARP Research Group University of Murcia, Spain


src/qvmath/qvsampleconsensus.h

00001 /*
00002  *      Copyright (C) 2007, 2008, 2009. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00021 #ifndef QVRANSAC_H
00022 #define QVRANSAC_H
00023 
00024 #include <iostream>
00025 #include <QMap>
00026 
00027 #include <qvmath.h>
00028 
00122 template <typename Element, typename Model> class QVRANSAC
00123         {
00124         protected:
00125                 int sampleSetSize, minInliers, iteration;
00126 
00127                 // To use after initialization
00128                 QList< Element > elements;
00129                 bool continueCondition;
00130 
00131                 // To return to the user.
00132                 QList<Element> bestInliers;
00133                 Model bestModel;
00134 
00135                 #ifndef DOXYGEN_IGNORE_THIS
00136                 virtual bool init()
00137                         {
00138                         // Check if there are enough in-liners to work.
00139                         if (elements.size() < sampleSetSize)
00140                                 return continueCondition = false;
00141                         else
00142                                 return continueCondition = true;
00143                         }
00144 
00145 
00146                 virtual const QList< Element > getNewTentativeInliersSet()
00147                         {
00148                         QList< Element > result;
00149 
00150                         for (int i = 0; i < this->sampleSetSize; i++)
00151                                 result.append(this->elements.at( RANDOM(0, this->elements.size()-1) ));
00152 
00153                         return result;
00154                         }
00155                 #endif
00156 
00157         public:
00164                 QVRANSAC(const int sampleSetSize, const int minInliers):sampleSetSize(sampleSetSize), minInliers(minInliers) { }
00165 
00173                 virtual const bool fit(const QList<Element> &elementList, Model &model) = 0;
00174 
00182                 virtual const bool test(const Model &model, const Element &element, const QList<Element> &bestInliers) = 0;
00183 
00189                 void addElement(const Element &element)                                 { elements.append(element); }
00190 
00196                 const Model & getBestModel() const                                      { return bestModel; }
00197 
00203                 const QList<Element> & getBestInliers() const                           { return bestInliers; }
00204 
00210                 const int getIterations() const                                         { return iteration; }
00211 
00219                 const bool iterate(const int maxIterations)
00220                         {
00221                         if (!init())
00222                                 return false;
00223 
00224                         iteration = 0;
00225 
00226                         while(continueCondition && (iteration++) < maxIterations)
00227                                 {
00228                                 // Get new feasible maybe model.
00229                                 Model tentativeModel;
00230 
00231                                 // If no feasible model was found, continue with the next tentative set.
00232                                 if (!fit(getNewTentativeInliersSet(), tentativeModel))
00233                                         continue;
00234                 
00235                                 // Else, get consensus set.
00236                                 QList<Element> inliersSet;
00237                                 foreach (Element element, elements)
00238                                         if (test(tentativeModel, element, inliersSet))
00239                                                 inliersSet.append(element);
00240 
00241                                 // Get consensus model.
00242                                 if (inliersSet.size() >= minInliers )
00243                                         {
00244                                         fit(inliersSet, tentativeModel);
00245                                         bestModel = tentativeModel;
00246                                         bestInliers = inliersSet;
00247                                         return true;
00248                                         }
00249                                 }
00250 
00251                         return false;
00252                         }
00253         };
00254 
00278 template <typename Element, typename Model> class QVPROSAC: public QVRANSAC<Element, Model>
00279         {
00280         protected:
00281                 QMap<double, Element > elementsMap;
00282 
00283                 #ifndef DOXYGEN_IGNORE_THIS
00284                 virtual const QList< Element > getNewTentativeInliersSet()
00285                         {
00286                         const int maxSize = 2* log(this->getIterations()) / log(2);
00287                         QList< Element > result;
00288 
00289                         for (int i = 0; i < this->sampleSetSize; i++)
00290                                 result.append(this->elements.at( RANDOM(0, MAX(this->sampleSetSize, maxSize-1)) ));
00291 
00292                         return result;
00293                         }
00294 
00295                 bool init()
00296                         {
00297                         const QList<double> preferenceList = elementsMap.uniqueKeys();
00298                         for (int i = 0; i < preferenceList.size(); i++)
00299                                 this->elements += elementsMap.values(preferenceList.at(i));
00300 
00301                         return QVRANSAC<Element, Model>::init();
00302                         }
00303                 #endif
00304 
00305         public:
00312                 QVPROSAC(const int sampleSetSize, const int minInliers): QVRANSAC<Element, Model>(sampleSetSize, minInliers) { }
00313 
00321                 void addElement(const Element &element, const double preference = 0)
00322                         { elementsMap.insertMulti(preference, element); }
00323         };
00324 
00325 #endif



QVision framework. PARP research group, copyright 2007, 2008.