last update 20 Sep 2009 |
00001 /* 00002 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 00003 * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany 00004 * Copyright (C) 2008 00005 * Pablo Alvarado 00006 * 00007 * This file is part of the Computer Vision and Robotics Library (CVR-Lib ) 00008 * 00009 * The CVR-Lib is free software; you can redistribute it and/or 00010 * modify it under the terms of the BSD License. 00011 * 00012 * All rights reserved. 00013 * 00014 * Redistribution and use in source and binary forms, with or without 00015 * modification, are permitted provided that the following conditions are met: 00016 * 00017 * 1. Redistributions of source code must retain the above copyright notice, 00018 * this list of conditions and the following disclaimer. 00019 * 00020 * 2. Redistributions in binary form must reproduce the above copyright notice, 00021 * this list of conditions and the following disclaimer in the documentation 00022 * and/or other materials provided with the distribution. 00023 * 00024 * 3. Neither the name of the authors nor the names of its contributors may be 00025 * used to endorse or promote products derived from this software without 00026 * specific prior written permission. 00027 * 00028 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00029 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00030 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00031 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00032 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00033 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00034 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00035 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00036 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00037 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00038 * POSSIBILITY OF SUCH DAMAGE. 00039 */ 00040 00041 /** 00042 * \file cvrPCA.h 00043 * Principal Components Analysis 00044 * \author Jochen Wickel 00045 * \author Pablo Alvarado 00046 * \date 27.11.2000 00047 * 00048 * revisions ..: $Id: cvrPCA.h,v 1.1 2008/05/08 15:00:29 alvarado Exp $ 00049 */ 00050 00051 #ifndef _CVR_P_C_A_H_ 00052 #define _CVR_P_C_A_H_ 00053 00054 #include "cvrLinearAlgebraFunctor.h" 00055 #include "cvrMatrix.h" 00056 00057 namespace cvr { 00058 /** 00059 * Principal Components Analysis (PCA). 00060 * 00061 * Functor for computing the principal components of a data set. 00062 * 00063 * It receives a set of input vectors in form of a matrix (each row of 00064 * the matrix corresponds to an input vector), which will be transformed 00065 * with PCA. 00066 * 00067 * The first time you use the apply()-method, the transformation 00068 * matrix will be computed. You can use this transformation matrix 00069 * with other data sets using the transform() methods. 00070 * 00071 * Please note that the eigenvector matrices will contain the 00072 * eigenvector in the COLUMNS and not in the rows, as could be 00073 * expected. This avoids the requirement of transposing matrices in 00074 * the vector transformations. 00075 * 00076 * For large data matrices is is advisable to use singular value 00077 * decomposition instead of an eigensystem for the PCA. The 00078 * operation will usually be faster and using less memory. To do so 00079 * set parameters::useSVD to true. 00080 * 00081 * @ingroup gLinearAlgebra 00082 */ 00083 template <typename T> 00084 class pca : public linearAlgebraFunctor { 00085 public: 00086 /** 00087 * The parameters for the class pca 00088 */ 00089 class parameters : public linearAlgebraFunctor::parameters { 00090 public: 00091 /** 00092 * Default constructor 00093 */ 00094 parameters(); 00095 00096 /** 00097 * Copy constructor 00098 * @param other the parameters object to be copied 00099 */ 00100 parameters(const parameters& other); 00101 00102 /** 00103 * Destructor 00104 */ 00105 ~parameters(); 00106 00107 /** 00108 * Return name of this class 00109 */ 00110 const std::string& name() const; 00111 00112 /** 00113 * Copy the contents of a parameters object 00114 * @param other the parameters object to be copied 00115 * @return a reference to this parameters object 00116 */ 00117 parameters& copy(const parameters& other); 00118 00119 /** 00120 * Assigns the contents of the other object to this object 00121 */ 00122 parameters& operator=(const parameters& other); 00123 00124 /** 00125 * Return a pointer to a clone of the parameters 00126 */ 00127 virtual parameters* clone() const; 00128 00129 /** 00130 * Return a pointer to a new instance of the parameters 00131 */ 00132 virtual parameters* newInstance() const; 00133 00134 /** 00135 * Read the parameters from the given ioHandler 00136 * 00137 * @param handler the ioHandler to be used 00138 * @param complete if true (the default) the enclosing begin/end will 00139 * be also read, otherwise only the data block will be read. 00140 * @return true if write was successful 00141 */ 00142 virtual bool read(ioHandler &handler, const bool complete=true); 00143 00144 /** 00145 * Write the parameters in the given ioHandler. 00146 * 00147 * @param handler the ioHandler to be used 00148 * @param complete if true (the default) the enclosing begin/end will 00149 * be also written, otherwise only the data block will be 00150 * written. 00151 * @return true if write was successful 00152 */ 00153 virtual bool write(ioHandler& handler,const bool complete=true) const; 00154 00155 // -------------- 00156 // The parameters 00157 // -------------- 00158 00159 /** 00160 * Final dimension of the reduced vectors. 00161 * 00162 * Default value: 3 00163 */ 00164 int resultDimension; 00165 00166 /** 00167 * This flag determines, if the functor should determine a 00168 * maximum allowable dimension itself. "Maximum dimension" means 00169 * that the dimension is equal to the number of eigenvalues of 00170 * the covariance matrix which are larger than zero. 00171 * 00172 * Default value: \c false 00173 */ 00174 bool autoDimension; 00175 00176 /** 00177 * This flag determines if the functor should use the 00178 * correlation coefficient matrix (flag is true) for eigenvector 00179 * computation or the covariance matrix (flag is false). 00180 * 00181 * Default value: \c false. 00182 */ 00183 bool useCorrelation; 00184 00185 /** 00186 * This flag determines if the functor should perform a 00187 * whitening transform of the data. Whitening means that 00188 * 1. A PCA is performed, using the covariance matrix for 00189 * eigenvector computation 00190 * 2. A scaling of the transformed data by the inverse of the 00191 * square root of the eigenvalues. 00192 * 00193 * You have to set useCorrelation to false if you use whitening. 00194 * 00195 * Default value: \c false. 00196 */ 00197 bool whitening; 00198 00199 /** 00200 * The factor which determines relevant eigenvectors. An eigenvector 00201 * is considered relevant if its eigenvalue is at least as large 00202 * as the largest eigenvalue divided by this number. Usually, 00203 * it takes values between 1e4 and 1e6. 00204 * 00205 * Default value: T(100000) 00206 */ 00207 T relevance; 00208 00209 /** 00210 * This flag denotes if the transformed data should be 00211 * centered around zero. This is the usual behaviour of 00212 * the PCA, but for some special operations it may be 00213 * necessary to disable this. If the flag is false, 00214 * the mean of the transformed data is moved to the transformed 00215 * mean of the source data. 00216 * 00217 * Default value: true 00218 */ 00219 bool centerData; 00220 00221 /** 00222 * When \c true, singular value decomposition instead of eigensystem 00223 * solution is used to calculate the eigenvectors and 00224 * eigenvalues. This can be much faster and less memory consuming. 00225 * 00226 * Default value: \c false. 00227 */ 00228 bool useSVD; 00229 }; 00230 00231 protected: 00232 00233 /** 00234 * Default constructor. 00235 * 00236 * @param createDefaultParams if true (default) a default parameters 00237 * object will be created. 00238 */ 00239 pca(const bool createDefaultParams); 00240 00241 public: 00242 /** 00243 * Default constructor. 00244 */ 00245 pca(); 00246 00247 /** 00248 * Default constructor with parameters 00249 * 00250 */ 00251 pca(const parameters& par); 00252 00253 /** 00254 * Copy constructor. 00255 * 00256 * @param other the object to be copied 00257 */ 00258 pca(const pca& other); 00259 00260 /** 00261 * Destructor 00262 */ 00263 virtual ~pca(); 00264 00265 /** 00266 * Returns the name of this type ("pca") 00267 */ 00268 virtual const std::string& name() const; 00269 00270 /** 00271 * Computes the principal components of the data matrix 00272 * and transforms it according to the new coordinate system. 00273 * The result is the transformed matrix. 00274 * Data and result must not be references to the same matrix. 00275 * Data points are expected to be in the rows of the data matrix. 00276 * 00277 * If you don't need to transform the input data, and just want to 00278 * use the input matrix to compute the principal components you 00279 * can use the method computeTransformMatrix(). If you just need 00280 * to transform the data, without computing the transformation matrix, you 00281 * can use the method transform(). 00282 * 00283 * @param data matrix<T> with the source data. 00284 * @param result matrix<T> with the result data. 00285 * @return true if the PCA could be computed, false otherwise 00286 */ 00287 virtual bool apply(const matrix<T>& data, matrix<T>& result); 00288 00289 /** 00290 * On-Place version of the transformation. 00291 * 00292 * If you don't need to transform the input data, and just want to 00293 * use the input matrix to compute the principal components you 00294 * can use the method computeTransformMatrix(). If you just need 00295 * to transform the data, without computing the transformation matrix, you 00296 * can use the method transform(). 00297 * 00298 * @param srcdest matrix<T> with the source data, which will also contain 00299 * the result. 00300 * @return a reference to <code>srcdest</code>. 00301 */ 00302 virtual bool apply(matrix<T>& srcdest); 00303 00304 /** 00305 * Transforms a single vector according to a previously computed 00306 * transformation matrix. (this is an alias for the transform() method) 00307 */ 00308 virtual inline bool apply(const vector<T> &src, vector<T>& result) { 00309 return transform(src,result); 00310 } 00311 00312 /** 00313 * Pass the covariance matrix and the mean values directly 00314 * to the functor to generate the transform matrix. 00315 * 00316 * If you know the mean and covariance of your data, you can use this 00317 * method to speed up the computations of the transformation matrix. 00318 * Otherwise, just call one of the apply() methods with your data vectors 00319 * in the rows of the matrix. The covariance and mean vectors will be 00320 * computed there automatically. 00321 */ 00322 bool setCovarianceAndMean(const matrix<T>& coVar, 00323 const vector<T>& meanVec); 00324 00325 /** 00326 * Transforms a single vector according to a previously computed 00327 * transformation matrix. 00328 * 00329 * @param src the data vector 00330 * @param result the vector which will receive the transformed data 00331 * @return a reference to <code>result</code> 00332 */ 00333 virtual bool transform(const vector<T> &src, vector<T>& result) const; 00334 00335 /** 00336 * Transform an entire matrix according to a previously computed 00337 * transformation matrix. Unfortunately, we must choose a name 00338 * different from apply. 00339 * 00340 * @param src the data matrix 00341 * @param result the matrix which will receive the transformed data 00342 * @return true if successful, false otherwise. 00343 */ 00344 virtual bool transform(const matrix<T> &src, matrix<T>& result) const; 00345 00346 /** 00347 * Transform an entire matrix according to a previously computed 00348 * transformation matrix. Unfortunately, we must choose a name 00349 * different from apply. 00350 * @param srcdest the data matrix. The result will be left here too. 00351 * @return true if successful, false otherwise. 00352 */ 00353 virtual bool transform(matrix<T> &srcdest) const; 00354 00355 /** 00356 * Compute the transformation matrix. Similar to the apply() method, 00357 * but it does not transform the given data (this saves some time). 00358 * 00359 * @param src the matrix with the input data to be analysed. 00360 * @return true if transformation matrix could be computed, false otherwise 00361 */ 00362 virtual bool computeTransformMatrix(const matrix<T>& src); 00363 00364 /** 00365 * Alias for computeTransformMatrix() 00366 */ 00367 virtual bool train(const matrix<T>& src); 00368 00369 /** 00370 * Reconstructs a data vector \c dest from the given coefficients 00371 * \c coeff, using the transformMatrix found by 00372 * computeTransformMatrix() or apply() and the appropriate offset. 00373 * 00374 * @param coeff PCA coefficients for reconstruction. 00375 * @param dest reconstructed data vector. 00376 * @return true if reconstruction was successful 00377 */ 00378 virtual bool reconstruct(const vector<T>& coeff, vector<T>& dest) const; 00379 00380 /** 00381 * Reconstructs a set of data vectors \c dest from the given 00382 * coefficients \c coeff, using the transformMatrix found by 00383 * computeTransformMatrix() or apply() and the appropriate 00384 * offset. As usual \c coeff as well as \c dest contain one data 00385 * vector per row. 00386 * 00387 * @param coeff each row contains PCA coefficients for reconstruction. 00388 * @param dest each row is one reconstructed data vector. 00389 * @return true if reconstruction was successful 00390 */ 00391 virtual bool reconstruct(const matrix<T>& coeff, matrix<T>& dest) const; 00392 00393 /** 00394 * Returns the previously computed transform matrix. 00395 * 00396 * @param result the matrix which will receive the transformation 00397 * matrix. 00398 * @return true if the matrix could be computed, false otherwise. 00399 */ 00400 virtual bool getTransformMatrix(matrix<T>& result) const; 00401 00402 /** 00403 * Returns the previously computed transform matrix. 00404 * 00405 * @return a const reference to the last computed or used transformation 00406 * matrix. 00407 */ 00408 virtual const matrix<T>& getTransformMatrix() const; 00409 00410 /** 00411 * Returns the previously computed offset vector, which corresponds to the 00412 * mean of the data. 00413 * 00414 * @param result the offset vector will be written here. 00415 * @return true if the matrix could be computed, false otherwise. 00416 */ 00417 virtual bool getOffsetVector(vector<T>& result) const; 00418 00419 /** 00420 * Returns the previously computed offset vector, which corresponds to the 00421 * mean of the data. 00422 * 00423 * @return a const reference to the last computed or used offset vector. 00424 */ 00425 virtual const vector<T>& getOffsetVector() const; 00426 00427 /** 00428 * Returns the previously computed eigenvalues of the covariance 00429 * matrix. 00430 * 00431 * @param result the vector which will receive the eigenvalues. 00432 * @return true if the values could be obtained, false otherwise. 00433 */ 00434 virtual bool getEigenValues(vector<T>& result) const; 00435 00436 /** 00437 * Returns the previously computed eigenvalues of the covariance 00438 * matrix. 00439 * 00440 * @return a const reference to the last computed eigenvalues 00441 */ 00442 virtual const vector<T>& getEigenValues() const; 00443 00444 /** 00445 * Returns the previously computed eigenvectors of the covariance 00446 * matrix. 00447 * 00448 * @param result the matrix which will receive the eigenvectors. 00449 * Each column of the matrix contains one eigenvector. 00450 * @return true if the vectors could be obtained, false otherwise 00451 */ 00452 virtual bool getEigenVectors(matrix<T>& result) const; 00453 00454 /** 00455 * Returns the previously computed eigenvectors of the covariance 00456 * matrix. 00457 * 00458 * This method will call the normal getEigenVectors() methods and 00459 * after that will transpose the obtained matrix, i.e. it is faster 00460 * to get the eigenvectors in the columns. 00461 * 00462 * @param result the matrix which will receive the eigenvectors. 00463 * Each row of the matrix contains one eigenvector. 00464 * @return true if the vectors could be obtained, false otherwise 00465 */ 00466 virtual bool getEigenVectorsInRows(matrix<T>& result) const; 00467 00468 /** 00469 * Returns the previously computed eigenvectors of the covariance 00470 * matrix. 00471 * 00472 * @return a const reference to the last computed eigenvectors 00473 */ 00474 virtual const matrix<T>& getEigenVectors() const; 00475 00476 /** 00477 * Set the dimension to which the vectors should be reduced. This 00478 * is just considered when computing the transformation 00479 * matrix. After this matrix is determined the (destination) 00480 * dimension is fixed and just can be changed by recalculating the 00481 * transformation matrix. 00482 */ 00483 virtual void setDimension(int k); 00484 00485 /** 00486 * Copy data of "other" functor. 00487 * 00488 * @param other the functor to be copied 00489 * @return a reference to this functor object 00490 */ 00491 pca& copy(const pca& other); 00492 00493 /** 00494 * Alias for copy. 00495 */ 00496 pca& operator=(const pca& other); 00497 00498 /** 00499 * Return a pointer to a clone of this functor. 00500 */ 00501 virtual functor* clone() const; 00502 00503 /** 00504 * Return a pointer to a new instance of this functor. 00505 */ 00506 virtual functor* newInstance() const; 00507 00508 /** 00509 * Return used parameters 00510 */ 00511 const parameters& getParameters() const; 00512 00513 /** 00514 * Update functor's parameters. 00515 * 00516 * This member initializes some internal data according to the values in 00517 * the parameters. 00518 * 00519 * @return true if successful, false otherwise 00520 */ 00521 virtual bool updateParameters(); 00522 00523 /** 00524 * Read this functor from the given handler. 00525 */ 00526 virtual bool read(ioHandler &handler, const bool complete=true); 00527 00528 /** 00529 * Write this functor to the given handler. 00530 */ 00531 virtual bool write(ioHandler &handler, const bool complete=true) const; 00532 00533 /** 00534 * Number of dimensions considered in the transformation 00535 * @return the number of dimensions used for the transformation. It 00536 * is always less or equal the number of dimensions of the input 00537 * vectors. 00538 */ 00539 int getUsedDimension() const { 00540 return usedDimensionality_; 00541 } 00542 00543 protected: 00544 /** 00545 * Determines the intrinsic dimensionality of the data set if the 00546 * user specify autoDim, otherwise return parameters::resultDim. 00547 * The member usedDimensionality will be set with the returned value 00548 */ 00549 int checkDim(); 00550 00551 /** 00552 * Resets all private members to size 0. Used when an error occurs 00553 * in the calculation of the transform matrix. 00554 */ 00555 void reset(); 00556 00557 protected: 00558 /** 00559 * Ordered eigen vectors 00560 */ 00561 matrix<T> orderedEigVec_; 00562 00563 /** 00564 * Transformation matrix 00565 */ 00566 matrix<T> transformMatrix_; 00567 00568 /** 00569 * Eigenvalues 00570 */ 00571 vector<T> eigValues_; 00572 00573 /** 00574 * Offset 00575 */ 00576 vector<T> offset_; 00577 00578 /** 00579 * Transformed offset 00580 */ 00581 vector<T> transformedOffset_; 00582 00583 /** 00584 * Scale 00585 */ 00586 vector<T> scale_; 00587 00588 /** 00589 * Whitening scale 00590 */ 00591 vector<T> whiteScale_; 00592 00593 /** 00594 * Dimensionality being used. 00595 */ 00596 int usedDimensionality_; 00597 }; 00598 00599 00600 } 00601 00602 #endif