Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libRaster / src / org / gvsig / raster / datastruct / Histogram.java @ 13925

History | View | Annotate | Download (12.4 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2007 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 */
19
package org.gvsig.raster.datastruct;
20

    
21
import org.apache.log4j.Logger;
22

    
23

    
24
/**
25
 * Representa un histograma.
26
 * @version 27/03/2007
27
 * @author Nacho Brodin (nachobrodin@gmail.com)
28
 *
29
 */
30
public class Histogram {
31
        /**
32
         * Variable que representa el histograma. La primera dimensi?n es el n?mero de 
33
         * bandas y la segunda un array de clases. En el caso b?sico de un RGB una clase tendr? el
34
         * valor m?nimo igual al m?ximo.
35
         */
36
        private HistogramClass[][] histogram = null;
37
        private int nClasses = 0;
38
        
39
        private long[][] table = null;
40
        private static String[] types = {"normal", "accumulated", "logaritmic"};
41
        private double min = Double.MAX_VALUE;
42
        private double max = Double.NEGATIVE_INFINITY;
43
        
44
        /**
45
         * Constructor
46
         */
47
        public Histogram(int nBands, int nClasses, double min, double max) {
48
                table = new long[nBands][nClasses];
49
                for (int i=0; i < table.length; i++)
50
                        for (int j = 0; j < table[0].length; j++)
51
                                table[i][j] = 0;
52
                this.min = min;
53
                this.max = max;
54
                this.nClasses = nClasses;
55
        }
56
        
57
        /**
58
         * Realiza la uni?n entre el histograma actual y el pasado 
59
         * por par?metro.
60
         * @param hist
61
         */
62
        public boolean union(Histogram hist) {
63
                if (nClasses != hist.getNumValues())
64
                        return false;
65
                for (int i = 0; i < table.length; i++) {
66
                        for (int j = 0; j < nClasses; j++) {
67
                                table[i][j] += hist.getTable()[i][j];
68
                        }
69
                }        
70
                return true;
71
        }
72
        
73
        /**
74
         * Asigna la tabla
75
         * @param t
76
         */
77
        public void setTable(long[][] t) {
78
                table = t;
79
        }
80
                
81
        /**
82
         * Obtiene el histograma sin modificar
83
         * @return array bidimensional donde el primer elemento es el valor del pixel
84
         * o rango y el segundo el n?mero de elementos que aparecen.
85
         */
86
        public HistogramClass[][] getHistogram() {
87
                if (nClasses <= 0)
88
                        return null;
89
                
90
                histogram = new HistogramClass[table.length][nClasses];
91
                
92
                for (int i = 0; i < table.length; i++) {
93
                        for (int j = 0; j < nClasses; j++) {
94
                                HistogramClass hc = new HistogramClass(        min + ((j * (max - min)) / nClasses), 
95
                                                                                                                min + (((j + 1) * (max - min)) / nClasses));
96
                                hc.setValue(table[i][j]);
97
                                histogram[i][j] = hc;
98
                        }
99
                }
100
                return histogram;
101
        }
102
        
103
        /**
104
         * Obtiene el n?mero de bandas del histograma 
105
         * @return entero que representa el n?mero de bandas 
106
         */
107
        public int getNumBands() {
108
                if (table != null)
109
                        return table.length;
110
                return 0;
111
        }
112
        
113
        /**
114
         * Obtiene la longitud (n?mero de valores) de una banda determinada
115
         * @param band Banda o obtener la longitud
116
         * @return entero con la longitud de la banda
117
         * rangos de valores y DataclassList.
118
         */
119
        public int getBandLenght(int band) {
120
                if (table != null)
121
                        return table[band].length;
122
                return 0;
123
        }
124
        
125
        /**
126
         * Obtiene el n?mero de valores o clases del histograma
127
         * @return entero que representa el n?mero de valores o clases del histograma
128
         */
129
        public int getNumValues() {
130
                return nClasses;
131
        }
132
        
133
        /**
134
         * Asigna un histograma
135
         * @param hist histograma asignado
136
         */
137
        public void setHistogram(HistogramClass[][] hist){
138
                histogram = hist;
139
        }
140
                
141
        /**
142
         * Asigna un valor para una posici?n del histograma
143
         * @param band Valor del pixel o clase a asignar
144
         * @param px Valor del pixel
145
         * @param value Valor a asignar
146
         */
147
        public void setHistogramValue(int band, double px, long value) {
148
                int pos = (int) ((nClasses * (px - min))/(max-min));
149
                if (pos < 0) pos = 0;
150
                if (pos >= nClasses) pos = nClasses - 1;
151
                table[band][pos] = value;
152
        }
153
        
154
        /**
155
         * Asigna un valor para una posici?n del histograma segun la posicion en las
156
         * clases
157
         * @param band Valor del pixel o clase a asignar
158
         * @param pos Posicion dentro de la clase. Ejemplo 0..63
159
         * @param value Valor a asignar
160
         */
161
        public void setHistogramValueByPos(int band, int pos, long value) {
162
                if (pos < 0) pos = 0;
163
                if (pos >= nClasses) pos = nClasses - 1;
164
                table[band][pos] = value;
165
        }
166

    
167
        /**
168
         * Obtiene un valor del histograma
169
         * @param band N?mero de banda del valor a recuperar
170
         * @param px Pixel o valor de la clase del valor a recuperar
171
         * @return valor
172
         */
173
        public double getHistogramValue(int band, double px) {
174
                if (histogram == null) getHistogram();
175
                for (int i = 0; i < histogram[band].length; i++) {
176
                        if (((HistogramClass)histogram[band][i]).isIn(px))
177
                                return ((HistogramClass)histogram[band][i]).getValue();
178
                }                
179
                return 0;
180
        }
181
        
182
        /**
183
         * Obtiene un valor del histograma segun la posicion dentro de las clases
184
         * @param band N?mero de banda del valor a recuperar
185
         * @param px Pixel o valor de la clase del valor a recuperar
186
         * @return valor
187
         */
188
        public double getHistogramValueByPos(int band, int pos) {
189
                if (pos < 0) pos = 0;
190
                if (pos >= nClasses) 
191
                        pos = nClasses - 1;
192
                return table[band][pos];
193
        }
194
        
195
        /**
196
         * Incrementa un valor de una posici?n del histograma
197
         * @param band N?mero de banda
198
         * @param px Pixel o valor de la clase
199
         */
200
        public void incrementPxValue(int band, double px) {
201
                int pos = (int) ((nClasses * (px - min)) / (max - min));
202
                if (pos < 0) 
203
                        pos = 0;
204
                if (pos >= nClasses) 
205
                        pos = nClasses - 1;
206
                table[band][pos]++;
207
        }
208
        
209
        /**
210
         * Devuelve el histograma acumulado
211
         * @return
212
         */
213
        public HistogramClass[][] getAccumulatedHistogram() {
214
                if (histogram != null) {
215
                        HistogramClass[][] hist = new HistogramClass[histogram.length][histogram[0].length];
216
                        for (int iBand = 0; iBand < hist.length; iBand++) {
217
                                hist[iBand][0] = new HistogramClass(histogram[iBand][0].getMin(), histogram[iBand][0].getMax());
218
                                hist[iBand][0].setValue(histogram[iBand][0].getValue());
219
                                for (int j = 1; j < hist[iBand].length; j++) {
220
                                        hist[iBand][j] = new HistogramClass(histogram[iBand][j].getMin(), histogram[iBand][j].getMax());
221
                                        hist[iBand][j].setValue(hist[iBand][j - 1].getValue() + histogram[iBand][j].getValue());
222
                                }
223
                        }
224
                        return hist;
225
                }
226
                return null;
227
        }
228
        
229
        /**
230
         * Devuelve el histograma logaritmico
231
         * @return
232
         */
233
        public HistogramClass[][] getLogaritmicHistogram() {
234
                if (histogram != null) {
235
                        HistogramClass[][] hist = new HistogramClass[histogram.length][histogram[0].length];
236
                        double minim = Double.MAX_VALUE;
237
                        for (int iBand = 0; iBand < histogram.length; iBand++) {
238
                                for (int j = 0; j < histogram[iBand].length; j++) {
239
                                        if (minim > histogram[iBand][j].getValue())
240
                                                minim = histogram[iBand][j].getValue();
241
                                }
242
                        }
243
                        for (int iBand = 0; iBand < histogram.length; iBand++) {
244
                                for (int j = 0; j < histogram[iBand].length; j++) {
245
                                        hist[iBand][j] = new HistogramClass(histogram[iBand][j].getMin(), histogram[iBand][j].getMax());
246
                                        hist[iBand][j].setValue(java.lang.Math.log(histogram[iBand][j].getValue() - minim + 1.0));
247
                                }
248
                        }
249
                        return hist;
250
                }
251
                return null;
252

    
253
        }
254
        
255
        /**
256
         * N?mero de tipos de histograma definidos en esta clase.
257
         * @return entero con el n?mero de tipos definidos.
258
         */
259
        public static int getHistogramTypesCount() {
260
                return types.length;
261
        }
262
        
263
        /**
264
         * Obtiene un tipo de histograma a partir de su posici?n en el array
265
         * @param pos posici?n en el array del tipo a obtener
266
         * @return Tipo
267
         */
268
        public static String getType(int pos) {
269
                return types[pos];
270
        }
271
        
272
        /**
273
         * Obtiene el histograma correspondiente al tipo pasado por par?metro. Los tipos
274
         * est?n definidos en esta misma clase de forma est?tica en la variable types.
275
         * @param type Tipo a devolver
276
         * @return Histograma
277
         */
278
        public HistogramClass[][] getHistogramByType(String type) {
279
                if(type.equals(types[0]))
280
                        return getHistogram();
281
                if(type.equals(types[1]))
282
                        return getAccumulatedHistogram();
283
                if(type.equals(types[2]))
284
                        return getLogaritmicHistogram();
285
                return null;
286
        }
287
        
288
  /**
289
   * Calculo de estad?sticas a partir de un histograma. El resultado de la funci?n es un array
290
   * bidimensional donde el primer ?ndice inndica la estadistica y el segundo el n?mero de banda.
291
   * 
292
   * <UL>
293
   * <LI>m?nimo</LI>
294
   * <LI>m?ximo</LI>
295
   * <LI>media</LI>
296
   * <LI>mediana</LI>
297
   * <LI>N?mero de pixels</LI>
298
   * </UL>
299
   * @param histogram
300
   * @param bandas solicitadas. Cada elemento del vector representa una banda. Si est? a true se calcula la 
301
   * estadistica para esa banda y si est? a false no se calcular?.
302
   * @return
303
   */
304
  public double[][] getBasicStats(boolean[] bands) {
305
          if (histogram == null)
306
                  return null;
307
          return getBasicStats(0, histogram[0].length - 1, bands);
308
  }
309

    
310
  /**
311
   * Calculo de estad?sticas a partir de un histograma. El resultado de la funci?n es un array
312
   * bidimensional donde el primer ?ndice inndica la estadistica y el segundo el n?mero de banda.
313
   * 
314
   * <UL>
315
   * <LI>m?nimo</LI>
316
   * <LI>m?ximo</LI>
317
   * <LI>media</LI>
318
   * <LI>mediana</LI>
319
   * <LI>N?mero de pixels</LI>
320
   * </UL>
321
   * @param histogram
322
   * @param beginPos Posici?n de inicio del histograma para contabilizar estadisticas
323
   * @param endPos Posici?n de fin del histograma para contabilizar estadisticas
324
   * @param bandas solicitadas. Cada elemento del vector representa una banda. Si est? a true se calcula la 
325
   * estadistica para esa banda y si est? a false no se calcular?.
326
   * @return
327
   */
328
  public double[][] getBasicStats(double beginPos2, double endPos2, boolean[] bands) {
329
                if (histogram == null)
330
                        getHistogram();
331
                
332
                int beginPos = (int) ((beginPos2 * (nClasses - 1)) / 100.0);
333
                int endPos = (int) ((endPos2 * (nClasses - 1)) / 100.0);
334

    
335
                // Contamos el n?mero de bandas para las cuales se calcula la estad?stica
336
                int bandCount = 0;
337
                for (int iBand = 0; iBand < bands.length; iBand++)
338
                        if (bands[iBand])
339
                                bandCount++;
340

    
341
                double[][] res = new double[5][];
342

    
343
                double[] min = new double[bandCount];// M?nimo
344
                double[] max = new double[bandCount];// M?ximo
345
                for (int iBand = 0; iBand < bandCount; iBand++) {
346
                        max[iBand] = Double.NEGATIVE_INFINITY;
347
                        min[iBand] = Double.POSITIVE_INFINITY;
348
                }
349
                double[] average = new double[bandCount]; // Valor de pixel medio (Media)
350
                double[] middle = new double[bandCount]; // Mediana
351
                double[] nPixelsBand = new double[bandCount];// N?mero de pixels por banda
352

    
353
                int showBandCounter = 0; // Contador de bandas de las que hay calcular la
354
                              // estadistica
355
                for (int iBand = 0; iBand < histogram.length; iBand++) {
356
                        if (bands[iBand]) {
357
                                for (int i = beginPos; i <= endPos; i++) {
358
                                        // Calculo del m?nimo
359
                                        if (histogram[iBand][i].getValue() != 0 && histogram[iBand][i].getMin() < min[showBandCounter])
360
                                                min[showBandCounter] = histogram[iBand][i].getMin();
361

    
362
                                        // Calculo del m?ximo
363
                                        if (histogram[iBand][i].getValue() != 0 && histogram[iBand][i].getMax() > max[showBandCounter])
364
                                                max[showBandCounter] = histogram[iBand][i].getMax();
365

    
366
                                        // Calculo del n?mero de pixeles
367
                                        nPixelsBand[showBandCounter] += histogram[iBand][i].getValue();
368

    
369
                                        average[showBandCounter] += histogram[iBand][i].getValue() * ((histogram[iBand][i].getMax() + histogram[iBand][i].getMin())/2);
370
                                }
371
                                // Calculo de la media
372
                                try {
373
                                        average[showBandCounter] /= nPixelsBand[showBandCounter];
374
                                } catch (ArithmeticException exc) {
375
                                        average[showBandCounter] = 0;
376
                                }
377

    
378
                                // Calculo de mediana
379
                                double stopPos = nPixelsBand[showBandCounter] / 2;
380
                                int aux = 0;
381
                                int i = beginPos;
382
                                for (i = beginPos; aux <= stopPos; i++) {
383
                                        try {
384
                                                aux += histogram[iBand][i].getValue();
385
                                        } catch (ArrayIndexOutOfBoundsException e) {
386
                                                Logger.getLogger(getClass().getName()).debug("Acceso a un valor de histogram (Banda: " + iBand + " Posici?n" + i + ") fuera de l?mites. (NBandas: " + histogram.length + " Valores:" + histogram[0].length + ")", e);
387
                                        }
388
                                }
389
                                middle[showBandCounter] = (histogram[iBand][i - 1].getMax() + histogram[iBand][i - 1].getMin()) / 2;
390

    
391
                                showBandCounter++;
392
                        }
393
                }
394
   
395
          res[0] = min;
396
          res[1] = max;
397
          res[2] = average;
398
          res[3] = middle;
399
          res[4] = nPixelsBand;
400
          return res;
401
  }
402
  
403
  /**
404
   * Obtiene la tabla de valores
405
   * @return
406
   */
407
  public long[][] getTable() {
408
          return table;
409
  }
410
}