Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libRaster / src / org / gvsig / raster / datastruct / Histogram.java @ 31829

History | View | Annotate | Download (16.1 KB)

1 12383 nacho
/* 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 27016 csanchez
import org.slf4j.Logger;
22
import org.slf4j.LoggerFactory;
23 20836 bsanchez
import org.gvsig.raster.RasterLibrary;
24 21543 bsanchez
import org.gvsig.raster.dataset.IBuffer;
25 12383 nacho
/**
26
 * Representa un histograma.
27 21306 bsanchez
 *
28 12383 nacho
 * @version 27/03/2007
29
 * @author Nacho Brodin (nachobrodin@gmail.com)
30
 */
31
public class Histogram {
32
        /**
33
         * Variable que representa el histograma. La primera dimensi?n es el n?mero de
34
         * bandas y la segunda un array de clases. En el caso b?sico de un RGB una clase tendr? el
35
         * valor m?nimo igual al m?ximo.
36
         */
37 20836 bsanchez
        private HistogramClass[][] histogram   = null;
38
39
        private long[][]           table       = null;
40 21306 bsanchez
        private double[]           min         = null;
41
        private double[]           max         = null;
42 20836 bsanchez
        private double             noDataValue = RasterLibrary.defaultNoDataValue;
43 21543 bsanchez
        private int                dataType    = IBuffer.TYPE_UNDEFINED;
44 12383 nacho
45 21306 bsanchez
        private int                nClasses    = 0;
46
47 12383 nacho
        /**
48
         * Constructor
49 13932 nacho
         * @param nBands N?mero de bandas
50
         * @param nClasses N?mero de clases en que hacemos la divisi?n
51
         * @param min Valor m?nimo del histograma
52
         * @param max Valor m?ximo del histograma
53 12383 nacho
         */
54 21306 bsanchez
        public Histogram(int nBands, int nClasses, double[] min, double[] max) {
55 21543 bsanchez
                if ((nBands != min.length) || (nBands != max.length)) {
56
                        System.out.println("No tiene las mismas bandas");
57
                }
58
                constructorHistogramImpl(min, max, nClasses);
59
        }
60
61
        private void constructorHistogramImpl(double[] min, double[] max, int nClasses) {
62
                table = new long[min.length][nClasses];
63 21306 bsanchez
                for (int i = 0; i < table.length; i++)
64 12383 nacho
                        for (int j = 0; j < table[0].length; j++)
65
                                table[i][j] = 0;
66 22098 bsanchez
                this.min = (double[]) min.clone();
67
                this.max = (double[]) max.clone();
68 21306 bsanchez
69
                this.nClasses = getNumValues();
70 12383 nacho
        }
71 21543 bsanchez
72
        /**
73
         * Constructor
74
         * @param nBands N?mero de bandas
75
         * @param nClasses N?mero de clases en que hacemos la divisi?n
76
         * @param min Valor m?nimo del histograma
77
         * @param max Valor m?ximo del histograma
78
         */
79
        public Histogram(int nBands, double[] min, double[] max, int dataType) {
80
                int numberClasses;
81
                this.dataType = dataType;
82 22098 bsanchez
                this.min = (double[]) min.clone();
83
                this.max = (double[]) max.clone();
84 21543 bsanchez
                if (dataType == IBuffer.TYPE_BYTE) {
85
                        numberClasses = RasterLibrary.defaultNumberOfColors;
86
                        boolean unsigned = false;
87
                        for (int i = 0; i < this.min.length; i++)
88
                                if (this.min[i] < 0)
89
                                        unsigned = true;
90
                        for (int i = 0; i < this.min.length; i++) {
91
                                if (unsigned) {
92
                                        this.min[i] = -128;
93
                                        this.max[i] = 127;
94
                                } else {
95
                                        this.min[i] = 0;
96
                                        this.max[i] = 255;
97
                                }
98
                        }
99
                } else {
100
                        numberClasses = RasterLibrary.defaultNumberOfClasses;
101
                }
102
103 21576 bsanchez
                constructorHistogramImpl(this.min, this.max, numberClasses);
104 21543 bsanchez
        }
105 12383 nacho
106
        /**
107 13590 nacho
         * Realiza la uni?n entre el histograma actual y el pasado
108
         * por par?metro.
109
         * @param hist
110 21306 bsanchez
         * @deprecated Con los nuevos maximos y minimos por banda, habria que estudiar
111
         * la viabilidad de este metodo y si se comporta correctamente
112 13590 nacho
         */
113
        public boolean union(Histogram hist) {
114 21306 bsanchez
                long[][] auxTable = hist.getTable();
115
116
                if (auxTable.length != table.length)
117 13590 nacho
                        return false;
118 21306 bsanchez
119
                if (auxTable.length == 0)
120
                        return true;
121
122
                if (auxTable[0].length != table[0].length)
123
                        return false;
124
125
                for (int i = 0; i < table.length; i++)
126
                        for (int j = 0; j < table[i].length; j++)
127
                                table[i][j] += auxTable[i][j];
128
129 13590 nacho
                return true;
130
        }
131 21306 bsanchez
132 13590 nacho
        /**
133 12383 nacho
         * Asigna la tabla
134
         * @param t
135
         */
136
        public void setTable(long[][] t) {
137 21306 bsanchez
                table = new long[t.length][t[0].length];
138
                for (int i = 0; i < table.length; i++)
139
                        for (int j = 0; j < table[0].length; j++)
140
                                table[i][j] = t[i][j];
141
142
                this.nClasses = getNumValues();
143 12383 nacho
        }
144 14437 bsanchez
145
        /**
146
         * Devuelve el minimo valor del histograma
147
         * @return
148
         */
149 21306 bsanchez
        public double getMin(int band) {
150
                return min[band];
151 14437 bsanchez
        }
152
153
        /**
154
         * Devuelve el maximo valor del histograma
155
         * @return
156
         */
157 21306 bsanchez
        public double getMax(int band) {
158
                return max[band];
159 14437 bsanchez
        }
160 21306 bsanchez
161 12383 nacho
        /**
162 21471 bsanchez
         * Devuelve los minimos valores del histograma
163
         * @return
164
         */
165
        public double[] getMinims() {
166
                return min;
167
        }
168
169
        /**
170
         * Devuelve los maximos valores del histograma
171
         * @return
172
         */
173
        public double[] getMaxims() {
174
                return max;
175
        }
176
177
        /**
178 21306 bsanchez
         * Devuelve si un histograma esta en un rango RGB aceptable
179
         * @return
180
         */
181
        public boolean isInRangeRGB() {
182 21543 bsanchez
                if (dataType == IBuffer.TYPE_BYTE)
183
                        return true;
184 21306 bsanchez
                return true;
185
        }
186
187
        /**
188 12383 nacho
         * Obtiene el histograma sin modificar
189
         * @return array bidimensional donde el primer elemento es el valor del pixel
190
         * o rango y el segundo el n?mero de elementos que aparecen.
191
         */
192
        public HistogramClass[][] getHistogram() {
193 21306 bsanchez
                if (nClasses == 0)
194 12383 nacho
                        return null;
195
196
                histogram = new HistogramClass[table.length][nClasses];
197 19453 nbrodin
198 12383 nacho
                for (int i = 0; i < table.length; i++) {
199 21306 bsanchez
                        for (int j = 0; j < table[i].length; j++) {
200 21543 bsanchez
                                HistogramClass hc = new HistogramClass(        min[i] + ((j * (max[i] - min[i])) / (nClasses - 1)),
201
                                                                                                                min[i] + (((j + 1) * (max[i] - min[i])) / (nClasses - 1)));
202 12383 nacho
                                hc.setValue(table[i][j]);
203
                                histogram[i][j] = hc;
204
                        }
205
                }
206
                return histogram;
207
        }
208
209
        /**
210
         * Obtiene el n?mero de bandas del histograma
211
         * @return entero que representa el n?mero de bandas
212
         */
213
        public int getNumBands() {
214
                if (table != null)
215
                        return table.length;
216
                return 0;
217
        }
218
219
        /**
220 21543 bsanchez
         * Obtiene el tipo de datos del histograma original
221
         * @return
222
         */
223
        public int getDataType() {
224
                return dataType;
225
        }
226
227
        /**
228 12383 nacho
         * Obtiene la longitud (n?mero de valores) de una banda determinada
229
         * @param band Banda o obtener la longitud
230
         * @return entero con la longitud de la banda
231
         * rangos de valores y DataclassList.
232
         */
233
        public int getBandLenght(int band) {
234
                if (table != null)
235
                        return table[band].length;
236
                return 0;
237
        }
238
239
        /**
240
         * Obtiene el n?mero de valores o clases del histograma
241
         * @return entero que representa el n?mero de valores o clases del histograma
242
         */
243
        public int getNumValues() {
244 21306 bsanchez
                if (table == null)
245
                        return 0;
246
247
                if (table.length == 0)
248
                        return 0;
249
250
                return table[0].length;
251 12383 nacho
        }
252
253
        /**
254
         * Asigna un histograma
255
         * @param hist histograma asignado
256
         */
257
        public void setHistogram(HistogramClass[][] hist){
258
                histogram = hist;
259
        }
260
261
        /**
262
         * Asigna un valor para una posici?n del histograma
263
         * @param band Valor del pixel o clase a asignar
264
         * @param px Valor del pixel
265
         * @param value Valor a asignar
266
         */
267
        public void setHistogramValue(int band, double px, long value) {
268 21543 bsanchez
                int pos = (int) (((nClasses - 1) * (px - min[band])) / (max[band] - min[band]));
269 21306 bsanchez
                if (pos < 0)
270
                        pos = 0;
271
                if (pos >= nClasses)
272
                        pos = nClasses - 1;
273 12383 nacho
                table[band][pos] = value;
274
        }
275
276
        /**
277
         * Asigna un valor para una posici?n del histograma segun la posicion en las
278
         * clases
279
         * @param band Valor del pixel o clase a asignar
280
         * @param pos Posicion dentro de la clase. Ejemplo 0..63
281
         * @param value Valor a asignar
282
         */
283
        public void setHistogramValueByPos(int band, int pos, long value) {
284 21306 bsanchez
                if (pos < 0)
285
                        pos = 0;
286
                if (pos >= nClasses)
287
                        pos = nClasses - 1;
288 12383 nacho
                table[band][pos] = value;
289
        }
290
291
        /**
292
         * Obtiene un valor del histograma
293
         * @param band N?mero de banda del valor a recuperar
294
         * @param px Pixel o valor de la clase del valor a recuperar
295
         * @return valor
296
         */
297
        public double getHistogramValue(int band, double px) {
298 21306 bsanchez
                if (histogram == null)
299
                        getHistogram();
300
301
                for (int i = 0; i < histogram[band].length; i++)
302
                        if (((HistogramClass) histogram[band][i]).isIn(px))
303
                                return ((HistogramClass) histogram[band][i]).getValue();
304
305 12383 nacho
                return 0;
306
        }
307
308
        /**
309
         * Obtiene un valor del histograma segun la posicion dentro de las clases
310
         * @param band N?mero de banda del valor a recuperar
311
         * @param px Pixel o valor de la clase del valor a recuperar
312
         * @return valor
313
         */
314
        public double getHistogramValueByPos(int band, int pos) {
315 21306 bsanchez
                if (pos < 0)
316
                        pos = 0;
317
318
                if (pos >= nClasses)
319 12383 nacho
                        pos = nClasses - 1;
320 21306 bsanchez
321 12383 nacho
                return table[band][pos];
322
        }
323
324
        /**
325
         * Incrementa un valor de una posici?n del histograma
326
         * @param band N?mero de banda
327
         * @param px Pixel o valor de la clase
328
         */
329
        public void incrementPxValue(int band, double px) {
330 19138 bsanchez
                if (Double.isNaN(px))
331
                        return;
332
333 20836 bsanchez
                if (px == noDataValue)
334
                        return;
335
336 21543 bsanchez
                int pos = (int) (((nClasses - 1) * (px - min[band])) / (max[band] - min[band]));
337 13943 nacho
338 21306 bsanchez
                if (pos < 0)
339 12383 nacho
                        pos = 0;
340 21306 bsanchez
341
                if (pos >= nClasses)
342 12383 nacho
                        pos = nClasses - 1;
343 21306 bsanchez
344 12383 nacho
                table[band][pos]++;
345
        }
346
347
        /**
348 20836 bsanchez
         * Calculo de estad?sticas a partir de un histograma. El resultado de la funci?n es un array
349
         * bidimensional donde el primer ?ndice inndica la estadistica y el segundo el n?mero de banda.
350
         *
351
         * <UL>
352
         * <LI>m?nimo</LI>
353
         * <LI>m?ximo</LI>
354
         * <LI>media</LI>
355
         * <LI>mediana</LI>
356
         * <LI>N?mero de pixels</LI>
357
         * </UL>
358
         * @param histogram
359
         * @param bandas solicitadas. Cada elemento del vector representa una banda. Si est? a true se calcula la
360
         * estadistica para esa banda y si est? a false no se calcular?.
361
         * @return
362
         */
363
        public double[][] getBasicStats(boolean[] bands) {
364
                if (histogram == null)
365
                        return null;
366
                return getBasicStats(0, histogram[0].length - 1, bands);
367
        }
368 12383 nacho
369 20836 bsanchez
        /**
370
         * Calculo de estad?sticas a partir de un histograma. El resultado de la funci?n es un array
371
         * bidimensional donde el primer ?ndice inndica la estadistica y el segundo el n?mero de banda.
372
         *
373
         * <UL>
374
         * <LI>m?nimo</LI>
375
         * <LI>m?ximo</LI>
376
         * <LI>media</LI>
377
         * <LI>mediana</LI>
378
         * <LI>N?mero de pixels</LI>
379
         * </UL>
380
         * @param histogram
381
         * @param beginPos Posici?n de inicio del histograma para contabilizar estadisticas
382
         * @param endPos Posici?n de fin del histograma para contabilizar estadisticas
383
         * @param bandas solicitadas. Cada elemento del vector representa una banda. Si est? a true se calcula la
384
         * estadistica para esa banda y si est? a false no se calcular?.
385
         * @return
386
         */
387
        public double[][] getBasicStats(double beginPos2, double endPos2, boolean[] bands) {
388 13646 bsanchez
                if (histogram == null)
389
                        getHistogram();
390
391
                int beginPos = (int) ((beginPos2 * (nClasses - 1)) / 100.0);
392
                int endPos = (int) ((endPos2 * (nClasses - 1)) / 100.0);
393
394
                // Contamos el n?mero de bandas para las cuales se calcula la estad?stica
395
                int bandCount = 0;
396
                for (int iBand = 0; iBand < bands.length; iBand++)
397
                        if (bands[iBand])
398
                                bandCount++;
399
400
                double[][] res = new double[5][];
401
402
                double[] min = new double[bandCount];// M?nimo
403
                double[] max = new double[bandCount];// M?ximo
404
                for (int iBand = 0; iBand < bandCount; iBand++) {
405
                        max[iBand] = Double.NEGATIVE_INFINITY;
406
                        min[iBand] = Double.POSITIVE_INFINITY;
407
                }
408
                double[] average = new double[bandCount]; // Valor de pixel medio (Media)
409
                double[] middle = new double[bandCount]; // Mediana
410
                double[] nPixelsBand = new double[bandCount];// N?mero de pixels por banda
411
412
                int showBandCounter = 0; // Contador de bandas de las que hay calcular la
413 20836 bsanchez
                                                                                                                        // estadistica
414 13646 bsanchez
                for (int iBand = 0; iBand < histogram.length; iBand++) {
415
                        if (bands[iBand]) {
416
                                for (int i = beginPos; i <= endPos; i++) {
417
                                        // Calculo del m?nimo
418
                                        if (histogram[iBand][i].getValue() != 0 && histogram[iBand][i].getMin() < min[showBandCounter])
419
                                                min[showBandCounter] = histogram[iBand][i].getMin();
420
421
                                        // Calculo del m?ximo
422
                                        if (histogram[iBand][i].getValue() != 0 && histogram[iBand][i].getMax() > max[showBandCounter])
423 21543 bsanchez
                                                max[showBandCounter] = histogram[iBand][i].getMin();
424 13646 bsanchez
425
                                        // Calculo del n?mero de pixeles
426
                                        nPixelsBand[showBandCounter] += histogram[iBand][i].getValue();
427
428
                                        average[showBandCounter] += histogram[iBand][i].getValue() * ((histogram[iBand][i].getMax() + histogram[iBand][i].getMin())/2);
429
                                }
430
                                // Calculo de la media
431
                                try {
432
                                        average[showBandCounter] /= nPixelsBand[showBandCounter];
433
                                } catch (ArithmeticException exc) {
434
                                        average[showBandCounter] = 0;
435
                                }
436
437
                                // Calculo de mediana
438
                                double stopPos = nPixelsBand[showBandCounter] / 2;
439
                                int aux = 0;
440
                                int i = beginPos;
441
                                for (i = beginPos; aux <= stopPos; i++) {
442 14437 bsanchez
                                        if (i >= histogram[iBand].length)
443
                                                break;
444 13925 nacho
                                        try {
445
                                                aux += histogram[iBand][i].getValue();
446
                                        } catch (ArrayIndexOutOfBoundsException e) {
447 27016 csanchez
                                                LoggerFactory.getLogger(getClass().getName()).debug("Acceso a un valor de histogram (Banda: " + iBand + " Posici?n: " + i + ") fuera de l?mites. (NBandas: " + histogram.length + " Valores:" + histogram[iBand].length + ")", e);
448 13925 nacho
                                        }
449 13646 bsanchez
                                }
450
                                middle[showBandCounter] = (histogram[iBand][i - 1].getMax() + histogram[iBand][i - 1].getMin()) / 2;
451
452
                                showBandCounter++;
453 12383 nacho
                        }
454 13646 bsanchez
                }
455 20836 bsanchez
456
                res[0] = min;
457
                res[1] = max;
458
                res[2] = average;
459
                res[3] = middle;
460
                res[4] = nPixelsBand;
461
                return res;
462
        }
463
464
        /**
465
         * Obtiene la tabla de valores
466
         * @return
467
         */
468
        public long[][] getTable() {
469
                return table;
470
        }
471
472
        /**
473
         * Obtiene la tabla de valores normalizada. Divide todos los elementos por el n?mero de
474
         * pixeles total.
475
         * @return tabla de valores normalizada
476
         */
477
        public static double[][] convertToNormalizeHistogram(long[][] tableToConvert) {
478
                long[] nValues = new long[tableToConvert.length];
479
                for (int i = 0; i < tableToConvert.length; i++)
480
                        for (int j = 0; j < tableToConvert[i].length; j++)
481
                                nValues[i] += tableToConvert[i][j];
482
483
                double[][] res = new double[tableToConvert.length][tableToConvert[0].length];
484
                for (int i = 0; i < tableToConvert.length; i++)
485
                        for (int j = 0; j < tableToConvert[i].length; j++)
486
                                res[i][j] = (double)((double)tableToConvert[i][j] / (double)nValues[i]);
487 19453 nbrodin
488 20836 bsanchez
                return res;
489
        }
490
491
        /**
492
         * Obtiene la tabla de valores normalizada y acumulada. Divide todos los elementos por el n?mero de
493
         * pixeles total.
494
         * @return tabla de valores normalizada
495
         */
496
        public static double[][] convertTableToNormalizeAccumulate(long[][] tableToConvert) {
497
                double[][] res = convertToNormalizeHistogram(tableToConvert);
498
                for (int i = 0; i < tableToConvert.length; i++)
499
                        for (int j = 0; j < tableToConvert[i].length; j++)
500
                                if(j > 0)
501
                                        res[i][j] += res[i][j - 1];
502 19453 nbrodin
503 20836 bsanchez
                return res;
504
        }
505
506
        /**
507
         * Obtiene el histograma de la imagen negativa.
508
         * @return long[][]
509
         */
510
        public long[][] getNegativeTable() {
511
                long[][] tableNeg = new long[table.length][table[0].length];
512
                for (int i = 0; i < tableNeg.length; i++)
513
                        for (int j = 0; j < tableNeg[i].length; j++)
514
                                tableNeg[i][table[i].length - j - 1] = table[i][j];
515
                return tableNeg;
516
        }
517 19453 nbrodin
518 20836 bsanchez
        /**
519
         * Convierte un histograma al rango de valores de RGB, en pocas palabras
520
         * aplica una operacion 0xff a cada pixel para quitar los numeros negativos
521
         * y desplazarlos a su rango visual.
522
         * @param histogram
523
         */
524
        public static Histogram convertHistogramToRGB(Histogram histogram) {
525 20454 bsanchez
                if (histogram == null)
526 21306 bsanchez
                        return null;
527
528 21543 bsanchez
                if (histogram.dataType != IBuffer.TYPE_BYTE)
529 20836 bsanchez
                        return histogram;
530 21306 bsanchez
531
                double min = histogram.getMin(0);
532
                double max = histogram.getMax(0);
533 19453 nbrodin
534 20836 bsanchez
                long table2[][] = histogram.getTable();
535 19453 nbrodin
536 20836 bsanchez
                long newTable[][] = new long[table2.length][table2[0].length];
537 19453 nbrodin
538 20836 bsanchez
                // Ponemos a cero todos los valores
539
                for (int i = 0; i < table2.length; i++)
540
                        for (int j = 0; j < table2[i].length; j++)
541
                                newTable[i][j] = 0;
542 19453 nbrodin
543 20836 bsanchez
                // Sumamos en la posicion calculada nueva el valor correspondiente
544
                for (int i = 0; i < table2.length; i++) {
545
                        for (int j = 0; j < table2[i].length; j++) {
546
                                double val = ((j * (max - min)) / 255) + min;
547
                                int pos = ((int) val) & 0xff;
548
                                if (pos < 0)
549
                                        pos = 0;
550 21543 bsanchez
                                if (pos >= newTable[i].length)
551
                                        pos = newTable[i].length - 1;
552 19453 nbrodin
553 20836 bsanchez
                                newTable[i][pos] += table2[i][j];
554
                        }
555
                }
556 19453 nbrodin
557 21306 bsanchez
                double mins[] = new double[histogram.getNumBands()];
558
                double maxs[] = new double[histogram.getNumBands()];
559
560
                for (int i = 0; i < mins.length; i++) {
561
                        mins[i] = 0;
562
                        maxs[i] = 255;
563
                }
564 19453 nbrodin
565 21543 bsanchez
                Histogram histogramNew = new Histogram(histogram.getNumBands(), mins, maxs, IBuffer.TYPE_BYTE);
566 21306 bsanchez
567 20836 bsanchez
                histogramNew.setTable(newTable);
568 19453 nbrodin
569 20836 bsanchez
                return histogramNew;
570
        }
571
572
        /**
573
         * @param noDataValue the noDataValue to set
574
         */
575
        public void setNoDataValue(double noDataValue) {
576
                this.noDataValue = noDataValue;
577
        }
578 12383 nacho
}