outlineDescriptor.Transform.java Source code

Java tutorial

Introduction

Here is the source code for outlineDescriptor.Transform.java

Source

/*******************************************************************************
 * @Author David Helekal
 *      Platelocator
 *
 *  Copyright (C) 2014  David Helekal
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package outlineDescriptor;

import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.SingularValueDecomposition;
import org.apache.commons.math3.stat.StatUtils;

@SuppressWarnings("unused")
final class Transform {

    private final static int aSteps = 61;

    private double angle = 0;

    private double coherence = 0;

    private Array2DRowRealMatrix svdMat;

    /**
     * @param pointData a 3 by N array, where N corresponds to the number of points
     *                  [0] corresponds to X coordinates
     *                  [1] corresponds to Y coordinates
     *                  [2] corresponds to intensity value
     */
    public Transform(double[][] pointData) {

        doTransform(pointData);

    }

    private Array2DRowRealMatrix createSVDmatrix(Array2DRowRealMatrix angleOffset, int aSteps, double step) {

        Array2DRowRealMatrix output = new Array2DRowRealMatrix(2 * aSteps, 2);

        for (int i = 0; i < aSteps; i++) {

            double angle = Math.PI - i * step;

            for (int row = 0; row < angleOffset.getRowDimension(); row++) {

                angleOffset.multiplyEntry(row, i, angleOffset.getEntry(row, i));
            }

            double stdDev = getDeviance(angleOffset.getColumn(i));
            // new StandardDeviation().evaluate(angleOffset.getColumn(i));

            double outX = Math.cos(angle) * stdDev;
            double outY = Math.sin(angle) * stdDev;

            output.setEntry(i, 0, outX);
            output.setEntry(i, 1, outY);

            output.setEntry(i + aSteps, 0, -outX);
            output.setEntry(i + aSteps, 1, -outY);

        }

        return output;

    }

    private Array2DRowRealMatrix simpleHoughTransform(Array2DRowRealMatrix inputMatrix, int aSteps, double step) {

        double xMax = StatUtils.max(inputMatrix.getColumn(0));
        double yMax = StatUtils.max(inputMatrix.getColumn(1));

        int maxDst = (int) Math.sqrt(xMax * xMax + yMax * yMax);

        Array2DRowRealMatrix angleOffset = new Array2DRowRealMatrix(2 * maxDst + 1, aSteps);

        //calculating all possible line/distance pairs for each point
        for (int i = 0; i < aSteps; i++) {
            double angle = i * step;

            double xc = Math.cos(Math.PI / 2 - angle);
            double yc = Math.sin(Math.PI / 2 - angle);

            for (int row = 0; row < inputMatrix.getRowDimension(); row++) {

                if (inputMatrix.getEntry(row, 2) == 0)
                    continue;

                int distance = (int) (xc * inputMatrix.getEntry(row, 0) + yc * inputMatrix.getEntry(row, 1));

                distance += maxDst;
                angleOffset.addToEntry(distance, i, inputMatrix.getEntry(row, 2));
            }
        }

        return angleOffset;
    }

    private Array2DRowRealMatrix transform(Array2DRowRealMatrix rm, int aSteps) {
        double meanX = StatUtils.mean(rm.getColumn(0));
        double meanY = StatUtils.mean(rm.getColumn(1));
        double step = Math.PI / aSteps;
        Array2DRowRealMatrix output;

        for (int i = 0; i < rm.getRowDimension(); i++) {
            rm.setEntry(i, 0, rm.getEntry(i, 0) - meanX);
            rm.setEntry(i, 1, rm.getEntry(i, 1) - meanY);
        }

        Array2DRowRealMatrix angleOffset = simpleHoughTransform(rm, aSteps, step);

        output = createSVDmatrix(angleOffset, aSteps, step);

        return output;
    }

    private void doTransform(double[][] pointData) {
        Array2DRowRealMatrix dataMatrix = transform(new Array2DRowRealMatrix(pointData), aSteps);
        Array2DRowRealMatrix v, s;
        double dim1X, dim1Y;
        double eigenVal1, eigenVal2;
        double aCos;

        /*
            
        calculating the SVD
        v - a non-singular matrix containing the eigenvectors of the input matrix
        s - a diagonal matrix containing the corresponding eigenvalues
            
        */

        SingularValueDecomposition svd = new SingularValueDecomposition(dataMatrix);

        v = (Array2DRowRealMatrix) svd.getV();
        s = (Array2DRowRealMatrix) svd.getS();
        dim1X = v.getEntry(0, 0);
        dim1Y = v.getEntry(1, 0);

        eigenVal1 = s.getEntry(0, 0);
        eigenVal2 = s.getEntry(1, 1);

        coherence = (eigenVal1 - eigenVal2) / (eigenVal2 + eigenVal1);
        aCos = dim1Y / Math.sqrt(dim1X * dim1X + dim1Y * dim1Y);
        svdMat = dataMatrix;
        angle = Math.acos(aCos);
        angle = Math.PI / 2 - angle;
    }

    private double getDeviance(double[] col) {

        double mean = StatUtils.mean(col);
        double dsum = 0;

        for (double d : col) {

            dsum += Math.pow(d - mean, 2);

        }

        return dsum / col.length;

    }

    /**
     * @return the angle as measured by SVD
     */
    double getAngle() {
        return angle;
    }

    /**
     * @return SVD coherence
     */
    double getCoherence() {
        return coherence;
    }

    /**
     * @return the Matrix which was used for decomposition
     */
    public Array2DRowRealMatrix getSvdMat() {
        return svdMat;
    }
}