imagingbook.lib.math.MahalanobisDistance.java Source code

Java tutorial

Introduction

Here is the source code for imagingbook.lib.math.MahalanobisDistance.java

Source

/*******************************************************************************
 This software is provided as a supplement to the authors' textbooks on digital
 image processing published by Springer-Verlag in various languages and editions.
 Permission to use and distribute this software is granted under the BSD 2-Clause 
 "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 
 Copyright (c) 2006-2013 Wilhelm Burger, Mark J. Burge. 
 All rights reserved. Visit http://www.imagingbook.com for additional details.
 ******************************************************************************/

package imagingbook.lib.math;

import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.stat.correlation.Covariance;

/**
 * This class implements the Mahalanobis distance using the Apache commons math library.
 * UNFINISHED! Complete distance/magnitude methods.
 */
public class MahalanobisDistance extends VectorNorm {

    final int N; // number of samples
    final int K; // feature dimension
    final double[][] iS; // inverse covariance matrix = S^{-1} of size K x K

    public MahalanobisDistance(double[][] samples) {
        N = samples.length;
        K = samples[0].length;
        Covariance cov = new Covariance(samples);
        RealMatrix S = cov.getCovarianceMatrix();
        // condition the covariance matrix to avoid singularity 
        // (add a small quantity to the diagonal)
        for (int i = 0; i < K; i++) {
            S.addToEntry(i, i, 0.0001);
        }
        // get the inverse covariance matrix
        RealMatrix iSM = new LUDecomposition(S).getSolver().getInverse();
        iS = iSM.getData();
    }

    public int getNumberOfSamples() {
        return N;
    }

    public int getSampleDimension() {
        return K;
    }

    public double distance(double[] a, double[] b) {
        return Math.sqrt(distance2(a, b));
    }

    // check calculation again!
    public double distance2(double[] X, final double[] Y) {
        if (X.length != K || Y.length != K) {
            throw new IllegalArgumentException("vectors must be of length " + K);
        }
        // d(X,Y) = sqrt[(X-Y)^T . S^{-1} . (X-Y)]      
        int m = X.length;
        double[] diffXY = new double[m]; // = (X-Y)
        for (int j = 0; j < m; j++) {
            diffXY[j] = X[j] - Y[j];
        }
        double[] SdiffXY = new double[m]; // = S^{-1} . (X-Y)
        for (int j = 0; j < m; j++) {
            for (int i = 0; i < m; i++) {
                SdiffXY[j] += iS[i][j] * diffXY[i];
            }
        }
        double d = 0;
        for (int i = 0; i < m; i++) {
            d += diffXY[i] * SdiffXY[i];
        } // d = (X-Y)^T . S^{-1} . (X-Y)
        return d;
    }

    public double distance(int[] a, int[] b) {
        throw new UnsupportedOperationException();
    }

    public double distance2(int[] a, int[] b) {
        throw new UnsupportedOperationException();
    }

    public double magnitude(double[] X) {
        throw new UnsupportedOperationException();
    }

    public double magnitude(int[] X) {
        throw new UnsupportedOperationException();
    }

    public double getScale(int n) {
        return 1.0;
    }
}