Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libRaster / src / org / gvsig / raster / dataset / properties / DatasetStatistics.java @ 21003

History | View | Annotate | Download (15 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 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.dataset.properties;
20

    
21
import java.io.File;
22
import java.io.IOException;
23
import java.util.ArrayList;
24
import java.util.Hashtable;
25

    
26
import org.gvsig.raster.RasterLibrary;
27
import org.gvsig.raster.dataset.FileNotOpenException;
28
import org.gvsig.raster.dataset.IBuffer;
29
import org.gvsig.raster.dataset.InvalidSetViewException;
30
import org.gvsig.raster.dataset.RasterDataset;
31
import org.gvsig.raster.dataset.io.RasterDriverException;
32
import org.gvsig.raster.dataset.io.rmf.ParsingException;
33
import org.gvsig.raster.dataset.io.rmf.RmfBlocksManager;
34
import org.gvsig.raster.dataset.serializer.StatisticsRmfSerializer;
35
import org.gvsig.raster.hierarchy.IStatistics;
36
import org.gvsig.raster.process.RasterTask;
37
import org.gvsig.raster.process.RasterTaskQueue;
38
import org.gvsig.raster.util.RasterUtilities;
39
/**
40
 * Estadisticas asociadas a un fichero raster.
41
 *  
42
 * @author Nacho Brodin (nachobrodin@gmail.com)
43
 */
44
public class DatasetStatistics implements IStatistics {
45
        
46
        /*
47
         * Esta a false si las estadisticas no son del fichero completo. Esto es posible porque podemos
48
         * tener unas estad?sticas calculadas a partir de una petici?n con subsampleo. Hay que tener en
49
         * cuenta que el raster puede ser muy grande y este calculo muy costoso.
50
         */
51
        protected boolean       complete       = false;
52
        protected double[]      max            = null;
53
        protected double[]      min            = null;
54
        protected double[]      secondMax      = null;
55
        protected double[]      secondMin      = null;
56

    
57
        protected double[]      maxRGB         = null;
58
        protected double[]      minRGB         = null;
59
        protected double[]      secondMaxRGB   = null;
60
        protected double[]      secondMinRGB   = null;
61

    
62
        protected double[]      mean           = null;
63
        protected double[]      variance       = null;
64

    
65
        protected String        fName          = null;
66
        protected RasterDataset dataset        = null;
67
        protected boolean       calculated     = false;
68
        protected Hashtable     tailTrim       = new Hashtable();
69
        protected ArrayList     tailTrimValues = new ArrayList();
70
        private int             bandCount      = 0;
71
        private int             percent        = 0;
72
        private boolean         forceToRecalc  = false;
73
        
74
        /**
75
         * Constructor. Asigna el fichero asociado.
76
         */
77
        public DatasetStatistics(RasterDataset grf){
78
                this.dataset = grf;
79
                if(dataset != null)
80
                        bandCount = dataset.getBandCount();
81
        }
82
        
83
        /**
84
         * Asigna el valor m?ximo del grid
85
         * @return Valor m?ximo
86
         */
87
        public void setMax(double[] max) {
88
                this.max = max;
89
        }
90

    
91
        /**
92
         * Asigna el valor del segundo m?ximo
93
         * @return Valor del segundo m?ximo
94
         */
95
        public void setSecondMax(double[] smax) {
96
                this.secondMax = smax;
97
        }
98
        
99
        /**
100
         * Asigna el valor m?ximo del grid
101
         * @return Valor m?ximo
102
         */
103
        public void setMaxRGB(double[] max) {
104
                this.maxRGB = max;
105
        }
106

    
107
        /**
108
         * Asigna el valor del segundo m?ximo
109
         * @return Valor del segundo m?ximo
110
         */
111
        public void setSecondMaxRGB(double[] smax) {
112
                this.secondMaxRGB = smax;
113
        }
114
        
115
        /**
116
         * Asigna el valor m?dio del grid
117
         * @return Valor medio
118
         */
119
        public void setMean(double[] mean) {
120
                this.mean = mean;
121
        }
122

    
123
        /**
124
         * Asigna el valor m?ximo del grid
125
         * @return Valor m?nimo
126
         */
127
        public void setMin(double[] min) {
128
                this.min = min;
129
        }
130

    
131
        /**
132
         * Asigna el valor del segundo m?nimo
133
         * @return Valor del segundo m?nimo
134
         */
135
        public void setSecondMin(double[] smin) {
136
                this.secondMin = smin;
137
        }
138
        
139
        /**
140
         * Asigna el valor m?ximo del grid
141
         * @return Valor m?nimo
142
         */
143
        public void setMinRGB(double[] min) {
144
                this.minRGB = min;
145
        }
146

    
147
        /**
148
         * Asigna el valor del segundo m?nimo
149
         * @return Valor del segundo m?nimo
150
         */
151
        public void setSecondMinRGB(double[] smin) {
152
                this.secondMinRGB = smin;
153
        }
154
        
155
        /**
156
         * Asigna la varianza
157
         * @return Varianza
158
         */
159
        public void setVariance(double[] variance) {
160
                this.variance = variance;
161
        }
162
        
163
        /*
164
         *  (non-Javadoc)
165
         * @see org.gvsig.fmap.driver.IStatistics#getMin()
166
         */
167
        public double[] getMin() {
168
                return min;
169
        }
170
        
171
        /*
172
         *  (non-Javadoc)
173
         * @see org.gvsig.fmap.driver.IStatistics#getMax()
174
         */
175
        public double[] getMax() {
176
                return max;
177
        }
178
        
179
        /*
180
         *  (non-Javadoc)
181
         * @see org.gvsig.fmap.driver.IStatistics#getSecondMax()
182
         */
183
        public double[] getSecondMax() {
184
                return secondMax;
185
        }
186
        
187
        /*
188
         *  (non-Javadoc)
189
         * @see org.gvsig.fmap.driver.IStatistics#getSecondMin()
190
         */
191
        public double[] getSecondMin() {
192
                return secondMin;
193
        }
194
        
195
        /*
196
         * (non-Javadoc)
197
         * @see org.gvsig.raster.hierarchy.IStatistics#getMinRGB()
198
         */
199
        public double[] getMinRGB() {
200
                return minRGB;
201
        }
202
        
203
        /*
204
         * (non-Javadoc)
205
         * @see org.gvsig.raster.hierarchy.IStatistics#getMaxRGB()
206
         */
207
        public double[] getMaxRGB() {
208
                return maxRGB;
209
        }
210
        
211
        /*
212
         * (non-Javadoc)
213
         * @see org.gvsig.raster.hierarchy.IStatistics#getSecondMaxRGB()
214
         */
215
        public double[] getSecondMaxRGB() {
216
                return secondMaxRGB;
217
        }
218
        
219
        /*
220
         * (non-Javadoc)
221
         * @see org.gvsig.raster.hierarchy.IStatistics#getSecondMinRGB()
222
         */
223
        public double[] getSecondMinRGB() {
224
                return secondMinRGB;
225
        }
226
        
227
        /*
228
         *  (non-Javadoc)
229
         * @see org.gvsig.fmap.driver.IStatistics#getMaximun()
230
         */
231
        public double getMaximun() {
232
                double m = Double.NEGATIVE_INFINITY;
233
                for (int i = 0; i < max.length; i++)
234
                        m = Math.max(m, max[i]);
235
                return m;
236
        }
237
        
238
        /*
239
         *  (non-Javadoc)
240
         * @see org.gvsig.fmap.driver.IStatistics#getMinimun()
241
         */
242
        public double getMinimun() {
243
                double m = Double.MAX_VALUE;
244
                for (int i = 0; i < min.length; i++)
245
                        m = Math.min(m, min[i]);
246
                return m;
247
        }
248
        
249
        /*
250
         * (non-Javadoc)
251
         * @see org.gvsig.raster.hierarchy.IStatistics#getMaximunRGB()
252
         */
253
        public double getMaximunRGB() {
254
                double m = Double.NEGATIVE_INFINITY;
255
                for (int i = 0; i < maxRGB.length; i++)
256
                        m = Math.max(m, maxRGB[i]);
257
                return m;
258
        }
259

    
260
        /*
261
         * (non-Javadoc)
262
         * @see org.gvsig.raster.hierarchy.IStatistics#getMinimunRGB()
263
         */
264
        public double getMinimunRGB() {
265
                double m = Double.MAX_VALUE;
266
                for (int i = 0; i < minRGB.length; i++)
267
                        m = Math.min(m, minRGB[i]);
268
                return m;
269
        }
270

    
271
        /*
272
         *  (non-Javadoc)
273
         * @see org.gvsig.fmap.driver.IStatistics#getMean()
274
         */
275
        public double[] getMean() {
276
                return mean;
277
        }
278

    
279
        /*
280
         *  (non-Javadoc)
281
         * @see org.gvsig.fmap.driver.IStatistics#getVariance()
282
         */
283
        public double[] getVariance() {
284
                return variance;
285
        }
286
        
287
        /*
288
         *  (non-Javadoc)
289
         * @see org.gvsig.fmap.driver.IStatistics#getBandCount()
290
         */
291
        public int getBandCount(){
292
                return this.bandCount;
293
        }
294
        
295
        /**
296
         * Asigna el n?mero de bandas
297
         * @param bandCount
298
         */
299
        public void setBandCount(int bandCount) {
300
                this.bandCount = bandCount;
301
        }
302
        
303
        /**
304
         * Intenta cargar las estadisticas desde el RMF. Para saber si las ha podido
305
         * cargar, se puede consultar despues con isCalculated()
306
         * @return
307
         */
308
        public void loadStatisticsFromRmf() {
309
                calculated = false;
310
                if (dataset == null)
311
                        return;
312
                try {
313
                        loadFromRmf(dataset.getRmfBlocksManager());
314
                } catch (ParsingException e) {
315
                        // No lee desde rmf
316
                }
317
                
318
        }
319
        
320
        /*
321
         * (non-Javadoc)
322
         * @see org.gvsig.raster.hierarchy.IStatistics#calcFullStatistics()
323
         */
324
        public void calcFullStatistics() 
325
                throws FileNotOpenException, RasterDriverException, InterruptedException {
326
                RasterTask task = RasterTaskQueue.get(Thread.currentThread().toString());
327
                percent = 0;
328
                if (dataset != null && !forceToRecalc) {
329
                        if (!isCalculated())
330
                                loadStatisticsFromRmf();
331
                        if (isCalculated())
332
                                return;
333
                }
334

    
335
                if (dataset != null)
336
                        bandCount = dataset.getBandCount();
337

    
338
//                long t2, p1, p2;
339
//                long t1 = new Date().getTime();
340
                max = new double[bandCount];
341
                min = new double[bandCount];
342
                secondMax = new double[bandCount];
343
                secondMin = new double[bandCount];
344
                maxRGB = new double[bandCount];
345
                minRGB = new double[bandCount];
346
                secondMaxRGB = new double[bandCount];
347
                secondMinRGB = new double[bandCount];
348
                mean = new double[bandCount];
349
                variance = new double[bandCount];
350
                long[] iValues = new long[bandCount];
351
                boolean[] init = new boolean[bandCount];
352
                int[] type = new int[bandCount];
353

    
354
                byte[][][] b = null;
355
                short[][][] s = null;
356
                int[][][] i = null;
357
                float[][][] f = null;
358
                double[][][] d = null;
359

    
360
                for (int iBand = 0; iBand < bandCount; iBand++) {
361
                        max[iBand] = Double.NEGATIVE_INFINITY;
362
                        min[iBand] = Double.POSITIVE_INFINITY;
363
                        secondMax[iBand] = Double.NEGATIVE_INFINITY;
364
                        secondMin[iBand] = Double.POSITIVE_INFINITY;
365
                        maxRGB[iBand] = 0;
366
                        minRGB[iBand] = 255;
367
                        secondMaxRGB[iBand] = 0;
368
                        secondMinRGB[iBand] = 255;
369
                        init[iBand] = true;
370
                        type[iBand] = dataset.getDataType()[iBand];
371
                        if (task.getEvent() != null)
372
                                task.manageEvent(task.getEvent());
373
                }
374

    
375
                int h = RasterLibrary.blockHeight;
376
                for (int block = 0; block < dataset.getHeight(); block += h) {
377
//                        p1 = new Date().getTime();
378
                        Object buf = null;
379
                        try {
380
                                buf = dataset.readBlock(block, RasterLibrary.blockHeight);
381
                        } catch (InvalidSetViewException e) {
382
                                // La vista se asigna autom?ticamente
383
                        }
384
                        switch (type[0]) {
385
                                case IBuffer.TYPE_BYTE:          b = (byte[][][]) buf; break;
386
                                case IBuffer.TYPE_SHORT:  s = (short[][][]) buf; break;
387
                                case IBuffer.TYPE_INT:    i = (int[][][]) buf; break;
388
                                case IBuffer.TYPE_FLOAT:  f = (float[][][]) buf; break;
389
                                case IBuffer.TYPE_DOUBLE: d = (double[][][]) buf; break;
390
                        }
391
                        
392
                        int hB = RasterLibrary.blockHeight;
393
                        if ((block + hB) > dataset.getHeight())
394
                                hB = Math.abs(dataset.getHeight() - block);
395
                        for (int iBand = 0; iBand < bandCount; iBand++) {
396
                                for (int col = 0; col < dataset.getWidth(); col++) {
397
                                        for (int row = 0; row < hB; row++) {
398
                                                double z = (b != null) ? b[iBand][row][col] : ((s != null) ? s[iBand][row][col] : ((i != null) ? i[iBand][row][col] : (f != null) ? f[iBand][row][col] : d[iBand][row][col]));
399
                                                if (z == dataset.getNoDataValue())
400
                                                        continue;
401

    
402
                                                if (Double.isNaN(z))
403
                                                        continue;
404

    
405
//                                                if(z < 0)
406
//                                                        System.out.println("");
407
                                                double rgb = (b != null) ? (b[iBand][row][col] & 0xff) : 0;
408
                                                if (init[iBand]) {
409
                                                        min[iBand] = z;
410
                                                        max[iBand] = z;
411
                                                        minRGB[iBand] = rgb;
412
                                                        maxRGB[iBand] = rgb;
413
                                                        init[iBand] = false;
414
                                                } else {
415
                                                        if (min[iBand] > z) {
416
                                                                secondMin[iBand] = min[iBand];
417
                                                                min[iBand] = z;
418
                                                        }
419

    
420
                                                        if (minRGB[iBand] > rgb) {
421
                                                                secondMinRGB[iBand] = minRGB[iBand];
422
                                                                minRGB[iBand] = rgb;
423
                                                        }
424
                                                        
425
                                                        if (max[iBand] < z) {
426
                                                                secondMax[iBand] = max[iBand];
427
                                                                max[iBand] = z;
428
                                                        }
429

    
430
                                                        if (maxRGB[iBand] < rgb) {
431
                                                                secondMaxRGB[iBand] = maxRGB[iBand];
432
                                                                maxRGB[iBand] = rgb;
433
                                                        }
434

    
435
                                                        if (z < max[iBand] && z > secondMax[iBand])
436
                                                                secondMax[iBand] = z;
437

    
438
                                                        if (z > min[iBand] && z < secondMin[iBand])
439
                                                                secondMin[iBand] = z;
440

    
441
                                                        if (rgb < maxRGB[iBand] && rgb > secondMaxRGB[iBand])
442
                                                                secondMaxRGB[iBand] = rgb;
443

    
444
                                                        if (rgb > minRGB[iBand] && rgb < secondMinRGB[iBand])
445
                                                                secondMinRGB[iBand] = rgb;
446

    
447
                                                }
448
                                                mean[iBand] += z;
449
                                                variance[iBand] += z * z;
450
                                                iValues[iBand]++;
451
                                        }
452

    
453
                                        if (task.getEvent() != null)
454
                                                task.manageEvent(task.getEvent());
455
                                }
456
                        }
457
                        percent += ((h * 100) / dataset.getHeight());
458
//                        p2 = new Date().getTime();
459
//                        System.out.println("Time (Statistics) " + block + ": " + ((p2 - p1) / 1000D) + ", secs.");
460
                }
461
                percent = 100;
462

    
463
                for (int iBand = 0; iBand < bandCount; iBand++) {
464
                        if (iValues[iBand] > 0) {
465
                                mean[iBand] /= (double) iValues[iBand];
466
                                variance[iBand] = variance[iBand] / (double) iValues[iBand] - mean[iBand] * mean[iBand];
467
                        }
468
                        if (task.getEvent() != null)
469
                                task.manageEvent(task.getEvent());
470
                }
471

    
472
                calculated = true;
473
//                t2 = new Date().getTime();
474
//    System.out.println("Estadisticas " + dataset.getFName() + ": " + ((t2 - t1) / 1000D) + ", secs.");
475
                        
476
                if (dataset != null) {
477
                        try {
478
                                saveToRmf(dataset.getRmfBlocksManager());
479
                                forceToRecalc = false;
480
                        } catch (IOException e) {
481
                                // No salva a rmf
482
                        }
483
                }
484
        }
485

    
486
        /**
487
         * Carga estadisticas desde el fichero Rmf si las hay.
488
         * @param fName Nombre del fichero
489
         * @throws ParsingException 
490
         */
491
        public void loadFromRmf(RmfBlocksManager manager) throws ParsingException {
492
                StatisticsRmfSerializer ser = new StatisticsRmfSerializer(this);
493
                if(!manager.checkRmf())
494
                        return;
495
                if(!new File(manager.getPath()).exists())
496
                        return;
497
                manager.addClient(ser);
498
                manager.read(null);
499
                manager.removeClient(ser.getClass());
500
        }
501
        
502
        /**
503
         * Salva estad?sticas a fichero rmf.
504
         * @param fName
505
         * @throws IOException  
506
         */
507
        public void saveToRmf(RmfBlocksManager manager) throws IOException {
508
                StatisticsRmfSerializer ser = new StatisticsRmfSerializer(this);
509
                if(!manager.checkRmf())
510
                        return;
511
                manager.addClient(ser);
512
                RasterUtilities.copyFile(manager.getPath(), manager.getPath() + "~");
513
                manager.write();
514
                manager.removeClient(ser.getClass());
515
        }
516

    
517
        /*
518
         *  (non-Javadoc)
519
         * @see org.gvsig.fmap.driver.IStatistics#isCalculated()
520
         */
521
        public boolean isCalculated() {
522
                return calculated;
523
        }
524
        
525
        /**
526
         * Asigna el flag de estad?sticas calculadas.
527
         * @param calc
528
         */
529
        public void setCalculated(boolean calc) {
530
                calculated = calc;
531
        }
532
        
533
        /*
534
         *  (non-Javadoc)
535
         * @see org.gvsig.fmap.driver.IStatistics#setTailTrimValue(double, java.lang.Object)
536
         */
537
        public void setTailTrimValue(double percent, Object valueByBand){
538
                tailTrim.put(percent + "", valueByBand);
539
                for (int i = 0; i < tailTrimValues.size(); i++) {
540
                        if(tailTrimValues.get(i).equals(percent + "")) {
541
                                tailTrimValues.set(i, percent + "");
542
                                return;
543
                        }
544
                }
545
                tailTrimValues.add(percent + "");
546
        }
547
        
548
        /*
549
         *  (non-Javadoc)
550
         * @see org.gvsig.fmap.driver.IStatistics#getTailTrimValue(double)
551
         */
552
        public Object getTailTrimValue(double percent){
553
                return tailTrim.get(percent + "");
554
        }
555
        
556
        /*
557
         *  (non-Javadoc)
558
         * @see org.gvsig.raster.shared.IStatistics#getTailTrimValue(int)
559
         */
560
        public Object[] getTailTrimValue(int pos) {
561
                return new Object[]{tailTrimValues.get(pos), tailTrim.get((Double)tailTrimValues.get(pos))};
562
        }
563
        
564
        /*
565
         *  (non-Javadoc)
566
         * @see org.gvsig.raster.shared.IStatistics#getTailTrimCount()
567
         */
568
        public int getTailTrimCount() {
569
                return tailTrimValues.size();
570
        }
571

    
572
        /**
573
         * Pone a cero el porcentaje de progreso del proceso de calculo de histograma
574
         */
575
        public void resetPercent() {
576
                percent = 0;
577
        }
578

    
579
        /**
580
         * Obtiene el porcentaje de progreso del proceso de calculo de histograma
581
         * @return porcentaje de progreso
582
         */
583
        public int getPercent() {
584
                return percent;
585
        }
586

    
587
        /**
588
         * Cuando se llama a este m?todo fuerza que la siguiente petici?n de estad?sticas 
589
         * no sea le?da de RMF y sean recalculadas por completo.
590
         * @param forceToRecalc
591
         */
592
        public void forceToRecalc() {
593
                this.forceToRecalc = true;
594
        }
595
}