package fr.unistra.pelican.algorithms.descriptors.shape; import fr.unistra.pelican.Descriptor; import fr.unistra.pelican.Image; import fr.unistra.pelican.algorithms.conversion.RGBToGray; import fr.unistra.pelican.util.data.DoubleArrayData; /** * Computes a series of geometric moments for its input * that are supposed to describe the shape of its content. * * They are computed using the grey-level version of the input. * * * @author Erchan Aptoula * @author Régis Witz (mask support, normalization and framework adaptation) */ public class GeometricMoments extends Descriptor { /** First input parameter. */ public Image input; /** Output parameter. */ public DoubleArrayData output; /** Constructor */ public GeometricMoments() { super(); super.inputs = "input"; super.outputs = "output"; } public static DoubleArrayData exec( Image input ) { return ( DoubleArrayData ) new GeometricMoments().process( input ); } /** @see fr.unistra.pelican.Algorithm#launch() */ @SuppressWarnings("unchecked") public void launch() { if ( this.input.getBDim() != 1 ) input = RGBToGray.exec(input); int sizeTotal = 7; Double[] values = new Double[ sizeTotal ]; // moments of order : 00, 01, 10, 11, 02, 20, 22 for ( int i = 0 ; i < sizeTotal ; i++ ) values[i] = new Double(0); values[0] = moment(0,0); values[1] = moment(0,1); values[2] = moment(1,0); values[3] = moment(1,1); values[4] = moment(0,2); values[5] = moment(2,0); values[6] = moment(2,2); normalize( values ); this.output = new DoubleArrayData(); this.output.setDescriptor( ( Class ) this.getClass() ); this.output.setValues( values ); } private double moment( int i, int j ) { int n = 0; double d = 0.0; for ( int x = 0 ; x < this.input.getXDim() ; x++ ) { for ( int y = 0 ; y < this.input.getYDim() ; y++ ) { if ( this.input.isPresentXY( x,y ) ) { d += Math.pow(x,i) * Math.pow(y,j) * this.input.getPixelXYDouble(x,y); n++; } } } if ( n == 0 ) return 0.0; return d/ ( ( Math.pow( this.input.getXDim(),i+1 )*Math.pow( this.input.getYDim(),j+1 ) ) / Math.pow( Math.sqrt(n), (double)i/2+(double)j/2+1 ) ) ; } // public static double distance( Data d1, Data d2 ) { // // Double[] v1 = (Double[]) d1.getValues(); // Double[] v2 = (Double[]) d2.getValues(); // return Tools.euclideanDistance( v1,v2 ); // } /** Vector normalization. * @param vector wich is normalized at end if possible. * @return 0, or -1 si <tt>vector</tt>'s norm equals to zero. */ private static int normalize( Double[] vector ) { double norm = 0; for ( int i = 0 ; i < vector.length ; i++ ) norm += vector[i]*vector[i]; norm = Math.sqrt( norm ); if ( norm == 0 ) return -1; if ( norm != 1 ) for ( int i = 0 ; i < vector.length ; i++ ) vector[i] = vector[i]/norm; return 0; } }