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 .......: ltiHomography8DofEstimator.h 00027 * authors ....: Claudia Goenner 00028 * organization: LTI, RWTH Aachen 00029 * creation ...: 14.4.2004 00030 * revisions ..: $Id: ltiHomography8DofEstimator.h,v 1.12 2006/02/08 11:17:12 ltilib Exp $ 00031 */ 00032 00033 #ifndef _LTI_HOMOGRAPHY8_DOF_ESTIMATOR_H_ 00034 #define _LTI_HOMOGRAPHY8_DOF_ESTIMATOR_H_ 00035 00036 #include "ltiHomographyEstimatorBase.h" 00037 #include "ltiHTypes.h" 00038 00039 namespace lti { 00040 /** 00041 * This class computes the parameters of the perspective transformation 00042 * between two images using a non-homogenous approach and least squares. 00043 * This works fine for translational and rotational camera movement, but 00044 * in case of zooming it might result in a degenerate configuration. Please 00045 * use the homography9DofEstimator (work in progress) instead. 00046 * 00047 * The implementation is based on a block oriented cholesky decompostion. 00048 * Details about the implemented least squares approach can be found in 00049 * 00050 * Claudia Goenner, "Approximation der Parameter fuer die 00051 * zentralperspektivische Abbildung durch Minimierung des mittleren 00052 * quadratischen Fehlers", 00053 * Studienarbeit, Mathematisch-Naturwissenschaftliche Fakultaet, 00054 * RWTH Aachen, 1996. 00055 * 00056 * and 00057 * 00058 * Thomas Lehmann, 00059 * "Geometrische Ausrichtung medizinischer Bilder am Beispiel intraoraler 00060 * Radiographien", pp. 71-73. Aachener Informatik Berichte 98-9, 00061 * RWTH Aachen, 1998. 00062 * 00063 * CAVEAT: This class is a port from old C-code and 00064 * contains some potential for speed up. 00065 * 00066 * @see lti::geometricTransform 00067 */ 00068 class homography8DofEstimator : public homographyEstimatorBase { 00069 public: 00070 /** 00071 * The parameters for the class homography8DofEstimator 00072 */ 00073 class parameters : public homographyEstimatorBase::parameters { 00074 public: 00075 /** 00076 * Default constructor 00077 */ 00078 parameters(); 00079 00080 /** 00081 * Copy constructor 00082 * @param other the parameters object to be copied 00083 */ 00084 parameters(const parameters& other); 00085 00086 /** 00087 * Destructor 00088 */ 00089 ~parameters(); 00090 00091 /** 00092 * Returns name of this type 00093 */ 00094 const char* getTypeName() const; 00095 00096 /** 00097 * Copy the contents of a parameters object 00098 * @param other the parameters object to be copied 00099 * @return a reference to this parameters object 00100 */ 00101 parameters& copy(const parameters& other); 00102 00103 /** 00104 * Copy the contents of a parameters object 00105 * @param other the parameters object to be copied 00106 * @return a reference to this parameters object 00107 */ 00108 parameters& operator=(const parameters& other); 00109 00110 00111 /** 00112 * Returns a pointer to a clone of the parameters 00113 */ 00114 virtual functor::parameters* clone() const; 00115 00116 /** 00117 * Write the parameters in the given ioHandler 00118 * @param handler the ioHandler to be used 00119 * @param complete if true (the default) the enclosing begin/end will 00120 * be also written, otherwise only the data block will be written. 00121 * @return true if write was successful 00122 */ 00123 virtual bool write(ioHandler& handler,const bool complete=true) const; 00124 00125 /** 00126 * Read the parameters from the given ioHandler 00127 * @param handler the ioHandler to be used 00128 * @param complete if true (the default) the enclosing begin/end will 00129 * be also written, otherwise only the data block will be written. 00130 * @return true if write was successful 00131 */ 00132 virtual bool read(ioHandler& handler,const bool complete=true); 00133 00134 # ifdef _LTI_MSC_6 00135 /** 00136 * This function is required by MSVC only, as a workaround for a 00137 * very awful bug, which exists since MSVC V.4.0, and still by 00138 * V.6.0 with all bugfixes (so called "service packs") remains 00139 * there... This method is also public due to another bug, so please 00140 * NEVER EVER call this method directly: use read() instead 00141 */ 00142 bool readMS(ioHandler& handler,const bool complete=true); 00143 00144 /** 00145 * This function is required by MSVC only, as a workaround for a 00146 * very awful bug, which exists since MSVC V.4.0, and still by 00147 * V.6.0 with all bugfixes (so called "service packs") remains 00148 * there... This method is also public due to another bug, so please 00149 * NEVER EVER call this method directly: use write() instead 00150 */ 00151 bool writeMS(ioHandler& handler,const bool complete=true) const; 00152 # endif 00153 00154 // ------------------------------------------------ 00155 // the parameters 00156 // ------------------------------------------------ 00157 00158 }; 00159 00160 /** 00161 * Default constructor 00162 */ 00163 homography8DofEstimator(); 00164 00165 /** 00166 * Construct a functor using the given parameters 00167 */ 00168 homography8DofEstimator(const parameters& par); 00169 00170 /** 00171 * Copy constructor 00172 * @param other the object to be copied 00173 */ 00174 homography8DofEstimator(const homography8DofEstimator& other); 00175 00176 /** 00177 * Destructor 00178 */ 00179 virtual ~homography8DofEstimator(); 00180 00181 /** 00182 * Returns the name of this type ("homography8DofEstimator") 00183 */ 00184 virtual const char* getTypeName() const; 00185 00186 /** 00187 * Estimates a transform from the supplied point sets, where all 00188 * points are considered. Please implement efficient code using 00189 * iterators here. Not all robust estimators use a random sampling 00190 * approach. Some estimators consider all input points and weight them 00191 * according to their deviation from the transform computed at the prior 00192 * iteration. 00193 * 00194 * All points of one point set give a matrix row, whereas all elements 00195 * of a specifec correspondence stand in a matrix column. 00196 * 00197 * @param src matrix<ipoint> with the point sets. All points of the same 00198 * image stand in a row. The correspondences in another image stand in 00199 * the according columns. 00200 * @param dest fvector the estimated transform. 00201 * @return true if apply successful or false otherwise. 00202 */ 00203 virtual bool apply(const matrix<ipoint>& src, 00204 fvector& dest) const; 00205 00206 /** 00207 * Estimates a transform from the supplied point sets, where all 00208 * points are considered. Usually this method calls the apply without 00209 * the residual first, and then computes the residual. 00210 * 00211 * All points of one point set give a matrix row, whereas all elements 00212 * of a specifec correspondence stand in a matrix column. 00213 * 00214 * @param src matrix<ipoint> with the point sets. All points of the same 00215 * image stand in a row. The correspondences in another image stand in 00216 * the according columns. 00217 * @param dest fvector the estimated transform. 00218 * @param error fvector containing the deviation of each point from the 00219 * estimated transform. Usually this is the residual or 00220 * elementwise squared residual. 00221 * @return true if apply successful or false otherwise. 00222 */ 00223 virtual bool apply(const matrix<ipoint>& src, 00224 fvector& dest, fvector& error) const; 00225 00226 /** 00227 * Estimates a transform from the supplied point sets, whereby only 00228 * the points specified in the index vector are considered. This method 00229 * is used by robost estimators using a monte carlo approach. 00230 * 00231 * All points of one point set give a matrix row, whereas all elements 00232 * of a specifec correspondence stand in a matrix column. 00233 * 00234 * @param src matrix<ipoint> with the point sets. All points of the same 00235 * image stand in a row. The correspondences in another image stand in 00236 * the according columns. 00237 * @param dest fvector the estimated transform. 00238 * @param indices ivector with the indices of the relevant points. 00239 * @param numCorrespondences the first numCorrespondences indices are 00240 * considered. 00241 * @return true if apply successful or false otherwise. 00242 */ 00243 virtual bool apply(const matrix<ipoint>& src, 00244 fvector& dest, 00245 const ivector& indices, 00246 int numCorrespondences) const; 00247 00248 /** 00249 * Estimates a transform from the supplied point sets, whereby only 00250 * the points specified in the index vector are considered. Usually this 00251 * method calls the apply without the residual first, and then computes 00252 * the residual. 00253 * 00254 * All points of one point set give a matrix row, whereas all elements 00255 * of a specifec correspondence stand in a matrix column. 00256 * 00257 * @param src matrix<ipoint> with the point sets. All points of the same 00258 * image stand in a row. The correspondences in another image stand in 00259 * the according columns. 00260 * @param dest fvector the estimated transform. 00261 * @param error fvector containing the deviation of each point from the 00262 * estimated transform. Usually this is the residual or 00263 * elementwise squared residual. 00264 * @param indices ivector with the indices of the relevant points. 00265 * @param numCorrespondences the first numCorrespondences indices are 00266 * considered. 00267 * @return true if apply successful or false otherwise. 00268 */ 00269 virtual bool apply(const matrix<ipoint>& src, 00270 fvector& dest, fvector& error, 00271 const ivector& indices, 00272 int numCorrespondences) const; 00273 00274 /** 00275 * Estimates a transform from the supplied point sets, where all 00276 * points are considered. Please implement efficient code using 00277 * iterators here. Not all robust estimators use a random sampling 00278 * approach. Some estimators consider all input points and weight them 00279 * according to their deviation from the transform computed at the prior 00280 * iteration. 00281 * 00282 * All points of one point set give a matrix row, whereas all elements 00283 * of a specifec correspondence stand in a matrix column. 00284 * 00285 * @param src matrix<fpoint> with the point sets. All points of the same 00286 * image stand in a row. The correspondences in another image stand in 00287 * the according columns. 00288 * @param dest fvector the estimated transform. 00289 * @return true if apply successful or false otherwise. 00290 */ 00291 virtual bool apply(const matrix<fpoint>& src, 00292 fvector& dest) const; 00293 00294 /** 00295 * Estimates a transform from the supplied point sets, where all 00296 * points are considered. Usually this method calls the apply without 00297 * the residual first, and then computes the residual. 00298 * 00299 * All points of one point set give a matrix row, whereas all elements 00300 * of a specifec correspondence stand in a matrix column. 00301 * 00302 * @param src matrix<fpoint> with the point sets. All points of the same 00303 * image stand in a row. The correspondences in another image stand in 00304 * the according columns. 00305 * @param dest fvector the estimated transform. 00306 * @param error fvector containing the deviation of each point from the 00307 * estimated transform. Usually this is the residual or 00308 * elementwise squared residual. 00309 * @return true if apply successful or false otherwise. 00310 */ 00311 virtual bool apply(const matrix<fpoint>& src, 00312 fvector& dest, fvector& error) const; 00313 00314 /** 00315 * Estimates a transform from the supplied point sets, whereby only 00316 * the points specified in the index vector are considered. This method 00317 * is used by robost estimators using a monte carlo approach. 00318 * 00319 * All points of one point set give a matrix row, whereas all elements 00320 * of a specifec correspondence stand in a matrix column. 00321 * 00322 * @param src matrix<fpoint> with the point sets. All points of the same 00323 * image stand in a row. The correspondences in another image stand in 00324 * the according columns. 00325 * @param dest fvector the estimated transform. 00326 * @param indices ivector with the indices of the relevant points. 00327 * @param numCorrespondences the first numCorrespondences indices are 00328 * considered. 00329 * @return true if apply successful or false otherwise. 00330 */ 00331 virtual bool apply(const matrix<fpoint>& src, 00332 fvector& dest, 00333 const ivector& indices, 00334 int numCorrespondences) const; 00335 00336 /** 00337 * Estimates a transform from the supplied point sets, whereby only 00338 * the points specified in the index vector are considered. Usually this 00339 * method calls the apply without the residual first, and then computes 00340 * the residual. 00341 * 00342 * All points of one point set give a matrix row, whereas all elements 00343 * of a specifec correspondence stand in a matrix column. 00344 * 00345 * @param src matrix<fpoint> with the point sets. All points of the same 00346 * image stand in a row. The correspondences in another image stand in 00347 * the according columns. 00348 * @param dest fvector the estimated transform. 00349 * @param error fvector containing the deviation of each point from the 00350 * estimated transform. Usually this is the residual or 00351 * elementwise squared residual. 00352 * @param indices ivector with the indices of the relevant points. 00353 * @param numCorrespondences the first numCorrespondences indices are 00354 * considered. 00355 * @return true if apply successful or false otherwise. 00356 */ 00357 virtual bool apply(const matrix<fpoint>& src, 00358 fvector& dest, fvector& error, 00359 const ivector& indices, 00360 int numCorrespondences) const; 00361 00362 /** 00363 * Estimates a transform from the supplied point sets, where all 00364 * points are considered. Please implement efficient code using 00365 * iterators here. Not all robust estimators use a random sampling 00366 * approach. Some estimators consider all input points and weight them 00367 * according to their deviation from the transform computed at the prior 00368 * iteration. 00369 * 00370 * All points of one point set give a matrix row, whereas all elements 00371 * of a specifec correspondence stand in a matrix column. 00372 * 00373 * @param src matrix<dpoint> with the point sets. All points of the same 00374 * image stand in a row. The correspondences in another image stand in 00375 * the according columns. 00376 * @param dest dvector the estimated transform. 00377 * @return true if apply successful or false otherwise. 00378 */ 00379 virtual bool apply(const matrix<dpoint>& src, 00380 dvector& dest) const; 00381 00382 /** 00383 * Estimates a transform from the supplied point sets, where all 00384 * points are considered. Usually this method calls the apply without 00385 * the residual first, and then computes the residual. 00386 * 00387 * All points of one point set give a matrix row, whereas all elements 00388 * of a specifec correspondence stand in a matrix column. 00389 * 00390 * @param src matrix<dpoint> with the point sets. All points of the same 00391 * image stand in a row. The correspondences in another image stand in 00392 * the according columns. 00393 * @param dest dvector the estimated transform. 00394 * @param error dvector containing the deviation of each point from the 00395 * estimated transform. Usually this is the residual or 00396 * elementwise squared residual. 00397 * @return true if apply successful or false otherwise. 00398 */ 00399 virtual bool apply(const matrix<dpoint>& src, 00400 dvector& dest, dvector& error) const; 00401 00402 /** 00403 * Estimates a transform from the supplied point sets, whereby only 00404 * the points specified in the index vector are considered. This method 00405 * is used by robost estimators using a monte carlo approach. 00406 * 00407 * All points of one point set give a matrix row, whereas all elements 00408 * of a specifec correspondence stand in a matrix column. 00409 * 00410 * @param src matrix<dpoint> with the point sets. All points of the same 00411 * image stand in a row. The correspondences in another image stand in 00412 * the according columns. 00413 * @param dest dvector the estimated transform. 00414 * @param indices ivector with the indices of the relevant points. 00415 * @param numCorrespondences the first numCorrespondences indices are 00416 * considered. 00417 * @return true if apply successful or false otherwise. 00418 */ 00419 virtual bool apply(const matrix<dpoint>& src, 00420 dvector& dest, 00421 const ivector& indices, 00422 int numCorrespondences) const; 00423 00424 /** 00425 * Estimates a transform from the supplied point sets, whereby only 00426 * the points specified in the index vector are considered. Usually this 00427 * method calls the apply without the residual first, and then computes 00428 * the residual. 00429 * 00430 * All points of one point set give a matrix row, whereas all elements 00431 * of a specifec correspondence stand in a matrix column. 00432 * 00433 * @param src matrix<dpoint> with the point sets. All points of the same 00434 * image stand in a row. The correspondences in another image stand in 00435 * the according columns. 00436 * @param dest dvector the estimated transform. 00437 * @param error dvector containing the deviation of each point from the 00438 * estimated transform. Usually this is the residual or 00439 * elementwise squared residual. 00440 * @param indices ivector with the indices of the relevant points. 00441 * @param numCorrespondences the first numCorrespondences indices are 00442 * considered. 00443 * @return true if apply successful or false otherwise. 00444 */ 00445 virtual bool apply(const matrix<dpoint>& src, 00446 dvector& dest, dvector& error, 00447 const ivector& indices, 00448 int numCorrespondences) const; 00449 00450 /** 00451 * Compute the residual for the given correspondences and transformation 00452 * vector. 00453 * @param src matrix<fpoint> with the point sets. All points of the same 00454 * image stand in a row. The correspondences in another image stand in 00455 * the according columns. 00456 * @param transform fvector with the transformation 00457 * @param dest fvector with the residual 00458 * @return true on success and false otherwise. 00459 */ 00460 virtual bool computeResidual(const matrix<fpoint >& src, 00461 const fvector& transform, 00462 fvector& dest) const; 00463 00464 /** 00465 * Compute the residual for the given correspondences and transformation 00466 * vector. 00467 * @param src matrix<dpoint> with the point sets. All points of the same 00468 * image stand in a row. The correspondences in another image stand in 00469 * the according columns. 00470 * @param transform dvector with the transformation 00471 * @param dest dvector with the residual 00472 * @return true on success and false otherwise. 00473 */ 00474 virtual bool computeResidual(const matrix<dpoint >& src, 00475 const dvector& transform, 00476 dvector& dest) const; 00477 00478 /** 00479 * Returns the minimum number of correspondences required to estimate 00480 * the transform. 00481 */ 00482 virtual int minNumberCorrespondences() const; 00483 00484 /** 00485 * Returns the mininum dimension of a correspondence, 00486 * e.g. the minimum dimension of a correspondence pair is 2. 00487 * Each derived transform estimator only works on correspondences of 00488 * priori defined dimensions. 00489 */ 00490 virtual int minCorrespondenceDimension() const; 00491 00492 /** 00493 * Returns the maximum dimension of a correspondence, 00494 * e.g. the maximum dimension of a correspondence pair is 2, whereas 00495 * transformEstimator running on n-tuples may allow an infinite number. 00496 * Each derived transform estimator only works on correspondences of 00497 * priori defined dimensions. 00498 */ 00499 virtual int maxCorrespondenceDimension() const; 00500 00501 /** 00502 * A transform estimated on normalized data usually differs from 00503 * the transform of the original data. Considering the normalization 00504 * performed this methods computes the transform which applies to the 00505 * original data. 00506 * @param srcdest the normalized transform. The result will be left here 00507 * too. 00508 * @param scale a vector containing the scale applied to each point set. 00509 * @param shift a vector containing the shift of each scaled point set. 00510 */ 00511 bool denormalize(fvector& srcdest, 00512 const vector<fpoint>& scale, 00513 const vector<fpoint>& shift) const; 00514 00515 /** 00516 * A transform estimated on normalized data usually differs from 00517 * the transform of the original data. Considering the normalization 00518 * performed this methods computes the transform which applies to the 00519 * original data. 00520 * @param srcdest the normalized transform. The result will be left here 00521 * too. 00522 * @param scale a vector containing the scale applied to each point set. 00523 * @param shift a vector containing the shift of each scaled point set. 00524 */ 00525 bool denormalize(dvector& srcdest, 00526 const vector<dpoint>& scale, 00527 const vector<dpoint>& shift) const; 00528 00529 /** 00530 * Converts the estimated vector into a hMatrix3D<float>, which is e.g. 00531 * used by geometricTransform. 00532 * @param src fvector the estimated transform. 00533 * @param dest hMatrix3D<float> the estimated transform as a hMatrix3D. 00534 * 00535 * @return true if successful or false otherwise. 00536 */ 00537 bool convert(const fvector& src, hMatrix3D<float>& dest) const; 00538 00539 /** 00540 * Converts the estimated vector into a hMatrix3D<float>, which is e.g. 00541 * used by geometricTransform. 00542 * @param src dvector the estimated transform. 00543 * @param dest hMatrix3D<float> the estimated transform as a hMatrix3D. 00544 * 00545 * @return true if successful or false otherwise. 00546 */ 00547 bool convert(const dvector& src, hMatrix3D<float>& dest) const; 00548 00549 /** 00550 * Converts the estimated vector into a 3x3 matrix. 00551 * 00552 * @param src fvector the estimated transform. 00553 * @param dest fmatrix the estimated transform as a matrix. 00554 * 00555 * @return true if successful or false otherwise. 00556 */ 00557 bool convert(const fvector& src, fmatrix& dest) const; 00558 00559 /** 00560 * Converts the estimated vector into a 3x3 matrix. 00561 * 00562 * @param src dvector the estimated transform. 00563 * @param dest dmatrix the estimated transform as a matrix. 00564 * 00565 * @return true if successful or false otherwise. 00566 */ 00567 bool convert(const dvector& src, dmatrix& dest) const; 00568 00569 /** 00570 * This is a fast short cut used by the special robust estimator 00571 * homographyVerification in the main loop. 00572 * @param pt fpoint the point to be transformed 00573 * @param transf fvector with the transformation, which e.g. was computed 00574 * by an apply. 00575 * @return the transformed point 00576 */ 00577 fpoint transform(const fpoint& pt, 00578 const fvector& transf) const; 00579 00580 /** 00581 * This is a fast short cut used in the special robust estimator 00582 * homographyVerification in the main loop. 00583 * @param pt fpoint the point to be transformed 00584 * @param transf fvector with the transformation, which e.g. was computed 00585 * by an apply. 00586 * @return the transformed point 00587 */ 00588 dpoint transform(const dpoint& pt, 00589 const dvector& transf) const; 00590 00591 00592 /** 00593 * Copy data of "other" functor. 00594 * @param other the functor to be copied 00595 * @return a reference to this functor object 00596 */ 00597 homography8DofEstimator& copy(const homography8DofEstimator& other); 00598 00599 /** 00600 * Alias for copy member 00601 * @param other the functor to be copied 00602 * @return a reference to this functor object 00603 */ 00604 homography8DofEstimator& operator=(const homography8DofEstimator& other); 00605 00606 /** 00607 * Returns a pointer to a clone of this functor. 00608 */ 00609 virtual functor* clone() const; 00610 00611 /** 00612 * Returns used parameters 00613 */ 00614 const parameters& getParameters() const; 00615 00616 }; 00617 00618 // ------------------------------------------------------------------- 00619 // The transform-methods! no t-helper due to efficiency here 00620 // ------------------------------------------------------------------- 00621 00622 inline fpoint homography8DofEstimator 00623 ::transform(const fpoint& pt, const fvector& transf) const { 00624 00625 fpoint res; 00626 // fvector::const_iterator it ( transf.begin() ); 00627 // res.x = *it * pt.x + *(++it) * pt.y + *(++it); 00628 // res.y = *(++it) * pt.x + *(++it) * pt.y + *(++it); 00629 res.x = transf.at(0) * pt.x + transf.at(1) * pt.y + transf.at(2); 00630 res.y = transf.at(3) * pt.x + transf.at(4) * pt.y + transf.at(5); 00631 00632 // const float denom ( *(++it) * pt.x + *(++it) * pt.y + 1 ); 00633 const float denom ( transf.at(6) * pt.x + transf.at(7) * pt.y + 1 ); 00634 res.x /= denom; 00635 res.y /= denom; 00636 00637 return res; 00638 } 00639 00640 inline dpoint homography8DofEstimator 00641 ::transform(const dpoint& pt, const dvector& transf) const { 00642 00643 dpoint res; 00644 // dvector::const_iterator it ( transf.begin() ); 00645 // res.x = *it * pt.x + *(++it) * pt.y + *(++it); 00646 // res.y = *(++it) * pt.x + *(++it) * pt.y + *(++it); 00647 res.x = transf.at(0) * pt.x + transf.at(1) * pt.y + transf.at(2); 00648 res.y = transf.at(3) * pt.x + transf.at(4) * pt.y + transf.at(5); 00649 00650 // const double denom ( *(++it) * pt.x + *(++it) * pt.y + 1 ); 00651 const double denom ( transf.at(6) * pt.x + transf.at(7) * pt.y + 1 ); 00652 res.x /= denom; 00653 res.y /= denom; 00654 00655 return res; 00656 } 00657 00658 } 00659 00660 #endif