Statistics
| Revision:

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

History | View | Annotate | Download (12.5 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
         * @param nBands N?mero de bandas
47
         * @param nClasses N?mero de clases en que hacemos la divisi?n
48
         * @param min Valor m?nimo del histograma
49
         * @param max Valor m?ximo del histograma
50
         */
51
        public Histogram(int nBands, int nClasses, double min, double max) {
52
                table = new long[nBands][nClasses];
53
                for (int i=0; i < table.length; i++)
54
                        for (int j = 0; j < table[0].length; j++)
55
                                table[i][j] = 0;
56
                this.min = min;
57
                this.max = max;
58
                this.nClasses = nClasses;
59
        }
60
        
61
        /**
62
         * Realiza la uni?n entre el histograma actual y el pasado 
63
         * por par?metro.
64
         * @param hist
65
         */
66
        public boolean union(Histogram hist) {
67
                if (nClasses != hist.getNumValues())
68
                        return false;
69
                for (int i = 0; i < table.length; i++) {
70
                        for (int j = 0; j < nClasses; j++) {
71
                                table[i][j] += hist.getTable()[i][j];
72
                        }
73
                }        
74
                return true;
75
        }
76
        
77
        /**
78
         * Asigna la tabla
79
         * @param t
80
         */
81
        public void setTable(long[][] t) {
82
                table = t;
83
        }
84
                
85
        /**
86
         * Obtiene el histograma sin modificar
87
         * @return array bidimensional donde el primer elemento es el valor del pixel
88
         * o rango y el segundo el n?mero de elementos que aparecen.
89
         */
90
        public HistogramClass[][] getHistogram() {
91
                if (nClasses <= 0)
92
                        return null;
93
                
94
                histogram = new HistogramClass[table.length][nClasses];
95
                
96
                for (int i = 0; i < table.length; i++) {
97
                        for (int j = 0; j < nClasses; j++) {
98
                                HistogramClass hc = new HistogramClass(        min + ((j * (max - min)) / nClasses), 
99
                                                                                                                min + (((j + 1) * (max - min)) / nClasses));
100
                                hc.setValue(table[i][j]);
101
                                histogram[i][j] = hc;
102
                        }
103
                }
104
                return histogram;
105
        }
106
        
107
        /**
108
         * Obtiene el n?mero de bandas del histograma 
109
         * @return entero que representa el n?mero de bandas 
110
         */
111
        public int getNumBands() {
112
                if (table != null)
113
                        return table.length;
114
                return 0;
115
        }
116
        
117
        /**
118
         * Obtiene la longitud (n?mero de valores) de una banda determinada
119
         * @param band Banda o obtener la longitud
120
         * @return entero con la longitud de la banda
121
         * rangos de valores y DataclassList.
122
         */
123
        public int getBandLenght(int band) {
124
                if (table != null)
125
                        return table[band].length;
126
                return 0;
127
        }
128
        
129
        /**
130
         * Obtiene el n?mero de valores o clases del histograma
131
         * @return entero que representa el n?mero de valores o clases del histograma
132
         */
133
        public int getNumValues() {
134
                return nClasses;
135
        }
136
        
137
        /**
138
         * Asigna un histograma
139
         * @param hist histograma asignado
140
         */
141
        public void setHistogram(HistogramClass[][] hist){
142
                histogram = hist;
143
        }
144
                
145
        /**
146
         * Asigna un valor para una posici?n del histograma
147
         * @param band Valor del pixel o clase a asignar
148
         * @param px Valor del pixel
149
         * @param value Valor a asignar
150
         */
151
        public void setHistogramValue(int band, double px, long value) {
152
                int pos = (int) ((nClasses * (px - min))/(max-min));
153
                if (pos < 0) pos = 0;
154
                if (pos >= nClasses) pos = nClasses - 1;
155
                table[band][pos] = value;
156
        }
157
        
158
        /**
159
         * Asigna un valor para una posici?n del histograma segun la posicion en las
160
         * clases
161
         * @param band Valor del pixel o clase a asignar
162
         * @param pos Posicion dentro de la clase. Ejemplo 0..63
163
         * @param value Valor a asignar
164
         */
165
        public void setHistogramValueByPos(int band, int pos, long value) {
166
                if (pos < 0) pos = 0;
167
                if (pos >= nClasses) pos = nClasses - 1;
168
                table[band][pos] = value;
169
        }
170

    
171
        /**
172
         * Obtiene un valor del histograma
173
         * @param band N?mero de banda del valor a recuperar
174
         * @param px Pixel o valor de la clase del valor a recuperar
175
         * @return valor
176
         */
177
        public double getHistogramValue(int band, double px) {
178
                if (histogram == null) getHistogram();
179
                for (int i = 0; i < histogram[band].length; i++) {
180
                        if (((HistogramClass)histogram[band][i]).isIn(px))
181
                                return ((HistogramClass)histogram[band][i]).getValue();
182
                }                
183
                return 0;
184
        }
185
        
186
        /**
187
         * Obtiene un valor del histograma segun la posicion dentro de las clases
188
         * @param band N?mero de banda del valor a recuperar
189
         * @param px Pixel o valor de la clase del valor a recuperar
190
         * @return valor
191
         */
192
        public double getHistogramValueByPos(int band, int pos) {
193
                if (pos < 0) pos = 0;
194
                if (pos >= nClasses) 
195
                        pos = nClasses - 1;
196
                return table[band][pos];
197
        }
198
        
199
        /**
200
         * Incrementa un valor de una posici?n del histograma
201
         * @param band N?mero de banda
202
         * @param px Pixel o valor de la clase
203
         */
204
        public void incrementPxValue(int band, double px) {
205
                int pos = (int) ((nClasses * (px - min)) / (max - min));
206

    
207
                if (pos < 0) 
208
                        pos = 0;
209
                if (pos >= nClasses) 
210
                        pos = nClasses - 1;
211
                table[band][pos]++;
212
        }
213
        
214
        /**
215
         * Devuelve el histograma acumulado
216
         * @return
217
         */
218
        public HistogramClass[][] getAccumulatedHistogram() {
219
                if (histogram != null) {
220
                        HistogramClass[][] hist = new HistogramClass[histogram.length][histogram[0].length];
221
                        for (int iBand = 0; iBand < hist.length; iBand++) {
222
                                hist[iBand][0] = new HistogramClass(histogram[iBand][0].getMin(), histogram[iBand][0].getMax());
223
                                hist[iBand][0].setValue(histogram[iBand][0].getValue());
224
                                for (int j = 1; j < hist[iBand].length; j++) {
225
                                        hist[iBand][j] = new HistogramClass(histogram[iBand][j].getMin(), histogram[iBand][j].getMax());
226
                                        hist[iBand][j].setValue(hist[iBand][j - 1].getValue() + histogram[iBand][j].getValue());
227
                                }
228
                        }
229
                        return hist;
230
                }
231
                return null;
232
        }
233
        
234
        /**
235
         * Devuelve el histograma logaritmico
236
         * @return
237
         */
238
        public HistogramClass[][] getLogaritmicHistogram() {
239
                if (histogram != null) {
240
                        HistogramClass[][] hist = new HistogramClass[histogram.length][histogram[0].length];
241
                        double minim = Double.MAX_VALUE;
242
                        for (int iBand = 0; iBand < histogram.length; iBand++) {
243
                                for (int j = 0; j < histogram[iBand].length; j++) {
244
                                        if (minim > histogram[iBand][j].getValue())
245
                                                minim = histogram[iBand][j].getValue();
246
                                }
247
                        }
248
                        for (int iBand = 0; iBand < histogram.length; iBand++) {
249
                                for (int j = 0; j < histogram[iBand].length; j++) {
250
                                        hist[iBand][j] = new HistogramClass(histogram[iBand][j].getMin(), histogram[iBand][j].getMax());
251
                                        hist[iBand][j].setValue(java.lang.Math.log(histogram[iBand][j].getValue() - minim + 1.0));
252
                                }
253
                        }
254
                        return hist;
255
                }
256
                return null;
257

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

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

    
340
                // Contamos el n?mero de bandas para las cuales se calcula la estad?stica
341
                int bandCount = 0;
342
                for (int iBand = 0; iBand < bands.length; iBand++)
343
                        if (bands[iBand])
344
                                bandCount++;
345

    
346
                double[][] res = new double[5][];
347

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

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

    
367
                                        // Calculo del m?ximo
368
                                        if (histogram[iBand][i].getValue() != 0 && histogram[iBand][i].getMax() > max[showBandCounter])
369
                                                max[showBandCounter] = histogram[iBand][i].getMax();
370

    
371
                                        // Calculo del n?mero de pixeles
372
                                        nPixelsBand[showBandCounter] += histogram[iBand][i].getValue();
373

    
374
                                        average[showBandCounter] += histogram[iBand][i].getValue() * ((histogram[iBand][i].getMax() + histogram[iBand][i].getMin())/2);
375
                                }
376
                                // Calculo de la media
377
                                try {
378
                                        average[showBandCounter] /= nPixelsBand[showBandCounter];
379
                                } catch (ArithmeticException exc) {
380
                                        average[showBandCounter] = 0;
381
                                }
382

    
383
                                // Calculo de mediana
384
                                double stopPos = nPixelsBand[showBandCounter] / 2;
385
                                int aux = 0;
386
                                int i = beginPos;
387
                                for (i = beginPos; aux <= stopPos; i++) {
388
                                        try {
389
                                                aux += histogram[iBand][i].getValue();
390
                                        } catch (ArrayIndexOutOfBoundsException e) {
391
                                                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);
392
                                        }
393
                                }
394
                                middle[showBandCounter] = (histogram[iBand][i - 1].getMax() + histogram[iBand][i - 1].getMin()) / 2;
395

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