001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.image.connectedcomponent.proc;
031
032import org.openimaj.feature.DoubleFV;
033import org.openimaj.feature.FeatureVectorProvider;
034import org.openimaj.image.pixel.ConnectedComponent;
035import org.openimaj.image.processor.connectedcomponent.ConnectedComponentProcessor;
036
037
038/**
039 * Affine-invariant moment descriptor for the
040 * shape of a connected component.
041 * 
042 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
043 */
044public class AffineInvariantMoments implements ConnectedComponentProcessor, FeatureVectorProvider<DoubleFV> {
045        /**
046         * The first affine-invariant moment
047         */
048        public double I1;
049        
050        /**
051         * The second affine-invariant moment
052         */
053        public double I2;
054        
055        /**
056         * The third affine-invariant moment
057         */
058        public double I3;
059        
060        /**
061         * The forth affine-invariant moment
062         */
063        public double I4;
064
065        @Override
066        public void process(ConnectedComponent cc) {
067                double u00 = cc.calculateMoment(0, 0);
068                double u20 = cc.calculateMoment(2, 0);
069                double u02 = cc.calculateMoment(0, 2);
070                double u11 = cc.calculateMoment(1, 1);
071                double u21 = cc.calculateMoment(2, 1);
072                double u12 = cc.calculateMoment(1, 2);
073                double u30 = cc.calculateMoment(3, 0);
074                double u03 = cc.calculateMoment(0, 3);
075
076                I1 = ((u20 * u02) - (u11*u11)) / Math.pow(u00, 4);
077                
078                I2 = ((u30*u30 * u03*u03) - (6 * u30 * u21 * u12 * u03) + 
079                                (4 * u30 * Math.pow(u12, 3)) + (4 * Math.pow(u21, 3) * u03) - (3 * u21 * u21 * u12 *u12)) / 
080                                Math.pow(u00, 10);
081                
082                I3 = ((u20 * (u21*u03 - u12*u12)) - (u11 * (u30*u03 - u21*u12)) + (u02 * (u30*u12 - u21*u21))) / Math.pow(u00, 7);
083                
084                I4 = (Math.pow(u20, 3)*u03*u03 - 6*u20*u20*u11*u12*u03 - 6*u20*u20*u02*u21*u03 + 9*u20*u20*u02*u12*u12 
085                                + 12*u20*u11*u11*u21*u03 + 6*u21*u11*u02*u30*u03 - 18*u20*u11*u02*u21*u12
086                                - 8*Math.pow(u11, 3)*u30*u03 - 6*u20*u02*u02*u30*u12 + 9*u20*u02*u02*u21*u21
087                                + 12*u11*u11*u02*u30*u12 - 6*u11*u02*u02*u30*u21 + Math.pow(u02, 3)*u30*u30) / Math.pow(u00, 11);
088        }
089
090        @Override
091        public String toString() {
092                return String.format("%2.2f, %2.2f, %2.2f, %2.2f", I1, I2, I3, I4);
093        }
094
095        /**
096         * Get all the values of the descriptor as an array.
097         * @return an array of descriptor values
098         */
099        public double[] getFeatureVectorArray() {
100                return new double[] {I1, I2, I3, I4};
101        }
102
103        @Override
104        public DoubleFV getFeatureVector() {
105                return new DoubleFV(getFeatureVectorArray());
106        }
107}