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 @ 2623

History | View | Annotate | Download (16.7 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
 * @author Nacho Brodin (nachobrodin@gmail.com)
34
 */
35
public class BufferHistogramImpl implements BufferHistogram {
36
        /**
37
         * Variable que representa el histograma. La primera dimensi?n es el n?mero de 
38
         * bandas y la segunda un array de clases. En el caso b?sico de un RGB una clase tendr? el
39
         * valor m?nimo igual al m?ximo.
40
         */
41
        private HistogramClass[][] histogram   = null;
42

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

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

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

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

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

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

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

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

    
131
                return true;
132
        }
133

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
595
                histogramNew.setTable(newTable);
596

    
597
                return histogramNew;
598
        }
599

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