/*
* Copyright (C) 2011-2015, Peter Abeles. All Rights Reserved.
*
* This file is part of Geometric Regression Library (GeoRegression).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package georegression.fitting.ellipse;
import georegression.struct.point.Vector2D_F64;
import org.ejml.data.Complex64F;
import org.ejml.data.DenseMatrix64F;
import org.ejml.factory.DecompositionFactory;
import org.ejml.interfaces.decomposition.EigenDecomposition;
/**
* Computes a containment ellipse given a covariance
*
* @author Peter Abeles
*/
public class CovarianceToEllipse_F64 {
EigenDecomposition<DenseMatrix64F> eigen = DecompositionFactory.eig(2, true);
DenseMatrix64F Q = new DenseMatrix64F(2,2);
// major axis
Vector2D_F64 x = new Vector2D_F64();
// minor axis
Vector2D_F64 y = new Vector2D_F64();
// major and minor axis length (in that order)
double lengthX,lengthY;
// number of standard deviations the ellipse should be
double numStdev = 1;
public void setNumStdev(double numStdev) {
this.numStdev = numStdev;
}
/**
* Specifies the covariance matrix. Q = [a11 a12; a12 a22]
* @param a11 element in covariance matrix.
* @param a12 element in covariance matrix.
* @param a22 element in covariance matrix.
* @return true if it was successful or false if something went wrong
*/
public boolean setCovariance( double a11 , double a12, double a22 ) {
Q.data[0] = a11;
Q.data[1] = a12;
Q.data[2] = a12;
Q.data[3] = a22;
if( !eigen.decompose(Q) ) {
System.err.println("Eigenvalue decomposition failed!");
return false;
}
Complex64F v0 = eigen.getEigenvalue(0);
Complex64F v1 = eigen.getEigenvalue(1);
DenseMatrix64F a0,a1;
if( v0.getMagnitude2() > v1.getMagnitude2() ) {
a0 = eigen.getEigenVector(0);
a1 = eigen.getEigenVector(1);
lengthX = (double) v0.getMagnitude();
lengthY = (double) v1.getMagnitude();
} else {
a0 = eigen.getEigenVector(1);
a1 = eigen.getEigenVector(0);
lengthX = (double) v1.getMagnitude();
lengthY = (double) v0.getMagnitude();
}
if( a0 == null || a1 == null ) {
System.err.println("Complex eigenvalues: "+v0+" "+v1);
return false;
}
lengthX = Math.sqrt(lengthX);
lengthY = Math.sqrt(lengthY);
x.set( (double) a0.get(0) , (double) a0.get(1));
y.set( (double) a1.get(0) , (double) a1.get(1));
return true;
}
/**
* @return Vector which defines the major axis
*/
public Vector2D_F64 getMajorVector() {
return x;
}
/**
* @return Vector which defines the minor axis
*/
public Vector2D_F64 getMinorVector() {
return y;
}
/**
* @return Angle between the major axis and the x-axis
*/
public double getAngle() {
return Math.atan2( x.y, x.x );
}
/**
* @return Length of the major axis
*/
public double getMajorAxis() {
return numStdev*lengthX;
}
/**
* @return Length of the minor axis
*/
public double getMinorAxis() {
return numStdev*lengthY;
}
}