Java tutorial
/******************************************************************************* * @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; } }