/Users/lyon/j4p/src/j2d/imageproc/HistogramEQProcessor.java

1    // Glenn Josefiak 
2    // Fairfield University 
3    // SW513 
4    // Spring 2003 
5     
6    package j2d.imageproc; 
7     
8    import java.awt.*; 
9     
10   /** 
11    * This classes allows adjustment of an image using histogram 
12    * equalization. 
13    * Reference: Douglas A. Lyon, "Image Processing in Java" 
14    */ 
15   public class HistogramEQProcessor extends ImageProcessor{ 
16    
17       private int lookupTable[] = new int[256]; 
18    
19       private double PMF[][] = new double[3][256]; 
20       private double CMF[][] = new double[3][256]; 
21       private double avgCMF[] = new double[256]; 
22    
23       private boolean blnExponential = false; 
24       private double dblAlpha = 0.001; 
25    
26       /** 
27        * Create a new HistogramEQProcessor 
28        */ 
29       public HistogramEQProcessor(){ 
30           for (int j = 0; j< 256; j++){ 
31               lookupTable[j] = j; 
32           } 
33       } 
34    
35       /** 
36        * Implementation of ImageProcessor 
37        */ 
38       public void performAlgorithm() throws Exception{ 
39           int pixels[]; 
40           int r, g, b; 
41    
42           pixels = getPixels(); 
43    
44           for (int i = 0; i<pixels.length; i++){ 
45    
46               // Separate RGB components 
47               r = (pixels[i] & 0x00FF0000) >> 16; 
48               g = (pixels[i] & 0x0000FF00) >> 8; 
49               b = (pixels[i] & 0x000000FF); 
50    
51               // Adjust the pixel 
52               r = lookupTable[r]; 
53               g = lookupTable[g]; 
54               b = lookupTable[b]; 
55    
56               // store the processed pixel 
57               pixels[i] = 0xFF000000 | (r << 16) | (g << 8) | b; 
58           } 
59    
60           setPixels(pixels); 
61       } 
62    
63       /** 
64        * Set the parameter for exponential EQ. 
65        * 
66        * @param alpha         parameter for exponential EQ 
67        */ 
68       public void setAlpha(double alpha){ 
69           if(alpha == dblAlpha) return; 
70           makeENAHETable(alpha); 
71           dblAlpha = alpha; 
72       } 
73    
74       /** 
75        * Sets uniform/exponential EQ option. 
76        * 
77        * @param state         true = exponential; false = uniform 
78        */ 
79       public void setExponential(boolean state){ 
80           if (state == blnExponential) return; 
81           if (state == true){ 
82               makeENAHETable(dblAlpha); 
83           }else{ 
84               makeUNAHETable(); 
85           } 
86           blnExponential = state; 
87       } 
88    
89       /** 
90        * Set the base image reference.  Compute aggregate stats on 
91        * the image that will be needed for histogram processing. 
92        */ 
93       public void setBaseImage(Image newImage){ 
94           super.setBaseImage(newImage); 
95           computeStats(); 
96           // compute lookup table 
97           if (blnExponential) 
98               makeENAHETable(dblAlpha); 
99           else 
100              makeUNAHETable(); 
101      } 
102   
103      /** 
104       * Compute PMF, CMF, etc. 
105       */ 
106      private void computeStats(){ 
107          int pixels[]; 
108          int r, g, b; 
109          int i, j; 
110          double increment; 
111   
112          pixels = getPixels(); 
113   
114          // Zero out all the stats. 
115          for (j = 0; j< 256; j++){ 
116              for ( i= 0; i<3; i++){ 
117                  PMF[i][j] = 0; 
118                  CMF[i][j] = 0; 
119              } 
120              avgCMF[j] = 0; 
121          } 
122   
123          // Count lots of pixels 
124   
125          increment = 1.0/pixels.length; 
126          for (i = 0; i<pixels.length; i++){ 
127   
128              // Separate RGB components 
129              r = (pixels[i] & 0x00FF0000) >> 16; 
130              g = (pixels[i] & 0x0000FF00) >> 8; 
131              b = (pixels[i] & 0x000000FF); 
132   
133              PMF[0][r] += increment; 
134              PMF[1][g] += increment; 
135              PMF[2][b] += increment; 
136          } 
137          for (i = 0; i< 3; i++){ 
138              CMF[i][0] = PMF[i][0]; 
139              for (j = 1; j < 256; j++){ 
140                  CMF[i][j] = CMF[i][j-1] + PMF[i][j]; 
141              } 
142          } 
143          for (i = 0; i < 3; i++){ 
144              for (j=0; j < 256; j++){ 
145                  avgCMF[j] += CMF[i][j] / 3; 
146              } 
147          } 
148      } 
149   
150      /** 
151       * Create lookup table for Uniform Non Adaptive 
152       * Histogram Equalization 
153       */ 
154      private void makeUNAHETable() { 
155          for (short i = 0; i < lookupTable.length; i++){ 
156              lookupTable[i] = (short) (255 * avgCMF[i]); 
157          } 
158      } 
159   
160      /** 
161       * Create lookup table for Exponential Non Adaptive 
162       * Histogram Equalization 
163       */ 
164      private void makeENAHETable(double alpha) { 
165          double val; 
166          double inverseCMF; 
167   
168          for (short i = 0; i < lookupTable.length; i++){ 
169              inverseCMF = 1.0 - avgCMF[i]; 
170              if (inverseCMF <= 0){ 
171                  // Keep log in defined range at top of CMF; the CMF 
172                  // may be >1 due to rounding. 
173                  val = 255; 
174              }else{ 
175                  val = 255.0 * (-Math.log(inverseCMF) / alpha); 
176                  val = Math.min(255, val); 
177                  val = Math.max(0, val); 
178              } 
179              lookupTable[i] = (int)val; 
180          } 
181      } 
182  } 
183