LTI-Lib latest version v1.9 - last update 10 Apr 2010

ltiFMatrixEstimatorBase.h

00001 /*
00002  * Copyright (C) 2004, 2005, 2006
00003  * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany
00004  *
00005  * This file is part of the LTI-Computer Vision Library (LTI-Lib)
00006  *
00007  * The LTI-Lib is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License (LGPL)
00009  * as published by the Free Software Foundation; either version 2.1 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * The LTI-Lib is distributed in the hope that it will be
00013  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00014  * of 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 the LTI-Lib; see the file LICENSE.  If
00019  * not, write to the Free Software Foundation, Inc., 59 Temple Place -
00020  * Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 
00024 /*--------------------------------------------------------------------
00025  * project ....: LTI-Lib: Image Processing and Computer Vision Library
00026  * file .......: ltiFMatrixEstimatorBase.h
00027  * authors ....: Stephanus Hendradji
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 15.7.2004
00030  * revisions ..: $Id: ltiFMatrixEstimatorBase.h,v 1.11 2006/02/08 11:04:48 ltilib Exp $
00031  */
00032 
00033 #ifndef _LTI_F_MATRIX_ESTIMATOR_BASE_H_
00034 #define _LTI_F_MATRIX_ESTIMATOR_BASE_H_
00035 
00036 #include "ltiTransformEstimator.h"
00037 #include "ltiUnifiedSVD.h"
00038 #include <limits>
00039 #include "ltiMath.h"
00040 
00041 #ifdef _LTI_MSC_VER
00042 #pragma warning(disable:4800)
00043 #endif
00044 
00045 #undef _LTI_DEBUG
00046 //#define _LTI_DEBUG 1
00047 #ifdef _LTI_DEBUG
00048 using std::endl;
00049 #endif
00050 
00051 #include "ltiDebug.h"
00052 
00053 namespace lti {
00054 
00055   /**
00056    * A base class for estimating the fundamental matrix with a least squares
00057    * approach. This class is here because a simultanous estimator for the
00058    * fundamental matrix and a radial distortion is planned.
00059    *
00060    * A note for developers of derived fmatrix classes: The header of this class
00061    * contains an hidden template base class for template helpers. This template
00062    * base helper must not be used by any classes other than least squares
00063    * fundamental matrix estimators, though. Therefore it is not included in the
00064    * doxygen documentation.
00065    */
00066   class fMatrixEstimatorBase : public transformEstimator {
00067   public:
00068     /**
00069      * The parameters for the class fMatrixEstimatorBase
00070      */
00071     class parameters : public transformEstimator::parameters {
00072     public:
00073       /**
00074        * Default constructor
00075        */
00076       parameters();
00077 
00078       /**
00079        * Copy constructor
00080        * @param other the parameters object to be copied
00081        */
00082       parameters(const parameters& other);
00083 
00084       /**
00085        * Destructor
00086        */
00087       ~parameters();
00088 
00089       /**
00090        * Returns name of this type
00091        */
00092       const char* getTypeName() const;
00093 
00094       /**
00095        * Copy the contents of a parameters object
00096        * @param other the parameters object to be copied
00097        * @return a reference to this parameters object
00098        */
00099       parameters& copy(const parameters& other);
00100 
00101       /**
00102        * Copy the contents of a parameters object
00103        * @param other the parameters object to be copied
00104        * @return a reference to this parameters object
00105        */
00106       parameters& operator=(const parameters& other);
00107 
00108 
00109       /**
00110        * Returns a pointer to a clone of the parameters
00111        */
00112       virtual functor::parameters* clone() const;
00113 
00114       /**
00115        * Write the parameters in the given ioHandler
00116        * @param handler the ioHandler to be used
00117        * @param complete if true (the default) the enclosing begin/end will
00118        *        be also written, otherwise only the data block will be written.
00119        * @return true if write was successful
00120        */
00121       virtual bool write(ioHandler& handler,const bool complete=true) const;
00122 
00123       /**
00124        * Read the parameters from the given ioHandler
00125        * @param handler the ioHandler to be used
00126        * @param complete if true (the default) the enclosing begin/end will
00127        *        be also written, otherwise only the data block will be written.
00128        * @return true if write was successful
00129        */
00130       virtual bool read(ioHandler& handler,const bool complete=true);
00131 
00132 #     ifdef _LTI_MSC_6
00133       /**
00134        * This function is required by MSVC only, as a workaround for a
00135        * very awful bug, which exists since MSVC V.4.0, and still by
00136        * V.6.0 with all bugfixes (so called "service packs") remains
00137        * there...  This method is also public due to another bug, so please
00138        * NEVER EVER call this method directly: use read() instead
00139        */
00140       bool readMS(ioHandler& handler,const bool complete=true);
00141 
00142       /**
00143        * This function is required by MSVC only, as a workaround for a
00144        * very awful bug, which exists since MSVC V.4.0, and still by
00145        * V.6.0 with all bugfixes (so called "service packs") remains
00146        * there...  This method is also public due to another bug, so please
00147        * NEVER EVER call this method directly: use write() instead
00148        */
00149       bool writeMS(ioHandler& handler,const bool complete=true) const;
00150 #     endif
00151 
00152       // ------------------------------------------------
00153       // the parameters
00154       // ------------------------------------------------
00155 
00156       /**
00157        * The rank 2 constraint may be enforced by the frobenius norm or
00158        * T-parameterization.
00159        */
00160       enum eRank2Type { Frobenius, TParameterization };
00161       
00162       /**
00163        * Several ways exist to enforce the rank 2 constraint.
00164        * E.g. the fundamental matrix may be replaced by the closest fundamental
00165        * matrix under the frobenius norm. A different approach is to replace
00166        * one row and one column by a linear combination of the other two. This
00167        * is called T-parameterization. The frobenius norm is computational more
00168        * efficient whereas T-parameterization is reported to produce more 
00169        * accurate results, e.g. when combined with a maximum likelyhood
00170        * estimator. But with an inaccurate fmatrix estimate the
00171        * Frobenius norm works better.
00172        * Default: Frobenius.
00173        */
00174       eRank2Type rank2Enforcement;
00175 
00176       /**
00177        * The distance measure to be used when computing the residual: Sampson
00178        * or epipolar distance.
00179        */
00180       enum eDistanceType { Sampson, Epipolar };
00181 
00182       /**
00183        * The distance measure to be used when computing the residual. The
00184        * Sampson distance is reported to be superior when iteratively refining
00185        * the fundamental matrix (e.g. Hartley, Zisserman: 3D Computer Vision),
00186        * whereas the epipolar distance is equivalent to the residual.
00187        * Default: Epipolar.
00188        */
00189       eDistanceType distanceMeasure;
00190 
00191     };
00192 
00193     /**
00194      * Default constructor
00195      */
00196     fMatrixEstimatorBase();
00197 
00198     /**
00199      * Construct a functor using the given parameters
00200      */
00201     fMatrixEstimatorBase(const parameters& par);
00202 
00203     /**
00204      * Copy constructor
00205      * @param other the object to be copied
00206      */
00207     fMatrixEstimatorBase(const fMatrixEstimatorBase& other);
00208 
00209     /**
00210      * Destructor
00211      */
00212     virtual ~fMatrixEstimatorBase();
00213 
00214     /**
00215      * Returns the name of this type ("fMatrixEstimatorBase")
00216      */
00217     virtual const char* getTypeName() const;
00218 
00219  
00220     /**
00221      * Estimates a transform from the supplied point sets, where all
00222      * points are considered. Please implement efficient code using
00223      * iterators here. Not all robust estimators use a random sampling
00224      * approach. Some estimators consider all input points and weight them
00225      * according to their deviation from the transform computed at the prior
00226      * iteration.
00227      *
00228      * All points of one point set give a matrix row, whereas all elements
00229      * of a specifec correspondence stand in a matrix column.
00230      *
00231      * @param src  matrix<ipoint> with the point sets. All points of the same
00232      *    image stand in a row. The correspondences in another image stand in
00233      *    the according columns.
00234      * @param dest fvector the estimated transform.
00235      * @return true if the transform could be estimated and false otherwise.
00236      */
00237     virtual bool apply(const matrix<ipoint>& src,
00238                        fvector& dest) const = 0;
00239 
00240     /**
00241      * Estimates a transform from the supplied point sets, where all
00242      * points are considered. Usually this method calls the apply without
00243      * the residual first, and then computes the residual.
00244      * @param src  matrix<ipoint> with the point sets. All points of the same
00245      *             image stand in a row. The correspondences in another image
00246      *             stand in the according columns.  All points of one point
00247      *             set give a matrix row, whereas all elements of a specific
00248      *             correspondence stand in a matrix column.
00249      * @param dest fvector the estimated transform.
00250      * @param error fvector containing the deviation of each point from the
00251      *              estimated transform. Usually this is the residual or
00252      *              elementwise squared residual.
00253      * @return true if the transform could be estimated and false otherwise.
00254      */
00255     virtual bool apply(const matrix<ipoint>& src,
00256                        fvector& dest, fvector& error) const = 0;
00257 
00258     /**
00259      * Estimates a transform from the supplied point sets, whereby only
00260      * the points specified in the index vector are considered. This method
00261      * is used by robost estimators using a monte carlo approach.
00262      *
00263      * All points of one point set give a matrix row, whereas all elements
00264      * of a specifec correspondence stand in a matrix column.
00265      *
00266      * @param src  matrix<ipoint> with the point sets. All points of the same
00267      *    image stand in a row. The correspondences in another image stand in
00268      *    the according columns.
00269      * @param dest fvector the estimated transform.
00270      * @param indices ivector with the indices of the relevant points.
00271      * @param numCorrespondences the first numCorrespondences indices are
00272      *                            considered.
00273      * @return true if the transform could be estimated and false otherwise.
00274      */
00275     virtual bool apply(const matrix<ipoint>& src,
00276                        fvector& dest,
00277                        const ivector& indices,
00278                        int numCorrespondences) const = 0;
00279 
00280     /**
00281      * Estimates a transform from the supplied point sets, whereby only
00282      * the points specified in the index vector are considered. Usually this
00283      * method calls the apply without the residual first, and then computes
00284      * the residual.
00285      *
00286      * All points of one point set give a matrix row, whereas all elements
00287      * of a specifec correspondence stand in a matrix column.
00288      *
00289      * @param src  matrix<ipoint> with the point sets. All points of the same
00290      *    image stand in a row. The correspondences in another image stand in
00291      *    the according columns.
00292      * @param dest fvector the estimated transform.
00293      * @param error fvector containing the deviation of each point from the
00294      *              estimated transform. Usually this is the residual or
00295      *              elementwise squared residual. All correspondences are
00296      *              considered, discarding the valid indices.
00297      * @param indices ivector with the indices of the relevant points.
00298      * @param numCorrespondences the first numCorrespondences indices are
00299      *                            considered.
00300      * @return true if the transform could be estimated and false otherwise.
00301      */
00302     virtual bool apply(const matrix<ipoint>& src,
00303                        fvector& dest, fvector& error,
00304                        const ivector& indices,
00305                        int numCorrespondences) const = 0;
00306 
00307     /**
00308      * Estimates a transform from the supplied point sets, where all
00309      * points are considered. Please implement efficient code using
00310      * iterators here. Not all robust estimators use a random sampling
00311      * approach. Some estimators consider all input points and weight them
00312      * according to their deviation from the transform computed at the prior
00313      * iteration.
00314      *
00315      * All points of one point set give a matrix row, whereas all elements
00316      * of a specifec correspondence stand in a matrix column.
00317      *
00318      * @param src  matrix<fpoint> with the point sets. All points of the same
00319      *    image stand in a row. The correspondences in another image stand in
00320      *    the according columns.
00321      * @param dest fvector the estimated transform.
00322      * @return true if the transform could be estimated and false otherwise.
00323      */
00324     virtual bool apply(const matrix<fpoint>& src,
00325                        fvector& dest) const = 0;
00326 
00327     /**
00328      * Estimates a transform from the supplied point sets, where all
00329      * points are considered. Usually this method calls the apply without
00330      * the residual first, and then computes the residual.
00331      * @param src  matrix<fpoint> with the point sets. All points of the same
00332      *             image stand in a row. The correspondences in another image 
00333      *             stand in the according columns.
00334      *             All points of one point set give a matrix row, whereas all
00335      *             elements of a specific correspondence stand in a matrix
00336      *             column.
00337      * @param dest fvector the estimated transform.
00338      * @param error fvector containing the deviation of each point from the
00339      *              estimated transform. Usually this is the residual or
00340      *              elementwise squared residual.
00341      * @return true if the transform could be estimated and false otherwise.
00342      */
00343     virtual bool apply(const matrix<fpoint>& src,
00344                        fvector& dest, fvector& error) const = 0;
00345 
00346     /**
00347      * Estimates a transform from the supplied point sets, whereby only
00348      * the points specified in the index vector are considered. This method
00349      * is used by robost estimators using a monte carlo approach.
00350      *
00351      * All points of one point set give a matrix row, whereas all elements
00352      * of a specifec correspondence stand in a matrix column.
00353      *
00354      * @param src  matrix<dpoint> with the point sets. All points of the same
00355      *    image stand in a row. The correspondences in another image stand in
00356      *    the according columns.
00357      * @param dest fvector the estimated transform.
00358      * @param indices ivector with the indices of the relevant points.
00359      * @param numCorrespondences the first numCorrespondences indices are
00360      *                            considered.
00361      * @return true if the transform could be estimated and false otherwise.
00362      */
00363     virtual bool apply(const matrix<fpoint>& src,
00364                        fvector& dest,
00365                        const ivector& indices,
00366                        int numCorrespondences) const = 0;
00367 
00368     /**
00369      * Estimates a transform from the supplied point sets, whereby only
00370      * the points specified in the index vector are considered. Usually this
00371      * method calls the apply without the residual first, and then computes
00372      * the residual.
00373      *
00374      * All points of one point set give a matrix row, whereas all elements
00375      * of a specifec correspondence stand in a matrix column.
00376      *
00377      * @param src  matrix<fpoint> with the point sets. All points of the same
00378      *    image stand in a row. The correspondences in another image stand in
00379      *    the according columns.
00380      * @param dest fvector the estimated transform.
00381      * @param error fvector containing the deviation of each point from the
00382      *              estimated transform. Usually this is the residual or
00383      *              elementwise squared residual. All correspondences are
00384      *              considered, discarding the valid indices.
00385      * @param indices ivector with the indices of the relevant points.
00386      * @param numCorrespondences the first numCorrespondences indices are
00387      *                            considered.
00388      * @return true if the transform could be estimated and false otherwise.
00389      */
00390     virtual bool apply(const matrix<fpoint>& src,
00391                        fvector& dest, fvector& error,
00392                        const ivector& indices,
00393                        int numCorrespondences) const = 0;
00394 
00395     /**
00396      * Estimates a transform from the supplied point sets, where all
00397      * points are considered. Please implement efficient code using
00398      * iterators here. Not all robust estimators use a random sampling
00399      * approach. Some estimators consider all input points and weight them
00400      * according to their deviation from the transform computed at the prior
00401      * iteration.
00402      *
00403      * All points of one point set give a matrix row, whereas all elements
00404      * of a specifec correspondence stand in a matrix column.
00405      *
00406      * @param src  matrix<dpoint> with the point sets. All points of the same
00407      *    image stand in a row. The correspondences in another image stand in
00408      *    the according columns.
00409      * @param dest dvector the estimated transform.
00410      * @return true if the transform could be estimated and false otherwise.
00411      */
00412     virtual bool apply(const matrix<dpoint>& src,
00413                        dvector& dest) const = 0;
00414 
00415     /**
00416      * Estimates a transform from the supplied point sets, where all
00417      * points are considered. Usually this method calls the apply without
00418      * the residual first, and then computes the residual.
00419      *
00420      * All points of one point set give a matrix row, whereas all elements
00421      * of a specifec correspondence stand in a matrix column.
00422      *
00423      * @param src  matrix<dpoint> with the point sets. All points of the same
00424      *    image stand in a row. The correspondences in another image stand in
00425      *    the according columns.
00426      * @param dest dvector the estimated transform.
00427      * @param error dvector containing the deviation of each point from the
00428      *              estimated transform. Usually this is the residual or
00429      *              elementwise squared residual.
00430      * @return true if the transform could be estimated and false otherwise.
00431      */
00432     virtual bool apply(const matrix<dpoint>& src,
00433                        dvector& dest, dvector& error) const = 0;
00434 
00435     /**
00436      * Estimates a transform from the supplied point sets, whereby only
00437      * the points specified in the index vector are considered. This method
00438      * is used by robost estimators using a monte carlo approach.
00439      *
00440      * All points of one point set give a matrix row, whereas all elements
00441      * of a specifec correspondence stand in a matrix column.
00442      *
00443      * @param src  matrix<dpoint> with the point sets. All points of the same
00444      *    image stand in a row. The correspondences in another image stand in
00445      *    the according columns.
00446      * @param dest dvector the estimated transform.
00447      * @param indices which rows of the src matrix have to be considered.
00448      * @param numCorrespondences the first numCorrespondences indices are
00449      *                            considered.
00450      * @return true if the transform could be estimated and false otherwise.
00451      */
00452     virtual bool apply(const matrix<dpoint>& src,
00453                        dvector& dest,
00454                        const ivector& indices,
00455                        int numCorrespondences) const = 0;
00456 
00457     /**
00458      * Estimates a transform from the supplied point sets, whereby only
00459      * the points specified in the index vector are considered. Usually this
00460      * method calls the apply without the residual first, and then computes
00461      * the residual.
00462      *
00463      * All points of one point set give a matrix row, whereas all elements
00464      * of a specifec correspondence stand in a matrix column.
00465      *
00466      * @param src  matrix<dpoint> with the point sets. All points of the same
00467      *    image stand in a row. The correspondences in another image stand in
00468      *    the according columns.
00469      * @param dest dvector the estimated transform.
00470      * @param error dvector containing the deviation of each point from the
00471      *              estimated transform. Usually this is the residual or
00472      *              elementwise squared residual.
00473      * @param indices ivector with the indices of the relevant points.
00474      * @param numCorrespondences the first numCorrespondences indices are
00475      *                            considered.
00476      * @return true if the transform could be estimated and false otherwise.
00477      */
00478     virtual bool apply(const matrix<dpoint>& src,
00479                        dvector& dest, dvector& error,
00480                        const ivector& indices,
00481                        int numCorrespondences) const = 0;
00482 
00483     /**
00484      * Compute the residual for the given correspondences and transformation
00485      * vector.
00486      * @param src matrix<fpoint> with the point sets. All points of the same
00487      *    image stand in a row. The correspondences in another image stand in
00488      *    the according columns.
00489      * @param transform fvector with the transformation
00490      * @param dest      fvector with the residual
00491      * @return true on success and false otherwise.
00492      */
00493     virtual bool computeResidual(const matrix<fpoint >& src,
00494                                     const fvector& transform,
00495                                     fvector& dest) const = 0;
00496 
00497     /**
00498      * Compute the residual for the given correspondences and transformation
00499      * vector.
00500      * @param src matrix<dpoint> with the point sets. All points of the same
00501      *    image stand in a row. The correspondences in another image stand in
00502      *    the according columns.
00503      * @param transform dvector with the transformation
00504      * @param dest      dvector with the residual
00505      * @return true on success and false otherwise.
00506      */
00507     virtual bool computeResidual(const matrix<dpoint >& src,
00508                                     const dvector& transform,
00509                                     dvector& dest) const = 0;
00510     
00511     /**
00512      * Returns the minimum number of correspondences required to estimate
00513      * the transform.
00514      */
00515     virtual int minNumberCorrespondences() const = 0;
00516 
00517     /**
00518      * Returns the mininum dimension of a correspondence,
00519      * e.g. the minimum dimension of a correspondence pair is 2.
00520      * Each derived transform estimator only works on correspondences of
00521      * priori defined dimensions.
00522      */
00523     virtual int minCorrespondenceDimension() const = 0;
00524 
00525     /**
00526      * Returns the maximum dimension of a correspondence,
00527      * e.g. the maximum dimension of a correspondence pair is 2, whereas
00528      * transformEstimator running on n-tuples may allow an infinite number.
00529      * Each derived transform estimator only works on correspondences of
00530      * priori defined dimensions.
00531      */
00532     virtual int maxCorrespondenceDimension() const = 0;
00533 
00534     /**
00535      * A transform estimated on normalized data usually differs from
00536      * the transform of the original data. Considering the normalization
00537      * performed this methods computes the transform which applies to the
00538      * original data.
00539      * @param srcdest the normalized transform. The result will be left here
00540      *     too.
00541      * @param scale a vector containing the scale applied to each point set.
00542      * @param shift a vector containing the shift of each scaled point set.
00543      */
00544     virtual bool denormalize(fvector& srcdest,
00545                              const vector<fpoint>& scale,
00546                              const vector<fpoint>& shift) const = 0;
00547     
00548     /**
00549      * A transform estimated on normalized data usually differs from
00550      * the transform of the original data. Considering the normalization
00551      * performed this methods computes the transform which applies to the
00552      * original data.
00553      * @param srcdest the normalized transform. The result will be left here
00554      *     too.
00555      * @param scale a vector containing the scale applied to each point set.
00556      * @param shift a vector containing the shift of each scaled point set.
00557      */
00558     virtual bool denormalize(dvector& srcdest,
00559                              const vector<dpoint>& scale,
00560                              const vector<dpoint>& shift) const = 0;  
00561 
00562     /**
00563      * Copy data of "other" functor.
00564      * @param other the functor to be copied
00565      * @return a reference to this functor object
00566      */
00567     fMatrixEstimatorBase& copy(const fMatrixEstimatorBase& other);
00568 
00569     /**
00570      * Alias for copy member
00571      * @param other the functor to be copied
00572      * @return a reference to this functor object
00573      */
00574     fMatrixEstimatorBase& operator=(const fMatrixEstimatorBase& other);
00575 
00576     /**
00577      * Returns a pointer to a clone of this functor.
00578      */
00579     virtual functor* clone() const = 0;
00580 
00581     /**
00582      * Returns used parameters
00583      */
00584     const parameters& getParameters() const;
00585 
00586   };
00587 
00588   /*
00589    *  A small template class that provides methods to enforce the
00590    *  singularaty of the fundamental matrix and other things common to
00591    *  fundamental matrix esimators.
00592    *
00593    *  Actually this class is at the level of a helper class,
00594    *  but it is required by several helper templates of fundamental estimators.
00595    *  Therefore this class is here and documented properly.
00596    */
00597   template<class T, class U>
00598   class fMatBaseHelper {
00599   public:
00600     fMatBaseHelper(const fMatrixEstimatorBase::parameters par) :
00601       computeSqError_   ( par.computeSqError ),
00602       rank2Enforcement_ ( par.rank2Enforcement),
00603       distanceMeasure_ ( par.distanceMeasure ) {
00604     };
00605 
00606     ~fMatBaseHelper() {
00607     };
00608 
00609     /*
00610      * To remember error messages.
00611      */
00612     std::string statusString;
00613 
00614   protected:
00615 
00616     /*
00617      * Compute a squared error for efficiency?
00618      */
00619     bool computeSqError_;
00620 
00621     /*
00622      * How shall we enforce singularity?
00623      */
00624     fMatrixEstimatorBase::parameters::eRank2Type rank2Enforcement_;
00625 
00626     /*
00627      * Which error measure is used?
00628      */
00629     bool distanceMeasure_;
00630 
00631     /*
00632      * Initialize the design matrix A for fundamental matrix computation.
00633      * As only A_transposed * A is processed further on, it is computed
00634      * directly from the point correspondences, without setting up A first.
00635      * CAUTION: returns transposed At_A for efficiency
00636      */
00637     void initialize(const matrix<tpoint<U> >& src, matrix<T>& At_A) const;
00638 
00639     /*
00640      * Initialize A_transposed * A as described above. But this time only
00641      * a subset of the correspondences are used. This subset is specified
00642      * by the first n entries of the index vector.
00643      * CAUTION: returns transposed At_A for efficiency
00644      */
00645     void initialize(const matrix<tpoint<U> >& src, const ivector& indices,
00646                     const int numCorrespondences, matrix<T>& At_A) const;
00647 
00648     /*
00649      * Enforce singularity, i.e. rank 2. How this will be done is specified
00650      * in the parameters.
00651      * CAUTION: input is transposed fmatrix, output is fmatrix
00652      */
00653     bool enforceSingularity(vector<T>& src);
00654 
00655     /*
00656      * Enforces singularity, i.e. rank 2, by frobenius norm.
00657      * CAUTION: input is transposed fmatrix, output is fmatrix
00658      */
00659     bool frobenius(vector<T>& src) const;
00660 
00661     /*
00662      * Enforces rank 2 by T-parameterization.
00663      * CAUTION: input is transposed fmatrix, output is fmatrix
00664      */
00665     bool tParameterization(vector<T>& src);
00666 
00667   private:
00668     /*
00669      * Compute the tParameterization for one permutation of the fmatrix.
00670      */
00671     bool oneTParameterization(matrix<T>&  src,
00672                               vector<T>& lambda, vector<T>& mu, T& norm);
00673 
00674     //todo: the epipole methods should be moved into a fmatrix-class,
00675     //      which provides useful methods when working with fmatrices.
00676     // e.g. compute epipoles, compute epipolar lines, extract homography,
00677     // extract trivial set of camera projection matrices.
00678 
00679     /*
00680      * Compute the epipoles by solving F*e = 0 with 3 degrees of freedom
00681      * and setting the 3rd coordinate equal 1 afterwards.
00682      */
00683     bool computeEpipoles3Dof(const matrix<T>& src, 
00684                          vector<T>& epipole1, vector<T>& epipole2);
00685 
00686     /*
00687      * Normalize the epipole (3rd coordinate equals 1)
00688      */
00689     bool normalizeEpipole(vector<T>& srcdest) const;
00690 
00691     /*
00692      * Compute the epipoles by solving [F1 F2] *e = [F3], i.e. with
00693      * 2 degrees of freedom. This method is more accurate for inaccurate
00694      * fundamental matrices (todo: verify on more data).
00695      */
00696     bool computeEpipoles2Dof(const matrix<T>& src, 
00697                      vector<T>& epipole1, vector<T>& epipole2);
00698 
00699     /*
00700      * Solve the equation system A * x = b by singular value decomposition,
00701      * i.e. x = v * w_inverse * u_transposed * b.
00702      */
00703     bool solveAXEqualsB(const matrix<T>& src, vector<T>& b, vector<T>& dest);
00704   };
00705 
00706   //------------------------
00707   // singularity enforcement
00708   //------------------------
00709 
00710   template<class T, class U>
00711   inline bool fMatBaseHelper<T,U>::enforceSingularity(vector<T>& src) {
00712 
00713     if ( rank2Enforcement_ == fMatrixEstimatorBase::parameters::Frobenius ) {
00714       return frobenius(src);
00715     } else {
00716       return tParameterization(src);
00717     }
00718   }
00719 
00720   template<class T, class U>
00721   inline bool fMatBaseHelper<T,U>::frobenius(vector<T>& src) const {
00722 
00723     matrix<T> fmat;
00724     fmat.useExternData(3,3,&src.at(0));
00725     _lti_debug(" old fmatrix:\n" << fmat << std::endl);
00726 
00727     matrix<T> u;    //eigenvectors
00728     matrix<T> v;    //left hand singular vectors
00729     vector<T> w;    //eigenvalues
00730     typename unifiedSVD<T>::parameters svdPara;
00731     svdPara.sort = true;
00732     svdPara.transposeU = true;  //faster; Ut is returned
00733     unifiedSVD<T> svd ( svdPara );
00734     if (!svd.apply(fmat,u,w,v)) {
00735       return false;
00736     }
00737 
00738     _lti_debug(" frobenius variances are:\n" << w
00739                << "\n ...setting 3rd value to 0 now\n");
00740 
00741     //set the 3rd variance to zero and new fmatrix is u*diag(w)*v
00742     T& s1 = w.at(0);
00743     T& s2 = w.at(1);
00744 
00745     //because u is transposed due to efficiency
00746     typename matrix<T>::iterator it ( u.begin() );
00747     *it     *= s1;  *(++it) *= s1;  *(++it) *= s1;
00748     *(++it) *= s2;  *(++it) *= s2,  *(++it) *= s2;
00749     *(++it) *= T(0);  *(++it) *= T(0);  *(++it) *= T(0);
00750     v.multiply(u);
00751 
00752     //copy back into src; OK because fmat not used anymore
00753     //necessary because v is local
00754     //v.transpose();
00755     v.detach(src);
00756   
00757     _lti_debug(" new fmatrix:\n" << src << std::endl);
00758 
00759     return true;
00760   }
00761 
00762   //===================
00763   // T-parameterization
00764   //===================
00765 
00766   template<class T, class U>
00767   inline bool fMatBaseHelper<T,U>::tParameterization(vector<T>& src) {
00768  
00769     //maximize over all possible T-parameterizations
00770     //CAUTION: the input fmatrix is transposed
00771 
00772     //the implementation could be optimized if computing the epipoles
00773     // by computeEpipole3Dof. In this case they need only be computed
00774     // once.
00775 
00776     //possible optimization for computeEpipole2Dof:
00777     //compute the one epipole for the 3 permutions of the rows and the
00778     //other for the 3 permutations of the columns
00779     
00780     //_lti_debug(" *** tpara *** old fmatrix " << endl << src << endl);
00781     T winningNorm ( T(0) );
00782     matrix<T> fmat ( false, 3, 3 );
00783     for ( int row (0); row<3; ++row ) {
00784       for ( int col (0); col<3; ++col ) {
00785         _lti_debug(" row " << row << " col " << col << endl);
00786         //shuffel the fundamental matrix
00787         // such that the last row and column are parameterized
00788         //caution: the input fundamenal matrix is tranposed !!!
00789         matrix<T> shuffelF (false,3,3);
00790         for ( int r ( 0 ); r < 3; ++r ) {
00791           const int usedCol ( (row + r + 1) % 3 );
00792           typename vector<T>::iterator it ( shuffelF.getRow(r).begin() );
00793           for ( int c ( 0 ); c < 3; ++c, ++it ) {
00794             const int usedRow ( ((col + c + 1) % 3) * 3 );
00795             *it = src.at(usedCol + usedRow );
00796           }//for c
00797         }//for r
00798         //_lti_debug("shuffeled at " << row << " " << col << endl
00799         //   << shuffelF << endl);
00800 
00801         T norm;
00802         vector<T> lambda, mu;
00803         if ( oneTParameterization(shuffelF,lambda, mu, norm) &&
00804              norm > winningNorm ) {
00805           //remember the new fundamental matrix - maximize norm
00806           winningNorm = norm;
00807           //init. parameterized row
00808           vector<T>& parRowVect = fmat.getRow(row);//parameterized row
00809           typename vector<T>::iterator fit ( parRowVect.begin() );
00810           *fit = T(0); *(++fit) = T(0); *(++fit) = T(0);
00811           for ( int r ( 0 ); r < 2; ++r ) {
00812             int usedRow ( ( row + r + 1) % 3 );
00813             vector<T>& newVect = fmat.getRow(usedRow);
00814             newVect.at(col) = T(0);
00815             typename vector<T>::iterator it ( shuffelF.getRow(r).begin() );
00816             //parameterized column
00817             for ( int c ( 0 ); c < 2; ++c, ++it ) {
00818               const int usedCol ( (col + c + 1) % 3 );
00819               newVect.at(usedCol) = *it;
00820               newVect.at(col) -= lambda.at(c) * *it;
00821               parRowVect.at(usedCol) -= mu.at(r) * *it;
00822             }//for c 
00823             //parametrized by row and column
00824             parRowVect.at(col) -=  mu.at(r) * newVect.at(col);
00825           }//for r
00826           //_lti_debug(" updated fmatrix " << row << " " << col 
00827           //     << " val " << norm << endl << fmat << endl);
00828         }
00829       }
00830     }
00831 
00832     //move the new fmatrix into the src (without copying)
00833     fmat.detach(src);
00834 
00835     return true;
00836   }
00837 
00838   template<class T, class U>
00839   inline bool fMatBaseHelper<T,U>
00840     ::oneTParameterization(matrix<T>&  src,
00841                            vector<T>& lambda, vector<T>& mu, T& norm) {
00842 
00843     const T epsilon ( std::numeric_limits<T>::epsilon() );
00844 
00845     //compute the row- and columnwise parameterizations
00846     //todo: which is better? with an initial FMatrix: 2Dof is more accurate;
00847     //      both result in poorer epipolar lines than frobenius
00848     //if ( !computeEpipoles2Dof(src, mu, lambda) ) {
00849     if ( !computeEpipoles3Dof(src, mu, lambda) ) {
00850       statusString += "\nCould not compute epipoles";
00851       return false;
00852     }
00853 
00854     //normalize by setting the largest value 1
00855     //thus the conditioning below will be (approx.) scale invariant
00856     typename matrix<T>::iterator it ( src.begin() );
00857     T maxEntry ( abs(*it) );
00858     maxEntry = max ( maxEntry, abs(*(++it)) );
00859     ++it; //igonre 3rd column
00860     maxEntry = max ( maxEntry, abs(*(++it)) );
00861     maxEntry = max ( maxEntry, abs(*(++it)) );
00862     //_lti_debug(" maxEntry " << maxEntry << " src " << endl << src << endl);
00863 
00864     if ( maxEntry > -epsilon && maxEntry < epsilon ) {
00865       statusString += "\nAll 4 FMatrix values are 0";
00866       return false;
00867     }
00868     //normalization is performed parallel to conditioning
00869     //choose best conditioned Jacobian matrix,
00870     //i.e. compute norm of the vector with determinants of the 8x8 submatrices
00871     it = src.begin();
00872     *it /= maxEntry;
00873     const T& f1 = *it;
00874     *(++it) /= maxEntry;
00875     const T& f2 = *it;
00876     ++it; //igonre 3rd column
00877     *(++it) /= maxEntry;
00878     norm = f2 * *(it);
00879     *(++it) /= maxEntry;
00880     norm += f1 * *(it);
00881     norm *= norm;
00882 
00883 //     typename vector<T>::const_iterator lit ( lambda.begin() );
00884 //     typename vector<T>::const_iterator mit ( mu.begin() );
00885 //     norm += sqrt( sqr(*lit) + sqr(*(++lit)) + 1)
00886 //       * sqrt( sqr(*mit) + sqr(*(++mit)) + 1);
00887 
00888     const T l0=lambda.at(0);
00889     const T l1=lambda.at(1);
00890     const T m0=mu.at(0);
00891     const T m1=mu.at(1);
00892     norm += sqrt(l0*l0 + l1*l1 + 1) * sqrt(m0*m0 + m1*m1 + 1);
00893 
00894     _lti_debug(" lambda " << lambda << " mu " << mu << endl);
00895     //_lti_debug(" norm and fmat (7-point) " << norm << endl << src << endl);
00896 
00897     return true;
00898   }
00899 
00900   //todo: which is epipole1 and epipole2
00901   //for compatibility with the method below this would be inversed ???
00902   template<class T, class U>
00903     inline bool fMatBaseHelper<T,U>::computeEpipoles2Dof(const matrix<T>& src, 
00904                                                          vector<T>& epipole1,
00905                                                          vector<T>& epipole2) {
00906 
00907     //seperate fmatrix into first two and third column
00908     matrix<T> a ( false, 3, 2);
00909     vector<T> b ( false, 3);
00910     typename matrix<T>::iterator aend ( a.end() );
00911     typename matrix<T>::iterator ait ( a.begin() );
00912     typename vector<T>::iterator bit ( b.begin() );
00913     typename matrix<T>::const_iterator fit ( src.begin() );
00914     for ( ; ait!=aend; ++ait,++bit,++fit ) {
00915       *ait = *fit;
00916       *(++ait) = *(++fit);
00917       *bit = *(++fit);
00918     }
00919     if ( !solveAXEqualsB(a,b,epipole2) ) {
00920       return false;
00921     }
00922 
00923     //seperate fmatrix into first two and third row
00924     a.copy(src, 0, 1, 0, 2);
00925     a.transpose();
00926     b.copy(src.getRow(2));
00927     if ( !solveAXEqualsB(a,b,epipole1) ) {
00928       return false;
00929     }
00930 
00931     return true;
00932   }
00933 
00934   template<class T, class U>
00935   inline bool fMatBaseHelper<T,U>
00936     ::solveAXEqualsB(const matrix<T>& src, vector<T>& b, vector<T>& dest) {
00937  
00938     matrix<T> u;    //eigenvectors
00939     matrix<T> v;    //left hand singular vectors
00940     vector<T> w;    //eigenvalues
00941     typename unifiedSVD<T>::parameters svdPara;
00942     svdPara.sort = true;
00943     svdPara.transposeU = true;
00944 
00945     unifiedSVD<T> svd ( svdPara );
00946     if (!svd.apply(src,u,w,v)) {
00947       statusString += svd.getStatusString();
00948       return false;
00949     }
00950     //invert w
00951     typename vector<T>::iterator it ( w.begin() );
00952     typename vector<T>::iterator end ( w.end() );
00953     for ( ; it!=end; ++it ) {
00954       const T epsilon ( std::numeric_limits<T>::epsilon() );
00955       if ( *it > -epsilon && *it < epsilon ) {
00956         *it = T(0);
00957       } else {
00958         *it = - T(1) / *it; //change sign because we solve for -b
00959       }
00960     }
00961     u.multiply(b);  //leaves the result in b
00962     w.emultiply(b); //elementwise multiply
00963     v.multiply(w);  //leaves the result in w
00964     w.detach(dest);
00965 
00966     return true;
00967   }
00968 
00969   template<class T, class U>
00970   inline bool fMatBaseHelper<T,U>
00971     ::computeEpipoles3Dof(const matrix<T>& src, 
00972                           vector<T>& epipole1, vector<T>& epipole2) {
00973     
00974     matrix<T> u;    //eigenvectors
00975     matrix<T> v;    //left hand singular vectors
00976     vector<T> w;    //eigenvalues
00977     typename unifiedSVD<T>::parameters svdPara;
00978     svdPara.sort = true;
00979     svdPara.transposeU = true;  //faster; Ut is returned
00980     unifiedSVD<T> svd ( svdPara );
00981     if (!svd.apply(src,u,w,v)) {
00982       statusString += svd.getStatusString();
00983       return false;
00984     }
00985 
00986     // epipole2_t * F * epipole1 = 0
00987 
00988     //epipole1 is the left eigenvector with least eigenvalue
00989     //the u-matrix is transposed, so use the last row
00990     epipole1.copy(u.getRow(u.lastRow()));
00991 
00992     //epipole2 is the right eigenvector with the least eigenvalue
00993     //get the last column
00994     epipole2.resize( 3, T(0), false, false );
00995     typename vector<T>::iterator it  ( epipole2.begin() );
00996     typename matrix<T>::iterator vit ( v.begin() );
00997     vit += 2; //move to last column
00998     *it = *vit; vit += 3; //move to next row
00999     *(++it) = *vit; vit += 3; //move to next row
01000     *(++it) = *vit;
01001   
01002     //_lti_debug(" u " << endl << u << endl << " v " << endl << v << endl);
01003     _lti_debug(" epipole1 " << epipole1 <<
01004                " epipole2 " << epipole2 << endl);
01005     
01006     //we do not normalize the epipoles if they are the plane of inifinity
01007     return normalizeEpipole(epipole1) && normalizeEpipole(epipole2);
01008   }
01009 
01010   template<class T, class U>
01011     inline bool fMatBaseHelper<T,U>
01012     ::normalizeEpipole(vector<T>& srcdest) const {
01013   
01014     const T epsilon ( std::numeric_limits<T>::epsilon() );
01015     const T& tmp = srcdest.at(2);
01016     if ( tmp < -epsilon || tmp > epsilon ) {
01017       typename vector<T>::iterator it ( srcdest.begin() );
01018       *it /= tmp;
01019       *(++it) /= tmp;
01020       *(++it ) = T(1);
01021       return true;
01022     } 
01023 
01024     //if e[3] is 0 then the columns/rows corresponding to e[0] and e[1] are
01025     //lineary dependent -> epipole at plane of infinity
01026     return false;
01027   }
01028   
01029   //------------------
01030   //the initialization
01031   //------------------
01032 
01033   template<class T, class U>
01034   inline void fMatBaseHelper<T,U>::initialize(const matrix<tpoint<U> >& src,
01035                                               matrix<T>& AtA) const {
01036 
01037     //initialize A_transponed * A
01038     //AtA is composed of 6 symmetric submatrices
01039     //        | m11  m21  m31 |
01040     // AtA =  | m21  m22  m32 |
01041     //        | m31  m32  m33 |
01042 
01043     //---------------------------------------------------
01044     //references for fast access of the vector's elements
01045     //---------------------------------------------------
01046     AtA.resize(9,9, T(0), false, true);  //initialize all with 0
01047     typename matrix<T>::iterator it ( AtA.begin() );
01048     //1st row
01049     T& m11_0 = *it;
01050     T& m11_1 = *(++it);
01051     T& m11_2 = *(++it);
01052     T& m21_0 = *(++it);
01053     T& m21_1 = *(++it);
01054     T& m21_2 = *(++it);
01055     T& m31_0 = *(++it);
01056     T& m31_1 = *(++it);
01057     T& m31_2 = *(++it);
01058 
01059     //2nd row
01060     T& a21   = *(++it);       //duplicate due to symmetry
01061     T& m11_3 = *(++it);
01062     T& m11_4 = *(++it);
01063     T& a24   = *(++it);       //duplicate due to symmetry
01064     T& m21_3 = *(++it);
01065     T& m21_4 = *(++it);
01066     T& a27   = *(++it);       //duplicate due to symmetry
01067     T& m31_3 = *(++it);
01068     T& m31_4 = *(++it);
01069 
01070     //3rd row
01071     T& a31   = *(++it);      //duplicate due to symmetry
01072     T& a32   = *(++it);      //duplicate due to symmetry
01073     T& m11_5 = *(++it);
01074     T& a34   = *(++it);      //duplicate due to symmetry
01075     T& a35   = *(++it);      //duplicate due to symmetry
01076     T& m21_5 = *(++it);
01077     T& a37   = *(++it);      //duplicate due to symmetry
01078     T& a38   = *(++it);      //duplicate due to symmetry
01079     T& m31_5 = *(++it);
01080     
01081     //4th row
01082     T& a41   = *(++it);      //duplicate due to symmetry
01083     T& a42   = *(++it);      //duplicate due to symmetry
01084     T& a43   = *(++it);      //duplicate due to symmetry
01085     T& m22_0 = *(++it);
01086     T& m22_1 = *(++it);
01087     T& m22_2 = *(++it);    
01088     T& m32_0 = *(++it);
01089     T& m32_1 = *(++it);
01090     T& m32_2 = *(++it);  
01091 
01092     //5th row
01093     T& a51   = *(++it);      //duplicate due to symmetry
01094     T& a52   = *(++it);      //duplicate due to symmetry
01095     T& a53   = *(++it);      //duplicate due to symmetry
01096     T& a54   = *(++it);      //duplicate due to symmetry
01097     T& m22_3 = *(++it);
01098     T& m22_4 = *(++it);    
01099     T& a57   = *(++it);      //duplicate due to symmetry
01100     T& m32_3 = *(++it);
01101     T& m32_4 = *(++it);
01102 
01103     //6th row
01104     T& a61   = *(++it);      //duplicate due to symmetry
01105     T& a62   = *(++it);      //duplicate due to symmetry
01106     T& a63   = *(++it);      //duplicate due to symmetry
01107     T& a64   = *(++it);      //duplicate due to symmetry
01108     T& a65   = *(++it);      //duplicate due to symmetry
01109     T& m22_5 = *(++it);
01110     T& a67   = *(++it);      //duplicate due to symmetry
01111     T& a68   = *(++it);      //duplicate due to symmetry
01112     T& m32_5 = *(++it);
01113 
01114     //7th row
01115     T& a71   = *(++it);      //duplicate due to symmetry
01116     T& a72   = *(++it);      //duplicate due to symmetry
01117     T& a73   = *(++it);      //duplicate due to symmetry
01118     T& a74   = *(++it);      //duplicate due to symmetry
01119     T& a75   = *(++it);      //duplicate due to symmetry
01120     T& a76   = *(++it);      //duplicate due to symmetry
01121     T& m33_0 = *(++it);
01122     T& m33_1 = *(++it);
01123     T& m33_2 = *(++it);
01124 
01125     //8th row
01126     T& a81   = *(++it);      //duplicate due to symmetry
01127     T& a82   = *(++it);      //duplicate due to symmetry
01128     T& a83   = *(++it);      //duplicate due to symmetry
01129     T& a84   = *(++it);      //duplicate due to symmetry
01130     T& a85   = *(++it);      //duplicate due to symmetry
01131     T& a86   = *(++it);      //duplicate due to symmetry
01132     T& a87   = *(++it);      //duplicate due to symmetry
01133     T& m33_3 = *(++it);
01134     T& m33_4 = *(++it);
01135 
01136     //9th row
01137     T& a91   = *(++it);      //duplicate due to symmetry
01138     T& a92   = *(++it);      //duplicate due to symmetry
01139     T& a93   = *(++it);      //duplicate due to symmetry
01140     T& a94   = *(++it);      //duplicate due to symmetry
01141     T& a95   = *(++it);      //duplicate due to symmetry
01142     T& a96   = *(++it);      //duplicate due to symmetry
01143     T& a97   = *(++it);      //duplicate due to symmetry
01144     T& a98   = *(++it);      //duplicate due to symmetry
01145     *(++it)  = static_cast<T>(src.columns());
01146 
01147     //--------------------
01148     //init all submatrices
01149     //--------------------
01150 
01151     const vector<tpoint<U> >& pts1 = src.getRow(0);
01152     const vector<tpoint<U> >& pts2 = src.getRow(1);
01153     typename vector<tpoint<U> >::const_iterator end ( pts1.end()   );
01154     typename vector<tpoint<U> >::const_iterator it1 ( pts1.begin() );
01155     typename vector<tpoint<U> >::const_iterator it2 ( pts2.begin() );
01156     
01157     for (; it1!=end; ++it1, ++it2) {
01158       //indices 1 and 2 are crossed because we compute a transposed fmatrix
01159       //due to efficiency of frobenius singularity enforcement
01160       const T x1 ( static_cast<T>((*it2).x) );
01161       const T y1 ( static_cast<T>((*it2).y) );
01162       const T sqX1 ( x1*x1 );
01163       const T sqY1 ( y1*y1 );
01164       const T x1Y1 ( x1*y1 );
01165 
01166       const T x2 ( static_cast<T>((*it1).x) );
01167       const T y2 ( static_cast<T>((*it1).y) );
01168       const T sqX2 ( x2*x2 );
01169       const T sqY2 ( y2*y2 );
01170       const T x2Y2 ( x2*y2 );
01171 
01172       //design matrix after Zisserman (if it1 and it2 were not crossed)
01173       m11_0 += sqX1 * sqX2;
01174       m11_1 += x1Y1 * sqX2;
01175       m11_2 += x1   * sqX2;
01176       m11_3 += sqY1 * sqX2;
01177       m11_4 += y1   * sqX2;
01178       m11_5 += sqX2;
01179  
01180       m21_0 += sqX1 * x2Y2;
01181       m21_1 += x1Y1 * x2Y2;
01182       m21_2 += x1   * x2Y2;
01183       m21_3 += sqY1 * x2Y2;
01184       m21_4 += y1   * x2Y2;
01185       m21_5 += x2Y2;
01186 
01187       m31_0 += sqX1 * x2;
01188       m31_1 += x1Y1 * x2;
01189       m31_2 += x1   * x2;
01190       m31_3 += sqY1 * x2;
01191       m31_4 += y1   * x2;
01192       m31_5 += x2;
01193   
01194       m22_0 += sqX1 * sqY2;
01195       m22_1 += x1Y1 * sqY2;
01196       m22_2 += x1   * sqY2;
01197       m22_3 += sqY1 * sqY2;
01198       m22_4 += y1   * sqY2;
01199       m22_5 += sqY2;
01200 
01201       m32_0 += sqX1 * y2;
01202       m32_1 += x1Y1 * y2;
01203       m32_2 += x1   * y2;
01204       m32_3 += sqY1 * y2;
01205       m32_4 += y1   * y2;
01206       m32_5 += y2;
01207 
01208       m33_0 += sqX1;
01209       m33_1 += x1Y1;
01210       m33_2 += x1;
01211       m33_3 += sqY1;
01212       m33_4 += y1;
01213     }
01214 
01215     //-------------------------------------------------
01216     //initialize symmetric elements of A_transponed * A
01217     //-------------------------------------------------
01218     //2nd row
01219     a21 = m11_1;
01220     a24 = m21_1;
01221     a27 = m31_1;
01222     //3rd row
01223     a31 = m11_2; a32 = m11_4;
01224     a34 = m21_2; a35 = m21_4;
01225     a37 = m31_2; a38 = m31_4;
01226     
01227     //4th row
01228     a41 = m21_0; a42 = m21_1; a43 = m21_2;
01229     //5th row
01230     a51 = m21_1;   a52 = m21_3; a53 = m21_4;
01231     a54 = m22_1;
01232     a57 = m32_1;
01233     //6th row
01234     a61 = m21_2; a62 = m21_4;   a63 = m21_5;
01235     a64 = m22_2; a65 = m22_4;
01236     a67 = m32_2; a68 = m32_4;
01237 
01238     //7th row
01239     a71 = m31_0; a72 = m31_1; a73 = m31_2;
01240     a74 = m32_0; a75 = m32_1; a76 = m32_2;
01241     //8th row 
01242     a81 = m31_1; a82 = m31_3; a83 = m31_4;
01243     a84 = m32_1; a85 = m32_3; a86 = m32_4;
01244     a87 = m33_1;
01245     //9th row
01246     a91 = m31_2; a92 = m31_4; a93 = m31_5;
01247     a94 = m32_2; a95 = m32_4; a96 = m32_5;
01248     a97 = m33_2; a98 = m33_4;
01249 
01250 #if defined(_LTI_DEBUG) && (_LTI_DEBUG > 3)
01251     cout << " At_A " << AtA << endl;
01252 #endif
01253   }
01254 
01255   template<class T, class U>
01256   inline void fMatBaseHelper<T,U>
01257   ::initialize(const matrix<tpoint<U> >& src, const ivector& indices,
01258                const int numCorrespondences, matrix<T>& AtA) const {
01259     
01260     //re-implemented due to efficiency
01261 
01262     //initialize A_transponed * A
01263     //AtA is composed of 6 symmetric submatrices
01264     //        | m11  m21  m31 |
01265     // AtA =  | m21  m22  m32 |
01266     //        | m31  m32  m33 |
01267 
01268     //---------------------------------------------------
01269     //references for fast access of the vector's elements
01270     //---------------------------------------------------
01271     AtA.resize(9,9, T(0), false, true);  //initialize all with 0
01272     typename matrix<T>::iterator it ( AtA.begin() );
01273     //1st row
01274     T& m11_0 = *it;
01275     T& m11_1 = *(++it);
01276     T& m11_2 = *(++it);
01277     T& m21_0 = *(++it);
01278     T& m21_1 = *(++it);
01279     T& m21_2 = *(++it);
01280     T& m31_0 = *(++it);
01281     T& m31_1 = *(++it);
01282     T& m31_2 = *(++it);
01283 
01284     //2nd row
01285     T& a21   = *(++it);       //duplicate due to symmetry
01286     T& m11_3 = *(++it);
01287     T& m11_4 = *(++it);
01288     T& a24   = *(++it);       //duplicate due to symmetry
01289     T& m21_3 = *(++it);
01290     T& m21_4 = *(++it);
01291     T& a27   = *(++it);       //duplicate due to symmetry
01292     T& m31_3 = *(++it);
01293     T& m31_4 = *(++it);
01294 
01295     //3rd row
01296     T& a31   = *(++it);      //duplicate due to symmetry
01297     T& a32   = *(++it);      //duplicate due to symmetry
01298     T& m11_5 = *(++it);
01299     T& a34   = *(++it);      //duplicate due to symmetry
01300     T& a35   = *(++it);      //duplicate due to symmetry
01301     T& m21_5 = *(++it);
01302     T& a37   = *(++it);      //duplicate due to symmetry
01303     T& a38   = *(++it);      //duplicate due to symmetry
01304     T& m31_5 = *(++it);
01305     
01306     //4th row
01307     T& a41   = *(++it);      //duplicate due to symmetry
01308     T& a42   = *(++it);      //duplicate due to symmetry
01309     T& a43   = *(++it);      //duplicate due to symmetry
01310     T& m22_0 = *(++it);
01311     T& m22_1 = *(++it);
01312     T& m22_2 = *(++it);    
01313     T& m32_0 = *(++it);
01314     T& m32_1 = *(++it);
01315     T& m32_2 = *(++it);  
01316 
01317     //5th row
01318     T& a51   = *(++it);      //duplicate due to symmetry
01319     T& a52   = *(++it);      //duplicate due to symmetry
01320     T& a53   = *(++it);      //duplicate due to symmetry
01321     T& a54   = *(++it);      //duplicate due to symmetry
01322     T& m22_3 = *(++it);
01323     T& m22_4 = *(++it);    
01324     T& a57   = *(++it);      //duplicate due to symmetry
01325     T& m32_3 = *(++it);
01326     T& m32_4 = *(++it);
01327 
01328     //6th row
01329     T& a61   = *(++it);      //duplicate due to symmetry
01330     T& a62   = *(++it);      //duplicate due to symmetry
01331     T& a63   = *(++it);      //duplicate due to symmetry
01332     T& a64   = *(++it);      //duplicate due to symmetry
01333     T& a65   = *(++it);      //duplicate due to symmetry
01334     T& m22_5 = *(++it);
01335     T& a67   = *(++it);      //duplicate due to symmetry
01336     T& a68   = *(++it);      //duplicate due to symmetry
01337     T& m32_5 = *(++it);
01338 
01339     //7th row
01340     T& a71   = *(++it);      //duplicate due to symmetry
01341     T& a72   = *(++it);      //duplicate due to symmetry
01342     T& a73   = *(++it);      //duplicate due to symmetry
01343     T& a74   = *(++it);      //duplicate due to symmetry
01344     T& a75   = *(++it);      //duplicate due to symmetry
01345     T& a76   = *(++it);      //duplicate due to symmetry
01346     T& m33_0 = *(++it);
01347     T& m33_1 = *(++it);
01348     T& m33_2 = *(++it);
01349 
01350     //8th row
01351     T& a81   = *(++it);      //duplicate due to symmetry
01352     T& a82   = *(++it);      //duplicate due to symmetry
01353     T& a83   = *(++it);      //duplicate due to symmetry
01354     T& a84   = *(++it);      //duplicate due to symmetry
01355     T& a85   = *(++it);      //duplicate due to symmetry
01356     T& a86   = *(++it);      //duplicate due to symmetry
01357     T& a87   = *(++it);      //duplicate due to symmetry
01358     T& m33_3 = *(++it);
01359     T& m33_4 = *(++it);
01360 
01361     //9th row
01362     T& a91   = *(++it);      //duplicate due to symmetry
01363     T& a92   = *(++it);      //duplicate due to symmetry
01364     T& a93   = *(++it);      //duplicate due to symmetry
01365     T& a94   = *(++it);      //duplicate due to symmetry
01366     T& a95   = *(++it);      //duplicate due to symmetry
01367     T& a96   = *(++it);      //duplicate due to symmetry
01368     T& a97   = *(++it);      //duplicate due to symmetry
01369     T& a98   = *(++it);      //duplicate due to symmetry
01370     *(++it)  = static_cast<T>(numCorrespondences);
01371 
01372     //--------------------
01373     //init all submatrices
01374     //--------------------
01375 
01376     const vector<tpoint<U> >& pts1 = src.getRow(0);
01377     const vector<tpoint<U> >& pts2 = src.getRow(1);
01378     typename ivector::const_iterator iit  ( indices.begin() );
01379     typename ivector::const_iterator iend ( iit + numCorrespondences );
01380     for (; iit!=iend; ++iit) {
01381       //indices 1 and 2 are crossed because we compute a transposed fmatrix
01382       //due to efficiency of frobenius singularity enforcement
01383       const tpoint<U>& pt1 = pts2.at(*iit);
01384       const T x1 ( static_cast<T>(pt1.x) );
01385       const T y1 ( static_cast<T>(pt1.y) );
01386       const T sqX1 ( x1*x1 );
01387       const T sqY1 ( y1*y1 );
01388       const T x1Y1 ( x1*y1 );
01389 
01390       const tpoint<U>& pt2 = pts1.at(*iit);
01391       const T x2 ( static_cast<T>(pt2.x) );
01392       const T y2 ( static_cast<T>(pt2.y) );
01393       const T sqX2 ( x2*x2 );
01394       const T sqY2 ( y2*y2 );
01395       const T x2Y2 ( x2*y2 );
01396 
01397      //design matrix after Zisserman (if it1 and it2 were not crossed)
01398       m11_0 += sqX1 * sqX2;
01399       m11_1 += x1Y1 * sqX2;
01400       m11_2 += x1   * sqX2;
01401       m11_3 += sqY1 * sqX2;
01402       m11_4 += y1   * sqX2;
01403       m11_5 += sqX2;
01404  
01405       m21_0 += sqX1 * x2Y2;
01406       m21_1 += x1Y1 * x2Y2;
01407       m21_2 += x1   * x2Y2;
01408       m21_3 += sqY1 * x2Y2;
01409       m21_4 += y1   * x2Y2;
01410       m21_5 += x2Y2;
01411 
01412       m31_0 += sqX1 * x2;
01413       m31_1 += x1Y1 * x2;
01414       m31_2 += x1   * x2;
01415       m31_3 += sqY1 * x2;
01416       m31_4 += y1   * x2;
01417       m31_5 += x2;
01418   
01419       m22_0 += sqX1 * sqY2;
01420       m22_1 += x1Y1 * sqY2;
01421       m22_2 += x1   * sqY2;
01422       m22_3 += sqY1 * sqY2;
01423       m22_4 += y1   * sqY2;
01424       m22_5 += sqY2;
01425 
01426       m32_0 += sqX1 * y2;
01427       m32_1 += x1Y1 * y2;
01428       m32_2 += x1   * y2;
01429       m32_3 += sqY1 * y2;
01430       m32_4 += y1   * y2;
01431       m32_5 += y2;
01432 
01433       m33_0 += sqX1;
01434       m33_1 += x1Y1;
01435       m33_2 += x1;
01436       m33_3 += sqY1;
01437       m33_4 += y1;
01438     }
01439 
01440     //-------------------------------------------------
01441     //initialize symmetric elements of A_transponed * A
01442     //-------------------------------------------------
01443     //2nd row
01444     a21 = m11_1;
01445     a24 = m21_1;
01446     a27 = m31_1;
01447     //3rd row
01448     a31 = m11_2; a32 = m11_4;
01449     a34 = m21_2; a35 = m21_4;
01450     a37 = m31_2; a38 = m31_4;
01451     
01452     //4th row
01453     a41 = m21_0; a42 = m21_1; a43 = m21_2;
01454     //5th row
01455     a51 = m21_1;   a52 = m21_3; a53 = m21_4;
01456     a54 = m22_1;
01457     a57 = m32_1;
01458     //6th row
01459     a61 = m21_2; a62 = m21_4;   a63 = m21_5;
01460     a64 = m22_2; a65 = m22_4;
01461     a67 = m32_2; a68 = m32_4;
01462 
01463     //7th row
01464     a71 = m31_0; a72 = m31_1; a73 = m31_2;
01465     a74 = m32_0; a75 = m32_1; a76 = m32_2;
01466     //8th row 
01467     a81 = m31_1; a82 = m31_3; a83 = m31_4;
01468     a84 = m32_1; a85 = m32_3; a86 = m32_4;
01469     a87 = m33_1;
01470     //9th row
01471     a91 = m31_2; a92 = m31_4; a93 = m31_5;
01472     a94 = m32_2; a95 = m32_4; a96 = m32_5;
01473     a97 = m33_2; a98 = m33_4;
01474 
01475 #if defined(_LTI_DEBUG) && (_LTI_DEBUG > 3)
01476     cout << " At_A " << AtA << endl;
01477 #endif
01478   }
01479 
01480 }
01481 
01482 #include "ltiUndebug.h"
01483 #endif

Generated on Sat Apr 10 15:25:31 2010 for LTI-Lib by Doxygen 1.6.1