latest version v1.9 - last update 10 Apr 2010 |
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