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 }