Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
PCA.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen *
5 * www.openflipper.org *
6 * *
7 *--------------------------------------------------------------------------- *
8 * This file is part of OpenFlipper. *
9 * *
10 * OpenFlipper is free software: you can redistribute it and/or modify *
11 * it under the terms of the GNU Lesser General Public License as *
12 * published by the Free Software Foundation, either version 3 of *
13 * the License, or (at your option) any later version with the *
14 * following exceptions: *
15 * *
16 * If other files instantiate templates or use macros *
17 * or inline functions from this file, or you compile this file and *
18 * link it with other files to produce an executable, this file does *
19 * not by itself cause the resulting executable to be covered by the *
20 * GNU Lesser General Public License. This exception does not however *
21 * invalidate any other reasons why the executable file might be *
22 * covered by the GNU Lesser General Public License. *
23 * *
24 * OpenFlipper is distributed in the hope that it will be useful, *
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
27 * GNU Lesser General Public License for more details. *
28 * *
29 * You should have received a copy of the GNU LesserGeneral Public *
30 * License along with OpenFlipper. If not, *
31 * see <http://www.gnu.org/licenses/>. *
32 * *
33 \*===========================================================================*/
34 
35 /*===========================================================================*\
36 * *
37 * $Revision: 10745 $ *
38 * $LastChangedBy: moebius $ *
39 * $Date: 2011-01-26 10:23:50 +0100 (Mi, 26 Jan 2011) $ *
40 * *
41 \*===========================================================================*/
42 
43 
44 
45 
46 //=============================================================================
47 //
48 // CLASS PCA - IMPLEMENTATION
49 //
50 //=============================================================================
51 
52 #define PCA_C
53 
54 //== INCLUDES =================================================================
55 
56 #include "PCA.hh"
57 
58 extern "C" {
59 
60  typedef void (*U_fp)(...);
61 
62  int dsyev_( char *jobz, char *uplo, long int *n, double *a,
63  long int *lda, double *w, double *work, long int *lwork,
64  long int *info);
65 
66 }
67 
68 // typedef gmm::dense_matrix< double > Matrix;
69 // typedef std::vector< double > Vector;
70 
72 static double * p_work_double = 0;
73 
75 static int m_workSize_double = 0;
76 
77 //== NAMESPACES ===============================================================
78 
79 namespace Pca {
80 
81 //== IMPLEMENTATION ==========================================================
82 
83 template < typename VectorT >
84 PCA< VectorT >::PCA( std::vector< VectorT >& _points , VectorT& _first , VectorT& _second , VectorT& _third)
85 {
86  pca(_points,_first,_second,_third);
87 }
88 
89 template < typename VectorT >
91 {
92  if ( p_work_double != 0){
93  delete [] p_work_double;
94  p_work_double = 0;
95  m_workSize_double = 0;
96  }
97 }
98 
99 template < typename VectorT >
100 inline
101 VectorT
103 center_of_gravity(const std::vector< VectorT >& _points ) {
104  // compute cog of Points
105  VectorT cog(0.0, 0.0, 0.0);
106 
107  for (uint i = 0 ; i < _points.size() ; ++i ) {
108  cog = cog + _points[i];
109  }
110 
111  cog = cog / ( typename VectorT::value_type )_points.size();
112 
113  return cog;
114 }
115 
116 template < typename VectorT >
117 bool
118 PCA< VectorT >::SymRightEigenproblem( Matrix &_mat_A, Matrix & _mat_VR,
119  std::vector< double > & _vec_EV )
120 {
121  char jobz, uplo;
122  long int n, lda;
123  long int lwork, info;
124  double size;
125 
126  jobz = 'V';
127  uplo = 'U';
128  n = gmm::mat_nrows( _mat_A );
129  lda = n;
130 
131  info = 0;
132  // compute optimal size of working array
133  lwork = -1;
134  dsyev_( &jobz, &uplo, &n, &_mat_A( 0, 0 ), &lda, &_vec_EV[ 0 ],
135  &size, &lwork, &info );
136 
137  if( info != 0 )
138  return false;
139 
140 
141  if( (long int) size > m_workSize_double )
142  {
143  if( p_work_double)
144  delete [] p_work_double;
145 
146  m_workSize_double = (long int) size;
147 
148  p_work_double= new double[ m_workSize_double ];
149  }
150  lwork = m_workSize_double;
151 
152  // compute eigenvalues / eigenvectors
153  dsyev_( &jobz, &uplo, &n, &_mat_A( 0, 0 ), &lda, &_vec_EV[ 0 ],
154  p_work_double, &lwork, &info );
155 
156  if( info != 0 )
157  return false;
158 
159  // copy eigenvectors to matrix
160  gmm::copy( _mat_A, _mat_VR );
161 
162  return true;
163 }
164 
165 
166 template < typename VectorT >
167 void
168 PCA< VectorT >::pca(std::vector< VectorT >& _points , VectorT& _first , VectorT& _second , VectorT& _third)
169 {
170  // compute Mean of Points
171  const VectorT cog = center_of_gravity(_points);
172 
173  //build covariance Matrix
174  Matrix points(3 , _points.size() );
175 
176  for ( uint i = 0 ; i < _points.size() ; ++i)
177  {
178  points(0 , i ) = ( _points[i] - cog) [0];
179  points(1 , i ) = ( _points[i] - cog) [1];
180  points(2 , i ) = ( _points[i] - cog) [2];
181  }
182 
183  Matrix cov(3,3);
184  gmm::mult(points,gmm::transposed(points),cov );
185 
186  Matrix EV(3,3);
187  std::vector< double > ew(3);
188 
189 
190  if ( !SymRightEigenproblem( cov, EV ,ew ) )
191  std::cerr << "Error: Could not compute Eigenvectors for PCA" << std::endl;
192 
193  int maximum,middle,minimum;
194 
195  if ( (ew[0] > ew[1]) && (ew[0] > ew[2]) ) {
196  maximum = 0;
197  } else {
198  if ( (ew[1] > ew[0]) && (ew[1] > ew[2]) )
199  maximum = 1;
200  else
201  maximum = 2;
202  }
203 
204  if ( (ew[0] < ew[1]) && (ew[0] < ew[2]) )
205  minimum = 0;
206  else if ( (ew[1] < ew[0]) && (ew[1] < ew[2]) )
207  minimum = 1;
208  else
209  minimum = 2;
210 
211  if ( (minimum != 0 ) && ( maximum != 0 ) )
212  middle = 0;
213  else
214  if ( (minimum != 1 ) && ( maximum != 1 ) )
215  middle = 1;
216  else
217  middle = 2;
218 
219  _first = VectorT( EV(0,maximum) , EV(1,maximum) , EV(2,maximum) );
220  _second = VectorT( EV(0,middle) , EV(1,middle) , EV(2,middle ) );
221 
222  _first = _first.normalize();
223  _second = _second.normalize();
224  _third = _first % _second;
225 
226  //remember the eigenvalues
227  lastEigenValues_.clear();
228  lastEigenValues_.push_back( ew[maximum] );
229  lastEigenValues_.push_back( ew[middle] );
230  lastEigenValues_.push_back( ew[minimum] );
231 }
232 //-----------------------------------------------------------------------------
233 
234 template < typename VectorT >
235 inline
236 std::vector<double>&
238 {
239  return lastEigenValues_;
240 }
241 
242 
243 //=============================================================================
244 
245 } //namespace Pca
246 
247 //=============================================================================