text:  > face_recognition_source.zip > EigenFaceComputation.java
  /* * Copyright (c) 2002 by Konrad Rzeszut Jama.*; /** * Computes an "face space" used for face recognition. * * This idea/algorhitm was derieved from Matthew A. Turn and Alex P. Pentland * paper, titled: "Face Recognition using Eigenfaces" * () *
  * The way this algorhitm works is by treating face recognition as a * "two-dimensional recognition problem, taking advantage of the fact that * faces are normally upright and thus may be described by a small set * of 2-D characterisits views.." (quoted from the paper's abstract) *
  * This work is released to the public with no license and no warranties. * Do with the code as you wish. *
  NOTE: This package uses Jama for computing eigenvalues and eigenvectors. * * Which is available at: *
  * And in case you are worreid about its copyright states:
  * *. * * * *
  * @author Konrad Rzeszutek * @version 1.0 */ public class EigenFaceComputation { /** * Our "heuresticly" determined value of how many faces we want to compute. * Just picked the value at random. You can fool around with it. */ private final static int MAGIC_NR = 11; /** * Compute the "face space" used for face recognition. The recognition is * actually being carried out in the FaceBundle object, but the preparation * of such object requires to do lots of computations. The steps are: *
  ** From then the rest of the algorithm (trying to match a face) has to be * called in {@link FaceBundle}. * * @param face_v 2-D array. Has to have 16 rows. Each column has to have the same length. Each * row contains the image in a vector representation. * @param width The width of the image in the row-vector in face_v. * @param height The height of the image in the row-vector in face_v. * @param id The string representing each of the sixteen images. * * @return An FaceBundle usable for recognition. * */ public static FaceBundle submit(double[][] face_v, int width, int height, String[] id, boolean debug) { int length = width*height; int nrfaces = face_v.length; int i, j, col,rows, pix, image; double temp = 0.0; double[][] faces = new double[nrfaces][length]; //ImageFileViewer simple = new ImageFileViewer(); //simple.setImage(face_v[0],width,height); double[] avgF = new double[length]; /* Compute average face of all of the faces. 1xN^2 */ for ( pix = 0; pix < length; pix++) { temp = 0; for ( image = 0; image < nrfaces; image++) { temp += face_v[image][pix]; } avgF[pix] = temp / nrfaces; } //simple.setImage(avgF, width,height); /* Compute difference. */ for ( image = 0; image < nrfaces; image++) { for ( pix = 0; pix < length; pix++) { face_v[image][pix] = face_v[image][pix] - avgF[pix]; } } /* Copy our face vector (MxN^2). We will use it later */ //for (image = 0; image < nrfaces; image++) // System.arraycopy(face_v[image],0,faces[image],0,length); System.arraycopy(face_v,0,faces,0,face_v.length); //simple.setImage(face_v[0],width,height); /* Build covariance matrix. MxM */ Matrix faceM = new Matrix(face_v, nrfaces,length); Matrix faceM_transpose = faceM.transpose(); /* Covariance matrix - its MxM (nrfaces x nrfaces) */ Matrix covarM = faceM.times(faceM_transpose); //double[][] z = covarM.getArray(); //System.out.println("Covariance matrix is "+z.length+" x "+z[0].length); /* Compute eigenvalues and eigenvector. Both are MxM */ EigenvalueDecomposition E = covarM.eig(); double[] eigValue = diag(E.getD().getArray()); double[][] eigVector = E.getV().getArray(); /* * We only need the largest associated values of the eigenvalues. * Thus we sort them (and keep an index of them) */ int[] index = new int[nrfaces]; double[][] tempVector = new double[nrfaces][nrfaces]; /* Temporary new eigVector */ for ( i = 0; i
  - Compute an average face. *
  - Build an covariance matrix. *
  - Compute eigenvalues and eigenvector *
  - Select only {@link MAGIC_NR} largest eigenvalues (and its corresponding eigenvectors) *
  - Compute the faces using our eigenvectors *
  - Compute our eigenspace for our given images. *
  = 0; col --) { for ( rows = 0; rows < nrfaces; rows++ ){ tempVector[rows][col] = eigVector[rows][index[col]]; } } eigVector = tempVector; tempVector = null; eigValue = null; /* * From this point on we don't care about our eigenvalues anymore. * * * We multiply our faceM (MxN^2) with our new eigenvector (MxM), * getting eigenfaces (MxN^2) */ Matrix eigVectorM = new Matrix(eigVector, nrfaces,nrfaces); eigVector = eigVectorM.times(faceM).getArray(); /* Normalize our eigen vector matrix. */ for ( image = 0; image < nrfaces; image++) { temp = max(eigVector[image]); // Our max for ( pix = 0; pix < eigVector[0].length; pix++) // Normalize eigVector[image][pix] = Math.abs( eigVector[image][pix] / temp); } /* * And now the computation of wk (face space), which is a vector and * is of some heuristically determind length. How does 11 sound? * * This is where we are using our copied faces vector (look at the * the beginning of the method) - the reason is b/c the faceM made the * array internally an covariance matrix. */ double[][] wk = new double[nrfaces][MAGIC_NR]; // M rows, 11 columns /* Compute our wk. */ for (image = 0; image < nrfaces; image++) { for (j = 0; j < MAGIC_NR; j++) { temp = 0.0; for ( pix=0; pix< length; pix++) temp += eigVector[j][pix] * faces[image][pix]; wk[image][j] = Math.abs( temp ); } } /* That's it! */ FaceBundle b = new FaceBundle(avgF, wk, eigVector ,id); /* //This is what you would use to recognize a face ... double[] inputFace = new double[length]; // So we are trying to recognize the 14th image.. System.arraycopy(faces[14],0,inputFace,0,length); // This is done for virgin images, not ones that we already subtracted. // for ( pix = 0; pix < inputFace.length; pix++) { // inputFace[pix] = inputFace[pix] - avgF[pix]; //} */ /* double[] input_wk = new double[MAGIC_NR]; for (j = 0; j < MAGIC_NR; j++) { temp = 0.0; for ( pix=0; pix sum(distance)) { idx = image; System.arraycopy(distance,0,minDistance,0,MAGIC_NR); } } */ /* * Normalize our minimum distance. */ /* divide(minDistance, max(minDistance)+1); double minD = sum(minDistance); System.out.println("image is idx "+idx+" distance from face: "+minD); //ImageFileViewer simple = new ImageFileViewer(); int[] bb = new int[length]; temp = max(eigVector[0]); for ( i = 0; i < width*height; i++) { bb[i] = (int) (255*(1 - eigVector[0][i] / temp )); } simple.setImage(bb,width,height); */ return b; } /** * Find the diagonal of an matrix. * * @param m the number of rows and columns must be the same * @return the diagonal of the matrix */ static double[] diag(double[][] m) { double[] d = new double[m.length]; for (int i = 0; i< m.length; i++) d[i] = m[i][i]; return d; } /** *; } /** * Quick sort on a vector with an index. * * @param a the array of numbers. This will be modified and sorted * ascendingly (smalles to highest) * @param index the index of the numbers as related to original * location. * @param lo the index where to start from. Usually 0. * @param hi the index where to stop. Usually a.length() */ static void doubleQuickSort(double a[], int index[], int lo0, int hi0) { int lo = lo0; int hi = hi0; double mid; if ( hi0 > lo0) { /* Arbitrarily establishing partition element as the midpoint of * the array. */ mid = a[ ( lo0 + hi0 ) / 2 ]; // loop through the array until indices cross while( lo <= hi ) { /* find the first element that is greater than or equal to * the partition element starting from the left Index. */ while( ( lo < hi0 ) && ( a[lo] < mid )) { ++lo; } /* find an element that is smaller than or equal to * the partition element starting from the right Index. */ while( ( hi > lo0 ) && ( a[hi] > mid )) { --hi; } // if the indexes have not crossed, swap if( lo <= hi ) { swap(a, index, lo, hi); ++lo; --hi; } } /* If the right index has not reached the left side of array * must now sort the left partition. */ if( lo0 < hi ) { doubleQuickSort( a, index, lo0, hi ); } /* If the left index has not reached the right side of array * must now sort the right partition. */ if( lo < hi0 ) { doubleQuickSort( a, index,lo, hi0 ); } } } static private void swap(double a[], int[] index, int i, int j) { double T; T = a[i]; a[i] = a[j]; a[j] = T; // Index index[i] = i; index[j] = j; } }