Statistics
| Revision:

gvsig-raster / org.gvsig.raster / trunk / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.impl / src / main / java / org / gvsig / raster / impl / datastruct / BufferHistogramImpl.java @ 1676

History | View | Annotate | Download (16.8 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.raster.impl.datastruct;
23

    
24
import org.gvsig.fmap.dal.coverage.RasterLibrary;
25
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
26
import org.gvsig.fmap.dal.coverage.datastruct.BufferHistogram;
27
import org.gvsig.fmap.dal.coverage.datastruct.HistogramClass;
28
import org.gvsig.fmap.dal.coverage.datastruct.NoData;
29
import org.slf4j.LoggerFactory;
30
/**
31
 * Representa un histograma.
32
 * 
33
 * @version 27/03/2007
34
 * @author Nacho Brodin (nachobrodin@gmail.com)
35
 */
36
public class BufferHistogramImpl implements BufferHistogram {
37
        /**
38
         * Variable que representa el histograma. La primera dimensi?n es el n?mero de 
39
         * bandas y la segunda un array de clases. En el caso b?sico de un RGB una clase tendr? el
40
         * valor m?nimo igual al m?ximo.
41
         */
42
        private HistogramClass[][] histogram   = null;
43

    
44
        private long[][]           table       = null;
45
        private double[]           min         = null;
46
        private double[]           max         = null;
47
        private NoData             noDataValue = null;
48
        private int                dataType    = Buffer.TYPE_UNDEFINED;
49
        
50
        private int                nClasses    = 0;
51

    
52
        /**
53
         * Constructor
54
         * @param nBands N?mero de bandas
55
         * @param nClasses N?mero de clases en que hacemos la divisi?n
56
         * @param min Valor m?nimo del histograma
57
         * @param max Valor m?ximo del histograma
58
         */
59
        public BufferHistogramImpl(int nBands, int nClasses, double[] min, double[] max) {
60
                if ((nBands != min.length) || (nBands != max.length)) {
61
                        System.out.println("No tiene las mismas bandas");
62
                }
63
                constructorHistogramImpl(min, max, nClasses);
64
        }
65
        
66
        private void constructorHistogramImpl(double[] min, double[] max, int nClasses) {
67
                table = new long[min.length][nClasses];
68
                for (int i = 0; i < table.length; i++)
69
                        for (int j = 0; j < table[0].length; j++)
70
                                table[i][j] = 0;
71
                this.min = (double[]) min.clone();
72
                this.max = (double[]) max.clone();
73

    
74
                this.nClasses = getNumValues();
75
        }
76

    
77
        /**
78
         * Constructor
79
         * @param nBands N?mero de bandas
80
         * @param nClasses N?mero de clases en que hacemos la divisi?n
81
         * @param min Valor m?nimo del histograma
82
         * @param max Valor m?ximo del histograma
83
         */
84
        public BufferHistogramImpl(int nBands, double[] min, double[] max, int dataType) {
85
                int numberClasses;
86
                this.dataType = dataType;
87
                this.min = (double[]) min.clone();
88
                this.max = (double[]) max.clone();
89
                if (dataType == Buffer.TYPE_BYTE) {
90
                        numberClasses = RasterLibrary.defaultNumberOfColors;
91
                        boolean unsigned = false;
92
                        for (int i = 0; i < this.min.length; i++)
93
                                if (this.min[i] < 0)
94
                                        unsigned = true;
95
                        for (int i = 0; i < this.min.length; i++) {
96
                                if (unsigned) {
97
                                        this.min[i] = -128;
98
                                        this.max[i] = 127;
99
                                } else {
100
                                        this.min[i] = 0;
101
                                        this.max[i] = 255;
102
                                }
103
                        }
104
                } else {
105
                        numberClasses = RasterLibrary.defaultNumberOfClasses;
106
                }
107
                
108
                constructorHistogramImpl(this.min, this.max, numberClasses);
109
        }
110
        
111
        /**
112
         * Realiza la uni?n entre el histograma actual y el pasado 
113
         * por par?metro.
114
         * @param hist
115
         */
116
        public boolean union(BufferHistogram hist) {
117
                long[][] auxTable = hist.getTable();
118

    
119
                if (auxTable.length != table.length)
120
                        return false;
121

    
122
                if (auxTable.length == 0)
123
                        return true;
124

    
125
                if (auxTable[0].length != table[0].length)
126
                        return false;
127

    
128
                for (int i = 0; i < table.length; i++)
129
                        for (int j = 0; j < table[i].length; j++)
130
                                table[i][j] += auxTable[i][j];
131

    
132
                return true;
133
        }
134

    
135
        /**
136
         * Asigna la tabla
137
         * @param t
138
         */
139
        public void setTable(long[][] t) {
140
                table = new long[t.length][t[0].length];
141
                for (int i = 0; i < table.length; i++)
142
                        for (int j = 0; j < table[0].length; j++)
143
                                table[i][j] = t[i][j];
144
                
145
                this.nClasses = getNumValues();
146
        }
147
        
148
        /**
149
         * Devuelve el minimo valor del histograma
150
         * @return
151
         */
152
        public double getMin(int band) {
153
                return min[band];
154
        }
155

    
156
        /**
157
         * Devuelve el maximo valor del histograma
158
         * @return
159
         */
160
        public double getMax(int band) {
161
                return max[band];
162
        }
163

    
164
        /**
165
         * Devuelve los minimos valores del histograma
166
         * @return
167
         */
168
        public double[] getMinims() {
169
                return min;
170
        }
171

    
172
        /**
173
         * Devuelve los maximos valores del histograma
174
         * @return
175
         */
176
        public double[] getMaxims() {
177
                return max;
178
        }
179

    
180
        /**
181
         * Devuelve si un histograma esta en un rango RGB aceptable
182
         * @return
183
         */
184
        public boolean isInRangeRGB() {
185
                if (dataType == Buffer.TYPE_BYTE)
186
                        return true;
187
                return true;
188
        }
189

    
190
        /**
191
         * Obtiene el histograma sin modificar
192
         * @return array bidimensional donde el primer elemento es el valor del pixel
193
         * o rango y el segundo el n?mero de elementos que aparecen.
194
         */
195
        public HistogramClass[][] getHistogram() {
196
                if (nClasses == 0)
197
                        return null;
198
                
199
                histogram = new HistogramClass[table.length][nClasses];
200
                                
201
                for (int i = 0; i < table.length; i++) {
202
                        for (int j = 0; j < table[i].length; j++) {
203
                                HistogramClass hc = new HistogramClassImpl(        min[i] + ((j * (max[i] - min[i])) / (nClasses - 1)), 
204
                                                                                                                min[i] + (((j + 1) * (max[i] - min[i])) / (nClasses - 1)));
205
                                hc.setValue(table[i][j]);
206
                                histogram[i][j] = hc;
207
                        }
208
                }
209
                return histogram;
210
        }
211
        
212
        /**
213
         * Obtiene el n?mero de bandas del histograma 
214
         * @return entero que representa el n?mero de bandas 
215
         */
216
        public int getNumBands() {
217
                if (table != null)
218
                        return table.length;
219
                return 0;
220
        }
221
        
222
        /**
223
         * Obtiene el tipo de datos del histograma original
224
         * @return
225
         */
226
        public int getDataType() {
227
                return dataType;
228
        }
229
        
230
        /**
231
         * Obtiene la longitud (n?mero de valores) de una banda determinada
232
         * @param band Banda o obtener la longitud
233
         * @return entero con la longitud de la banda
234
         * rangos de valores y DataclassList.
235
         */
236
        public int getBandLenght(int band) {
237
                if (table != null)
238
                        return table[band].length;
239
                return 0;
240
        }
241
        
242
        /**
243
         * Obtiene el n?mero de valores o clases del histograma
244
         * @return entero que representa el n?mero de valores o clases del histograma
245
         */
246
        public int getNumValues() {
247
                if (table == null)
248
                        return 0;
249

    
250
                if (table.length == 0)
251
                        return 0;
252
                
253
                return table[0].length;
254
        }
255
        
256
        /**
257
         * Asigna un histograma
258
         * @param hist histograma asignado
259
         */
260
        public void setHistogram(HistogramClass[][] hist){
261
                histogram = hist;
262
        }
263
                
264
        /**
265
         * Asigna un valor para una posici?n del histograma
266
         * @param band Valor del pixel o clase a asignar
267
         * @param px Valor del pixel
268
         * @param value Valor a asignar
269
         */
270
        public void setHistogramValue(int band, double px, long value) {
271
                int pos = (int) (((nClasses - 1) * (px - min[band])) / (max[band] - min[band]));
272
                if (pos < 0)
273
                        pos = 0;
274
                if (pos >= nClasses)
275
                        pos = nClasses - 1;
276
                table[band][pos] = value;
277
        }
278
        
279
        /**
280
         * Asigna un valor para una posici?n del histograma segun la posicion en las
281
         * clases
282
         * @param band Valor del pixel o clase a asignar
283
         * @param pos Posicion dentro de la clase. Ejemplo 0..63
284
         * @param value Valor a asignar
285
         */
286
        public void setHistogramValueByPos(int band, int pos, long value) {
287
                if (pos < 0)
288
                        pos = 0;
289
                if (pos >= nClasses)
290
                        pos = nClasses - 1;
291
                table[band][pos] = value;
292
        }
293

    
294
        /**
295
         * Obtiene un valor del histograma
296
         * @param band N?mero de banda del valor a recuperar
297
         * @param px Pixel o valor de la clase del valor a recuperar
298
         * @return valor
299
         */
300
        public double getHistogramValue(int band, double px) {
301
                if (histogram == null)
302
                        getHistogram();
303

    
304
                for (int i = 0; i < histogram[band].length; i++)
305
                        if (((HistogramClass) histogram[band][i]).isIn(px))
306
                                return ((HistogramClass) histogram[band][i]).getValue();
307

    
308
                return 0;
309
        }
310
        
311
        /**
312
         * Obtiene un valor del histograma segun la posicion dentro de las clases
313
         * @param band N?mero de banda del valor a recuperar
314
         * @param px Pixel o valor de la clase del valor a recuperar
315
         * @return valor
316
         */
317
        public double getHistogramValueByPos(int band, int pos) {
318
                if (pos < 0)
319
                        pos = 0;
320

    
321
                if (pos >= nClasses)
322
                        pos = nClasses - 1;
323

    
324
                return table[band][pos];
325
        }
326
        
327
        /**
328
         * Incrementa un valor de una posici?n del histograma
329
         * @param band N?mero de banda
330
         * @param px Pixel o valor de la clase
331
         */
332
        public void incrementPxValue(int band, double px) {
333
                if (Double.isNaN(px))
334
                        return;
335

    
336
                if (noDataValue != null && noDataValue.isDefined()) {
337
                        switch (dataType) {
338
                        case Buffer.TYPE_BYTE:
339
                                if(((byte)px) == noDataValue.getValue().byteValue())
340
                                                return;
341
                                break;
342
                        case Buffer.TYPE_SHORT:
343
                                if(((short)px) == noDataValue.getValue().shortValue())
344
                                        return;
345
                                break;
346
                        case Buffer.TYPE_INT:
347
                                if(((int)px) == noDataValue.getValue().intValue())
348
                                        return;
349
                                break;
350
                        case Buffer.TYPE_FLOAT:
351
                                if(((float)px) == noDataValue.getValue().floatValue())
352
                                        return;
353
                                break;
354
                        case Buffer.TYPE_DOUBLE:
355
                                if(((double)px) == noDataValue.getValue().doubleValue())
356
                                        return;
357
                                break;
358
                        }
359
                }
360
                        
361

    
362
                int pos = (int) (((nClasses - 1) * (px - min[band])) / (max[band] - min[band]));
363

    
364
                if (pos < 0)
365
                        pos = 0;
366

    
367
                if (pos >= nClasses)
368
                        pos = nClasses - 1;
369

    
370
                table[band][pos]++;
371
        }
372

    
373
        /**
374
         * Calculo de estad?sticas a partir de un histograma. El resultado de la funci?n es un array
375
         * bidimensional donde el primer ?ndice inndica la estadistica y el segundo el n?mero de banda.
376
         * 
377
         * <UL>
378
         * <LI>m?nimo</LI>
379
         * <LI>m?ximo</LI>
380
         * <LI>media</LI>
381
         * <LI>mediana</LI>
382
         * <LI>N?mero de pixels</LI>
383
         * </UL>
384
         * @param histogram
385
         * @param bandas solicitadas. Cada elemento del vector representa una banda. Si est? a true se calcula la 
386
         * estadistica para esa banda y si est? a false no se calcular?.
387
         * @return
388
         */
389
        public double[][] getBasicStats(boolean[] bands) {
390
                if (histogram == null)
391
                        return null;
392
                return getBasicStats(0, histogram[0].length - 1, bands);
393
        }
394

    
395
        /**
396
         * Calculo de estad?sticas a partir de un histograma. El resultado de la funci?n es un array
397
         * bidimensional donde el primer ?ndice inndica la estadistica y el segundo el n?mero de banda.
398
         * 
399
         * <UL>
400
         * <LI>m?nimo</LI>
401
         * <LI>m?ximo</LI>
402
         * <LI>media</LI>
403
         * <LI>mediana</LI>
404
         * <LI>N?mero de pixels</LI>
405
         * </UL>
406
         * @param histogram
407
         * @param beginPos Posici?n de inicio del histograma para contabilizar estadisticas
408
         * @param endPos Posici?n de fin del histograma para contabilizar estadisticas
409
         * @param bandas solicitadas. Cada elemento del vector representa una banda. Si est? a true se calcula la 
410
         * estadistica para esa banda y si est? a false no se calcular?.
411
         * @return
412
         */
413
        public double[][] getBasicStats(double beginPos2, double endPos2, boolean[] bands) {
414
                if (histogram == null)
415
                        getHistogram();
416
                
417
                int beginPos = (int) ((beginPos2 * (nClasses - 1)) / 100.0);
418
                int endPos = (int) ((endPos2 * (nClasses - 1)) / 100.0);
419

    
420
                // Contamos el n?mero de bandas para las cuales se calcula la estad?stica
421
                int bandCount = 0;
422
                for (int iBand = 0; iBand < bands.length; iBand++)
423
                        if (bands[iBand])
424
                                bandCount++;
425

    
426
                double[][] res = new double[5][];
427

    
428
                double[] average = new double[bandCount]; // Valor de pixel medio (Media)
429
                double[] middle = new double[bandCount]; // Mediana
430
                double[] nPixelsBand = new double[bandCount];// N?mero de pixels por banda
431

    
432
                int showBandCounter = 0; // Contador de bandas de las que hay calcular la
433
                                                                                                                        // estadistica
434
                for (int iBand = 0; iBand < histogram.length; iBand++) {
435
                        if (bands[iBand]) {
436
                                for (int i = beginPos; i <= endPos; i++) {
437
                                        // Calculo del n?mero de pixeles
438
                                        nPixelsBand[showBandCounter] += histogram[iBand][i].getValue();
439
                                        average[showBandCounter] += histogram[iBand][i].getValue() * ((histogram[iBand][i].getMax() + histogram[iBand][i].getMin())/2);
440
                                }
441
                                // Calculo de la media
442
                                try {
443
                                        average[showBandCounter] /= nPixelsBand[showBandCounter];
444
                                } catch (ArithmeticException exc) {
445
                                        average[showBandCounter] = 0;
446
                                }
447

    
448
                                // Calculo de mediana
449
                                double stopPos = nPixelsBand[showBandCounter] / 2;
450
                                double aux = 0;
451
                                int i = beginPos;
452
                                for (i = beginPos; aux <= stopPos; i++) {
453
                                        if (i >= histogram[iBand].length)
454
                                                break;
455
                                        try {
456
                                                aux += histogram[iBand][i].getValue();
457
                                        } catch (ArrayIndexOutOfBoundsException e) {
458
                                                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);
459
                                        }
460
                                }
461
                                middle[showBandCounter] = (histogram[iBand][i - 1].getMax() + histogram[iBand][i - 1].getMin()) / 2;
462
                                showBandCounter++;
463
                        }
464
                }
465
         
466
                res[0] = min;
467
                res[1] = max;
468
                res[2] = average;
469
                res[3] = middle;
470
                res[4] = nPixelsBand;
471
                return res;
472
        }
473
        
474
        /**
475
         * Obtiene la tabla de valores
476
         * @return
477
         */
478
        public long[][] getTable() {
479
                return table;
480
        }
481
        
482
        /*
483
         * (non-Javadoc)
484
         * @see org.gvsig.fmap.dal.coverage.datastruct.BufferHistogram#addTable(long[][])
485
         */
486
        public void addTable(long[][] table) {
487
                if(this.table == null) {
488
                        this.table = table;
489
                        return;
490
                }
491
                long[][] newTable = new long[this.table.length + table.length][];
492
                for (int i = 0; i < this.table.length; i++) {
493
                        newTable[i] = this.table[i];
494
                }
495
                for (int i = this.table.length; i < (this.table.length + table.length); i++) {
496
                        newTable[i] = table[i];
497
                }
498
                table = newTable;
499
        }
500
        
501
        /**
502
         * Obtiene la tabla de valores normalizada. Divide todos los elementos por el n?mero de
503
         * pixeles total.
504
         * @return tabla de valores normalizada
505
         */
506
        public static double[][] convertToNormalizeHistogram(long[][] tableToConvert) {
507
                long[] nValues = new long[tableToConvert.length];
508
                for (int i = 0; i < tableToConvert.length; i++)
509
                        for (int j = 0; j < tableToConvert[i].length; j++)
510
                                nValues[i] += tableToConvert[i][j];
511
                
512
                double[][] res = new double[tableToConvert.length][tableToConvert[0].length];
513
                for (int i = 0; i < tableToConvert.length; i++)
514
                        for (int j = 0; j < tableToConvert[i].length; j++) 
515
                                res[i][j] = (double)((double)tableToConvert[i][j] / (double)nValues[i]);
516

    
517
                return res;
518
        }
519
        
520
        /**
521
         * Obtiene la tabla de valores normalizada y acumulada. Divide todos los elementos por el n?mero de
522
         * pixeles total.
523
         * @return tabla de valores normalizada
524
         */
525
        public static double[][] convertTableToNormalizeAccumulate(long[][] tableToConvert) {
526
                double[][] res = convertToNormalizeHistogram(tableToConvert);
527
                for (int i = 0; i < tableToConvert.length; i++)
528
                        for (int j = 0; j < tableToConvert[i].length; j++)
529
                                if(j > 0)
530
                                        res[i][j] += res[i][j - 1];
531

    
532
                return res;
533
        }
534
        
535
        /**
536
         * Obtiene el histograma de la imagen negativa.
537
         * @return long[][]
538
         */
539
        public long[][] getNegativeTable() {
540
                long[][] tableNeg = new long[table.length][table[0].length];
541
                for (int i = 0; i < tableNeg.length; i++) 
542
                        for (int j = 0; j < tableNeg[i].length; j++) 
543
                                tableNeg[i][table[i].length - j - 1] = table[i][j];
544
                return tableNeg;
545
        }
546

    
547
        /**
548
         * Convierte un histograma al rango de valores de RGB, en pocas palabras
549
         * aplica una operacion 0xff a cada pixel para quitar los numeros negativos
550
         * y desplazarlos a su rango visual.
551
         * @param histogram
552
         */
553
        public static BufferHistogram convertHistogramToRGB(BufferHistogram histogram) {
554
                if (histogram == null)
555
                        return null;
556

    
557
                if (histogram.getDataType() != Buffer.TYPE_BYTE)
558
                        return histogram;
559

    
560
                double min = histogram.getMin(0);
561
                double max = histogram.getMax(0);
562

    
563
                long table2[][] = histogram.getTable();
564

    
565
                long newTable[][] = new long[table2.length][table2[0].length];
566

    
567
                // Ponemos a cero todos los valores
568
                for (int i = 0; i < table2.length; i++)
569
                        for (int j = 0; j < table2[i].length; j++)
570
                                newTable[i][j] = 0;
571

    
572
                // Sumamos en la posicion calculada nueva el valor correspondiente
573
                for (int i = 0; i < table2.length; i++) {
574
                        for (int j = 0; j < table2[i].length; j++) {
575
                                double val = ((j * (max - min)) / 255) + min;
576
                                int pos = ((int) val) & 0xff;
577
                                if (pos < 0)
578
                                        pos = 0;
579
                                if (pos >= newTable[i].length)
580
                                        pos = newTable[i].length - 1;
581

    
582
                                newTable[i][pos] += table2[i][j];
583
                        }
584
                }
585

    
586
                double mins[] = new double[histogram.getNumBands()];
587
                double maxs[] = new double[histogram.getNumBands()];
588
                
589
                for (int i = 0; i < mins.length; i++) {
590
                        mins[i] = 0;
591
                        maxs[i] = 255;
592
                }
593

    
594
                BufferHistogramImpl histogramNew = new BufferHistogramImpl(histogram.getNumBands(), mins, maxs, Buffer.TYPE_BYTE);
595

    
596
                histogramNew.setTable(newTable);
597

    
598
                return histogramNew;
599
        }
600

    
601
        /**
602
         * @param noDataValue the noDataValue to set
603
         */
604
        public void setNoDataValue(NoData noDataValue) {
605
                this.noDataValue = noDataValue;
606
        }
607
}