package edu.stanford.rsl.conrad.calibration; import java.util.ArrayList; import Jama.EigenvalueDecomposition; import Jama.Matrix; import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND; /** * Implements the Principal Component Analysis for a set of PointND.java, restricted to 2D. First the centroid S is computed. * Then the set of points is weighted and the covariance matrix C is built. Eigenvalues and eigenvectors are estimated using * the Eigenvalue Decomposition. Imports Jama.Matrix and Jama.EigenvalueDecomposition. * * @author Philipp Roser */ public class PrincipalComponentAnalysis2D { /** * double array containing the eigenvalues of the covariance matrix C. Should be of length 2. */ private double[] eigenvalues; /** * Jama.Matrix array containing the eigenvectors of the covariance matrix C. Should be of length 2. */ private Matrix[] eigenvectors; /** * Covariance matrix C of the data set. */ private Matrix C; /** * Centroid S of the data set. */ private PointND S; /** * PointND array containing the data to be analyzed. */ private PointND[] set; /** * PointND array containing the data translated by the centroid. */ private PointND[] weightedSet; /** * Constructor, expecting the data set to be analyzed as array PointND[]. Executes the complete Principal Component Analysis. * * @param set */ public PrincipalComponentAnalysis2D(PointND[] set) { this.set = set; computeS(); weightSet(); buildC(); computeEigenvalues(); computeEigenvectors(); } /** * Constructor, expecting the data set to be analyzed as ArrayList<PointND>. Executes the complete Principal Component Analysis. * * @param set */ public PrincipalComponentAnalysis2D(ArrayList<PointND> set) { this.set = new PointND[set.size()]; for (int i = 0; i < this.set.length; i++) { this.set[i] = new PointND(set.get(i)); } computeS(); weightSet(); buildC(); computeEigenvalues(); computeEigenvectors(); } /** * * @return Principal Components of the data set as Jama.Matrix[] of length 2. */ public Matrix[] getEigenvectors() { return this.eigenvectors; } /** * * @return Principal Components of the data set as String. */ public String stringEigenvectors() { String result = ""; for (int i = 0; i < eigenvectors.length; i++) { result += "e" + i + " = (" + eigenvectors[i].get(0, 0) + ", " + eigenvectors[i].get(1, 0) + ")\n"; } return result; } /** * * @return eigenvalues of the covariance matrix */ public double[] getEigenvalues() { return this.eigenvalues; } /** * Computes the centroid S of the data set. */ private void computeS() { double xsum = 0.0; double ysum = 0.0; for (int i = 0; i < set.length; i++) { xsum = xsum + set[i].get(0); ysum = ysum + set[i].get(1); } S = new PointND(xsum / set.length, ysum / set.length); } /** * Translates all points in the data set by the centroid S. */ private void weightSet() { weightedSet = new PointND[set.length]; for (int i = 0; i < set.length; i++) { weightedSet[i] = new PointND(set[i].get(0) - S.get(0), set[i].get(1) - S.get(1)); } } /** * Builds the covariance matrix. */ private void buildC() { C = new Matrix(2, 2); int n = set.length; for (int i = 0; i < n; i++) { Matrix P = new Matrix(2, 2); P.set(0, 0, ((double) 1.0 / (n - 1)) * weightedSet[i].get(0) * weightedSet[i].get(0)); P.set(0, 1, ((double) 1.0 / (n - 1)) * weightedSet[i].get(0) * weightedSet[i].get(1)); P.set(1, 0, ((double) 1.0 / (n - 1)) * weightedSet[i].get(1) * weightedSet[i].get(0)); P.set(1, 1, ((double) 1.0 / (n - 1)) * weightedSet[i].get(1) * weightedSet[i].get(1)); C = C.plus(P); } } /** * Estimates the eigenvalues of the covariance Matrix C using Jama.EigenvalueDecomposition. */ private void computeEigenvalues() { EigenvalueDecomposition eig = C.eig(); eigenvalues = eig.getRealEigenvalues(); } /** * Estimates the eigenvectors of the covaricance matrix C using Jama.EigenvalueDecomposition. */ private void computeEigenvectors() { // Matrix c1 = C.minus(Matrix.identity(2, 2).times(eigenvalues[0])); // Matrix c2 = C.minus(Matrix.identity(2, 2).times(eigenvalues[1])); EigenvalueDecomposition m = C.eig(); Matrix eig = m.getV(); eigenvectors = new Matrix[2]; eigenvectors[0] = eig.getMatrix(0, 1, 0, 0); eigenvectors[1] = eig.getMatrix(0, 1, 1, 1); /* * eigenvectors[0] = new Matrix(2, 1); eigenvectors[0].set(0, 0, * 1.0); eigenvectors[0].set(1, 0, -1.0 * c1.get(0, 0) / c1.get(0, * 1)); eigenvectors[1] = new Matrix(2, 1); eigenvectors[1].set(0, * 0, 1.0); eigenvectors[1].set(1, 0, -1.0 * c2.get(0, 0) / * c2.get(0, 1)); */ } }