title: Principal Component Analysis C++ OpenCV
body: <p>I am new to OpenCV and I am trying to implement Principal Component Analysis (Eigenspace) on  <a href="http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html" rel="nofollow noreferrer">AT&amp;T database</a>. The eigenvalues come in order of 10^6. The outcome is disappointing since images seem to be projected randomly on space of eigenvectors. Distance^2 between similar as well as dissimilar images in the order of 10^8. Following is my code:</p>
  
  <p>Some constants :</p>
  
  <pre><code>const int ROWSIZE = 112; //number of rows per image
  const int COLSIZE = 92; //number of columns per image
  int ROW = 92*112; //each image is represented as a column of size ROW*1
  int PEOPLE = 3; // number of people in training set
  int FACES = 3; // number of faces used per person
  int COL = PEOPLE*FACES; //total number of training faces
  static const double THRESHOLD = 0.9; //fraction of energy of eigenvalue to be chosen
  </code></pre>
  
  <p>Following are the steps:
  Load image to image matrix, convert to CV_64F format and convert image in the training set to a column.  </p>
  
  <pre><code>img.convertTo(img1, CV_64F);
  for (int i = 1; i &lt;= PEOPLE; i++) {
      for (int j = 1; j &lt;= FACES; j++) {
          for (int x = 0; x &lt; ROWSIZE; x++) {
              for (int y = 0; y &lt; COLSIZE; y++) {
                  images.at&lt;double&gt;(x*COLSIZE+y, (i-1)*FACES+j-1) = 
                  img1.at&lt;double&gt;(x, y);
              }
          }
      } 
  }
  </code></pre>
  
  <p>Convert testImage to single column.</p>
  
  <p>Compute the average of all columns and subtract mean using </p>
  
  <pre><code>    Mat avg(ROW, 1, CV_64F, double(0));
      for (int j = 0; j &lt; COL; j++) {
          avg += images.col(j);
      }
      avg = avg / COL;
      for (int j = 0; j &lt; COL; j++) {
          images.col(j) = images.col(j) - avg;
      }
  </code></pre>
  
  <p>Compute eigenvalues and eigenvectors for images.t()*images() since it has low dimensionality</p>
  
  <pre><code>    Mat eig_val(COL, 1, CV_64F, double(0));
      Mat eig_vec(COL, COL, CV_64F, double(0));   
      eigen((images.t()*images), eig_val, eig_vec);
  </code></pre>
  
  <p>Compute significant eigenvalues using </p>
  
  <pre><code>    double totalSum = 0;
      for (int i = 0; i &lt; COL; i++) {
          totalSum += sqrt(eig_val.at&lt;double&gt;(i, 0));
      }
      double sum = 0; int k = 0;
      for (k = 0; k &lt; COL; k++) {
          sum += sqrt(eig_val.at&lt;double&gt;(k, 0));
          if (sum &gt; THRESHOLD*totalSum)break;
      }
      int sigValue = k + 1;
  </code></pre>
  
  <p>Compute normalized eigenvectors of initial images matrix. Please note that eigenvectors are the rows of eig_vec matrix</p>
  
  <pre><code>    Mat featureVec(sigValue, ROW, CV_64F, double(0));
      for (int i = 0; i &lt; sigValue; i++) {
              featureVec.row(i) = eig_vec.row(i)*images.t();
              Mat d = featureVec.row(i)*featureVec.row(i).t();
              featureVec.row(i) = featureVec.row(i) / sqrt(d.at&lt;double&gt;(0,0));
      }   
  </code></pre>
  
  <p>Compute transformed training vectors and test vectors</p>
  
  <pre><code>    Mat transformedData = featureVec*images;
      Mat transformedTestImage = featureVec*testImage;
  </code></pre>
  
  <p>Obtain index of training image with least distance from test image</p>
  
  <pre><code>    int imageIndex = -1; double currMin = 1000000000.0;
      for (int j = 0; j &lt; COL; j++) {
          Mat mat = (transformedData.col(j).t() - transformedTestImage.col(0).t())*(transformedData.col(j) - transformedTestImage.col(0));
          if (currMin &gt; mat.at&lt;double&gt;(0,0)){
              imageIndex = j;
              currMin = mat.at&lt;double&gt;(0, 0);
          }
      }
  </code></pre>