001    /*
002     * TextureAnalysis
003     * 
004     * Copyright (c) 2001, 2002, 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.color.analysis;
009    
010    import net.sourceforge.jiu.color.data.CoOccurrenceMatrix;
011    import net.sourceforge.jiu.ops.MissingParameterException;
012    import net.sourceforge.jiu.ops.Operation;
013    
014    /**
015     * This class determines a number of properties for a given co-occurrence matrix.
016     * The only input parameter is a mandatory co-occurrence matrix object
017     * to be specified using {@link #setMatrix}.
018     * Then {@link #process} must be called.
019     * After that, the various properties can be retrieved using the 
020     * corresponding get methods, e.g. {@link #getContrast}, 
021     * {@link #getEnergy} etc.
022     * <p>
023     * The following resources were helpful when creating this class:
024     * <ul>
025     * <li>Article <em>Suchen ohne Worte</em> by Henning Müller in German computer magazine
026     * c't <a target="_top" href="http://www.heise.de/ct/01/15/004/">15 / 2001</a>,
027     * p. 162ff.</li>
028     * <li><a target="_top" href="http://www.ucalgary.ca/~mhallbey/texture/texture_tutorial.html">GLCM
029     * Texture: A Tutorial</a> by Mryka Hall-Beyer.</li>
030     * <li><a target="_top" href="http://www.burrill.demon.co.uk/meddoc/tmnmri.html">Texture Mapping 
031     * of Neurological Magnetic Resonance Images</a> by J.H.P. Burrill</li>
032     * </ul>
033     * @since 0.7.0
034     *
035     * @author Marco Schmidt
036     */
037    public class TextureAnalysis extends Operation
038    {
039            private CoOccurrenceMatrix matrix;
040            private int contrast;
041            private double correlation;
042            private int dissimilarity;
043            private int energy;
044            private double entropy;
045            private double homogeneity;
046            private int sum;
047            private boolean symmetry;
048    
049            /**
050             * Returns the contrast value determined in {@link #process}.
051             * Also called <em>inertia</em>.
052             */
053            public int getContrast()
054            {
055                    return contrast;
056            }
057    
058            /**
059             * Returns the correlation determined in {@link #process}.
060             */
061            public double getCorrelation()
062            {
063                    return correlation;
064            }
065    
066            /**
067             * Returns the dissimilarity value determined in {@link #process}.
068             */
069            public int getDissimilarity()
070            {
071                    return dissimilarity;
072            }
073    
074            /**
075             * Returns the energy value determined in {@link #process}.
076             */
077            public int getEnergy()
078            {
079                    return energy;
080            }
081    
082            /**
083             * Returns the entropy value determined in {@link #process}.
084             */
085            public double getEntropy()
086            {
087                    return entropy;
088            }
089    
090            /**
091             * Returns the homogeneity value determined in {@link #process}.
092             * Also called <em>inverse difference moment</em>.
093             */
094            public double getHomogeneity()
095            {
096                    return homogeneity;
097            }
098    
099            /**
100             * Returns the sum of all entries in the matrix.
101             */
102            public int getSum()
103            {
104                    return sum;
105            }
106    
107            public boolean isSymmetrical()
108            {
109                    return symmetry;
110            }
111    
112            /**
113             * Run over the input matrix and determine contrast, energy, entropy and homogeneity
114             * of that matrix.
115             * @throws MissingParameterException if no co-occurrence matrix was provided using
116             *  {@link #setMatrix}
117             */
118            public void process() throws
119                    MissingParameterException
120            {
121                    if (matrix == null)
122                    {
123                            throw new MissingParameterException("No input co-occurrence matrix was provided.");
124                    }
125                    final int DIMENSION = matrix.getDimension();
126                    int items = 0;
127                    final int TOTAL_ITEMS = DIMENSION * 3;
128                    // initialize mu_i and mu_j
129                    double[] muI = new double[DIMENSION];
130                    double[] muJ = new double[DIMENSION];
131                    for (int k = 0; k < DIMENSION; k++)
132                    {
133                            muI[k] = 0.0;
134                            muJ[k] = 0.0;
135                            for (int i = 0; i < DIMENSION; i++)
136                            {
137                                    for (int j = 0; j < DIMENSION; j++)
138                                    {
139                                            int value = matrix.getValue(i, j);
140                                            muI[k] += i * value;
141                                            muJ[k] += j * value;
142                                    }
143                            }
144                            setProgress(items++, TOTAL_ITEMS);
145                    }
146                    // initialize sigma_i and sigma_j
147                    double[] sigmaI = new double[DIMENSION];
148                    double[] sigmaJ = new double[DIMENSION];
149                    for (int k = 0; k < DIMENSION; k++)
150                    {
151                            sigmaI[k] = 0.0;
152                            sigmaJ[k] = 0.0;
153                            for (int i = 0; i < DIMENSION; i++)
154                            {
155                                    for (int j = 0; j < DIMENSION; j++)
156                                    {
157                                            int value = matrix.getValue(i, j);
158                                            double a = (i - muI[i]);
159                                            sigmaI[k] += value * a * a;
160                                            double b = (j - muJ[j]);
161                                            sigmaJ[k] += value * b * b;
162                                    }
163                            }
164                            setProgress(items++, TOTAL_ITEMS);
165                    }
166                    contrast = 0;
167                    dissimilarity = 0;
168                    energy = 0;
169                    entropy = 0;
170                    homogeneity = 0;
171                    sum = 0;
172                    symmetry = true;
173                    for (int i = 0; i < DIMENSION; i++)
174                    {
175                            for (int j = 0; j < DIMENSION; j++)
176                            {
177                                    int value = matrix.getValue(i, j);
178                                    symmetry = symmetry && value == matrix.getValue(j, i);
179                                    sum += value;
180                                    energy += value * value;
181                                    int diffAbs = (i - j);
182                                    if (diffAbs < 0)
183                                    {
184                                            diffAbs = - diffAbs;
185                                    }
186                                    dissimilarity += diffAbs * value;
187                                    contrast += diffAbs * diffAbs * value;
188                                    if (value != 0) // log not defined for 0
189                                    {
190                                            entropy += value * Math.log(value);
191                                    }
192                                    homogeneity += value / (1.0 + diffAbs);
193                                    double a = sigmaI[i] * sigmaJ[j];
194                                    if (a != 0.0)
195                                    {
196                                            correlation += (value * (i - muI[i]) * (j - muJ[j])) / Math.sqrt(a);
197                                    }
198                            }
199                            setProgress(items++, TOTAL_ITEMS);
200                    }
201            }
202    
203            /**
204             * Sets the matrix to be used by this operation to the argument value.
205             * @param m the matrix for which the various properties will be computed
206             */
207            public void setMatrix(CoOccurrenceMatrix m)
208            {
209                    matrix = m;
210            }
211    }