Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-2018a / org.gvsig.desktop.library / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.buffer.impl / src / main / java / org / gvsig / raster / lib / buffer / impl / operations / median / MedianOperation.java @ 43864

History | View | Annotate | Download (20.6 KB)

1
/* gvSIG. Desktop Geographic Information System.
2
 *
3
 * Copyright ? 2007-2017 gvSIG Association
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., 51 Franklin Street, Fifth Floor, Boston,
18
 * MA  02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us
21
 * at info AT gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.raster.lib.buffer.impl.operations.median;
24

    
25
import java.util.ArrayList;
26
import java.util.Collections;
27
import java.util.Comparator;
28
import java.util.Iterator;
29
import java.util.List;
30

    
31
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
32
import org.gvsig.raster.lib.buffer.api.Band;
33
import org.gvsig.raster.lib.buffer.api.BufferLocator;
34
import org.gvsig.raster.lib.buffer.api.BufferManager;
35
import org.gvsig.raster.lib.buffer.api.NoData;
36
import org.gvsig.raster.lib.buffer.api.exceptions.BandException;
37
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
38
import org.gvsig.raster.lib.buffer.api.exceptions.BufferOperationException;
39
import org.gvsig.raster.lib.buffer.api.operations.OperationFactory;
40
import org.gvsig.raster.lib.buffer.api.statistics.Statistics;
41
import org.gvsig.raster.lib.buffer.spi.exceptions.ProcessingOperationException;
42
import org.gvsig.raster.lib.buffer.spi.operations.AbstractSpecifiedBandsOperation;
43
import org.gvsig.tools.locator.LocatorException;
44

    
45

    
46
/**
47
 * @author fdiaz
48
 *
49
 */
50
public class MedianOperation extends AbstractSpecifiedBandsOperation{
51

    
52
    static public String SIDE_WINDOW_PARAM = "side_window";
53

    
54
    private Statistics statistics;
55
    private int sideWindow;
56
    private RowProcessor[] rowProcessors;
57
    private int halfSideWindow;
58

    
59
    /**
60
     * @param factory
61
     *
62
     */
63
    public MedianOperation(OperationFactory factory) {
64
        super(factory);
65
    }
66

    
67
    @SuppressWarnings("unchecked")
68
    @Override
69
    public void preProcess() throws BufferOperationException {
70
        super.preProcess();
71
        BufferManager manager = BufferLocator.getBufferManager();
72

    
73
        sideWindow = (int) this.getParameter(SIDE_WINDOW_PARAM, 3);
74
        halfSideWindow = (int)(sideWindow/2);
75

    
76
        int bands = this.getInputBuffer().getBandCount();
77
        NoData[] noData = this.getInputBuffer().getBandNoData();
78
        if (mustCopyUnprocessedBands()) {
79
            try {
80
                this.setOutputBuffer(
81
                    manager.createBuffer(
82
                            this.getInputBuffer().getRows(), 
83
                            this.getInputBuffer().getColumns(), 
84
                            this.getInputBuffer().getBandTypes(),
85
                            this.getInputBuffer().getBandNoData(), 
86
                            this.getInputBuffer().getProjection(), 
87
                            this.getInputBuffer().getEnvelope()));
88
            } catch (LocatorException | BufferException | CreateEnvelopeException e) {
89
                throw new ProcessingOperationException(e);
90
            }
91
        } else {
92
            try {
93
                this.setOutputBuffer(
94
                    manager.createBuffer(
95
                            this.getInputBuffer().getRows(), 
96
                            this.getInputBuffer().getColumns(), 
97
                            this.getProcessableBandTypesAsArray(),
98
                            this.getProcessableBandNoDatasAsArray(), 
99
                            this.getInputBuffer().getProjection(), 
100
                            this.getInputBuffer().getEnvelope()));
101
            } catch (LocatorException | BufferException | CreateEnvelopeException e) {
102
                throw new ProcessingOperationException(e);
103
            }
104
        }
105

    
106
        rowProcessors = new RowProcessor[bands];
107
        for (int band = 0; band < noData.length; band++) {
108
            if (isProcessableBand(band)) {
109
                int bandType = this.getInputBuffer().getBand(band).getDataType();
110
                switch (bandType) {
111
                case BufferManager.TYPE_BYTE:
112
                    rowProcessors[band] = new ByteRowProcessor(band);
113
                    break;
114
                case BufferManager.TYPE_USHORT:
115
                    rowProcessors[band] = new UShortRowProcessor(band);
116
                    break;
117
                case BufferManager.TYPE_SHORT:
118
                    rowProcessors[band] = new ShortRowProcessor(band);
119
                    break;
120
                case BufferManager.TYPE_INT:
121
                    rowProcessors[band] = new IntRowProcessor(band);
122
                    break;
123
                case BufferManager.TYPE_FLOAT:
124
                    rowProcessors[band] = new FloatRowProcessor(band);
125
                    break;
126
                case BufferManager.TYPE_DOUBLE:
127
                    rowProcessors[band] = new DoubleRowProcessor(band);
128
                    break;
129
                default:
130
                    throw new IllegalArgumentException("Unknow type of band '" + band + "'");
131
                }
132
            }
133
        }
134
    }
135

    
136
    @Override
137
    public void process() throws ProcessingOperationException {
138
        super.process();
139
        for (int band=0; band<this.getInputBuffer().getBandCount(); band++){
140
            if (getBandsToProcess().contains(band)) {
141
                Band bufferBand = this.getInputBuffer().getBand(band);
142
                Band outputBufferBand = this.getOutputBuffer().getBand(band);
143

    
144

    
145
                for (int row = 0; row < this.getInputBuffer().getRows(); row++) {
146
                    Object rowBuffer = bufferBand.createRowBuffer();
147
                    bufferBand.fetchRow(row, rowBuffer);
148
                    List<Object> bundle = new ArrayList<>();
149
                    for(int r=Math.max(row-halfSideWindow,0); r<=Math.min(row+halfSideWindow,this.getInputBuffer().getRows()-1);r++){
150
                        Object bundleRow = bufferBand.createRowBuffer();
151
                        bufferBand.fetchRow(row, bundleRow);
152
                        bundle.add(bundleRow);
153
                    }
154

    
155
                    Object outputRowBuffer = outputBufferBand.createRowBuffer();
156
//                    outputBufferBand.fetchRow(row, outputRowBuffer);
157

    
158
                    rowProcessors[band].processRow(rowBuffer, bundle, outputRowBuffer);
159

    
160
                    outputBufferBand.putRow(row, outputRowBuffer);
161
                }
162
            } else {
163
                if(mustCopyUnprocessedBands()){
164
                    try {
165
                        this.getOutputBuffer().getBand(band).copyFrom(this.getInputBuffer().getBand(band));
166
                    } catch (BandException e) {
167
                        throw new ProcessingOperationException(e);
168
                    }
169
                }
170
            }
171
        }
172
    }
173

    
174
    @Override
175
    public void postProcess()  throws BufferOperationException {
176
        super.postProcess();
177
    }
178

    
179
    interface RowProcessor {
180
        void processRow(Object inputRow, List<Object> bundleRow, Object outputRow);
181
        Number processValue(Number value, List<Number> kernel);
182
    };
183

    
184
    private abstract class AbstractRowProcessor implements RowProcessor {
185
        int band;
186
        NoData noData;
187

    
188
        public AbstractRowProcessor(int band) {
189
            this.band = band;
190
            noData = getInputBuffer().getBand(band).getNoData();
191
        }
192
    }
193

    
194
    private class ByteRowProcessor extends AbstractRowProcessor {
195

    
196

    
197
        public ByteRowProcessor(int band) {
198
            super(band);
199
        }
200

    
201
        @Override
202
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
203
            byte[] inputByteRow = (byte[])inputRow;
204
            byte[] outputByteRow = (byte[])outputRow;
205
            for (int i = 0; i < inputByteRow.length; i++) {
206
                List<Number> kernel = new ArrayList<>();
207
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
208
                    byte[] row = (byte[]) iterator.next();
209
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputByteRow.length-1);c++){
210
                        Integer value = 0xFF & ((Byte) row[c]);
211
                        if(noData.isDefined() && noData.getValue().equals(value)){
212
                            continue;
213
                        } else {
214
                            kernel.add(value);
215
                        }
216
                    }
217
                }
218
                outputByteRow[i] = processValue(inputByteRow[i], kernel).byteValue();
219
            }
220
        }
221

    
222
        @Override
223
        public Number processValue(Number value, List<Number> kernel) {
224
            if(noData.isDefined() && noData.getValue().equals(value)){
225
                return (byte)value;
226
            }
227
            Collections.sort(kernel,new Comparator<Number>() {
228
                @Override
229
                public int compare(Number o1, Number o2) {
230
                    return o1.intValue()-o2.intValue();
231
                }
232
            });
233

    
234
            int n = kernel.size();
235
            int temp = n / 2;
236
            int pos;
237
            double temp0;
238
            if ( n % 2 == 0 ) {
239
                pos = (int)temp;
240
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
241
            } else { // if ( n % 2 == 1 )
242
                pos = (int)(temp + 0.5);
243
                temp0 = (double)(kernel.get(pos).intValue());
244
            }
245

    
246
          return (byte)(new Double(temp0).intValue() & 0xFF);
247

    
248
        }
249

    
250
    }
251

    
252
    private class ShortRowProcessor extends AbstractRowProcessor {
253

    
254
        public ShortRowProcessor(int band) {
255
            super(band);
256
        }
257

    
258
        @Override
259
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
260
            Number[] inputShortRow = (Number[])inputRow;
261
            short[] outputShortRow = (short[])outputRow;
262
            for (int i = 0; i < inputShortRow.length; i++) {
263
                List<Number> kernel = new ArrayList<Number>();
264
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
265
                    short[] row = (short[]) iterator.next();
266
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputShortRow.length-1);c++){
267
                        Short value = ((Short) row[c]).shortValue();
268
                        if(noData.isDefined() && noData.getValue().equals(value)){
269
                            continue;
270
                        } else {
271
                            kernel.add(value);
272
                        }
273
                        kernel.add(value);
274
                    }
275
                }
276
                outputShortRow[i] = processValue(inputShortRow[i], kernel).shortValue();
277
            }
278
        }
279

    
280
        @Override
281
        public Number processValue(Number value, List<Number> kernel) {
282
            if(noData.isDefined() && noData.getValue().equals(value)){
283
                return (short)value;
284
            }
285
            Collections.sort(kernel,new Comparator<Number>() {
286
                @Override
287
                public int compare(Number o1, Number o2) {
288
                    return ((Short)o1).compareTo((Short)o2);
289
                }
290
            });
291

    
292
            int n = kernel.size();
293
            int temp = n / 2;
294
            int pos;
295
            double temp0;
296
            if ( n % 2 == 0 ) {
297
                pos = (int)temp;
298
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
299
            } else { // if ( n % 2 == 1 )
300
                pos = (int)(temp + 0.5);
301
                temp0 = (double)(kernel.get(pos).intValue());
302
            }
303

    
304
          return (short)(new Double(temp0).intValue());
305
        }
306
    }
307

    
308
    private class UShortRowProcessor extends AbstractRowProcessor {
309

    
310
        public UShortRowProcessor(int band) {
311
            super(band);
312
        }
313

    
314
        @Override
315
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
316
            Number[] inputShortRow = (Number[])inputRow;
317
            short[] outputShortRow = (short[])outputRow;
318
            for (int i = 0; i < inputShortRow.length; i++) {
319
                List<Number> kernel = new ArrayList<Number>();
320
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
321
                    short[] row = (short[]) iterator.next();
322
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputShortRow.length-1);c++){
323
                        Integer value = 0xFFFF & ((Short) row[c]).shortValue();
324
                        if(noData.isDefined() && noData.getValue().equals(value)){
325
                            continue;
326
                        } else {
327
                            kernel.add(value);
328
                        }
329
                        kernel.add(value);
330
                    }
331
                }
332
                outputShortRow[i] = processValue(inputShortRow[i], kernel).shortValue();
333
            }
334
        }
335

    
336
        @Override
337
        public Number processValue(Number value, List<Number> kernel) {
338
            if(noData.isDefined() && noData.getValue().equals(value)){
339
                return (short)value;
340
            }
341
            Collections.sort(kernel,new Comparator<Number>() {
342
                @Override
343
                public int compare(Number o1, Number o2) {
344
                    return o1.intValue()-o2.intValue();
345
                }
346
            });
347

    
348
            int n = kernel.size();
349
            int temp = n / 2;
350
            int pos;
351
            double temp0;
352
            if ( n % 2 == 0 ) {
353
                pos = (int)temp;
354
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
355
            } else { // if ( n % 2 == 1 )
356
                pos = (int)(temp + 0.5);
357
                temp0 = (double)(kernel.get(pos).intValue());
358
            }
359

    
360
          return (short)(new Double(temp0).intValue() & 0xFFFF);
361
        }
362
    }
363

    
364
    private class IntRowProcessor extends AbstractRowProcessor {
365

    
366

    
367
        public IntRowProcessor(int band) {
368
            super(band);
369
        }
370

    
371
        @Override
372
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
373
            Number[] inputIntRow = (Number[])inputRow;
374
            int[] outputIntRow = (int[])outputRow;
375
            for (int i = 0; i < inputIntRow.length; i++) {
376
                List<Number> kernel = new ArrayList<Number>();
377
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
378
                    int[] row = (int[]) iterator.next();
379
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputIntRow.length-1);c++){
380
                        Integer value = ((Integer) row[c]).intValue();
381
                        if(noData.isDefined() && noData.getValue().equals(value)){
382
                            continue;
383
                        } else {
384
                            kernel.add(value);
385
                        }
386
                        kernel.add(value);
387
                    }
388
                }
389
                outputIntRow[i] = processValue(inputIntRow[i], kernel).intValue();
390
            }
391
        }
392

    
393
        @Override
394
        public Number processValue(Number value, List<Number> kernel) {
395
            if(noData.isDefined() && noData.getValue().equals(value)){
396
                return (int)value;
397
            }
398
            Collections.sort(kernel,new Comparator<Number>() {
399
                @Override
400
                public int compare(Number o1, Number o2) {
401
                    return ((Integer)o1).compareTo((Integer)o2);
402
                }
403
            });
404

    
405
            int n = kernel.size();
406
            int temp = n / 2;
407
            int pos;
408
            double temp0;
409
            if ( n % 2 == 0 ) {
410
                pos = (int)temp;
411
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
412
            } else { // if ( n % 2 == 1 )
413
                pos = (int)(temp + 0.5);
414
                temp0 = (double)(kernel.get(pos).intValue());
415
            }
416

    
417
          return new Double(temp0).intValue();
418

    
419
        }
420

    
421
    }
422
    private class FloatRowProcessor extends AbstractRowProcessor {
423

    
424

    
425
        public FloatRowProcessor(int band) {
426
            super(band);
427
        }
428

    
429
        @Override
430
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
431
            Number[] inputFloatRow = (Number[])inputRow;
432
            float[] outputFloatRow = (float[])outputRow;
433
            for (int i = 0; i < inputFloatRow.length; i++) {
434
                List<Number> kernel = new ArrayList<Number>();
435
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
436
                    float[] row = (float[]) iterator.next();
437
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputFloatRow.length-1);c++){
438
                        Float value = ((Float) row[c]).floatValue();
439
                        if(noData.isDefined() && noData.getValue().equals(value)){
440
                            continue;
441
                        } else {
442
                            kernel.add(value);
443
                        }
444
                        kernel.add(value);
445
                    }
446
                }
447
                outputFloatRow[i] = processValue(inputFloatRow[i], kernel).floatValue();
448
            }
449
        }
450

    
451
        @Override
452
        public Number processValue(Number value, List<Number> kernel) {
453
            if(noData.isDefined() && noData.getValue().equals(value)){
454
                return (float)value;
455
            }
456
            Collections.sort(kernel,new Comparator<Number>() {
457
                @Override
458
                public int compare(Number o1, Number o2) {
459
                    return ((Double)o1).compareTo((Double)o2);
460
                }
461
            });
462

    
463
            int n = kernel.size();
464
            int temp = n / 2;
465
            int pos;
466
            double temp0;
467
            if ( n % 2 == 0 ) {
468
                pos = (int)temp;
469
                temp0 = (double)(kernel.get(pos).doubleValue() + kernel.get(pos + 1).doubleValue())/2;
470
            } else { // if ( n % 2 == 1 )
471
                pos = (int)(temp + 0.5);
472
                temp0 = (double)(kernel.get(pos).doubleValue());
473
            }
474

    
475
          return new Double(temp0).floatValue();
476
        }
477

    
478
    }
479
    private class DoubleRowProcessor extends AbstractRowProcessor {
480

    
481

    
482
        public DoubleRowProcessor(int band) {
483
            super(band);
484
        }
485

    
486
        @Override
487
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
488
            Number[] inputDoubleRow = (Number[])inputRow;
489
            double[] outputDoubleRow = (double[])outputRow;
490
            for (int i = 0; i < inputDoubleRow.length; i++) {
491
                List<Number> kernel = new ArrayList<Number>();
492
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
493
                    double[] row = (double[]) iterator.next();
494
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputDoubleRow.length-1);c++){
495
                        Double value = ((Double) row[c]).doubleValue();
496
                        if(noData.isDefined() && noData.getValue().equals(value)){
497
                            continue;
498
                        } else {
499
                            kernel.add(value);
500
                        }
501
                        kernel.add(value);
502
                    }
503
                }
504
                outputDoubleRow[i] = processValue(inputDoubleRow[i], kernel).floatValue();
505
            }
506
        }
507

    
508
        @Override
509
        public Number processValue(Number value, List<Number> kernel) {
510
            if(noData.isDefined() && noData.getValue().equals(value)){
511
                return (double)value;
512
            }
513
            Collections.sort(kernel,new Comparator<Number>() {
514
                @Override
515
                public int compare(Number o1, Number o2) {
516
                    return ((Double)o1).compareTo((Double)o2);
517
                }
518
            });
519

    
520
            int n = kernel.size();
521
            int temp = n / 2;
522
            int pos;
523
            double temp0;
524
            if ( n % 2 == 0 ) {
525
                pos = (int)temp;
526
                temp0 = (double)(kernel.get(pos).doubleValue() + kernel.get(pos + 1).doubleValue())/2;
527
            } else { // if ( n % 2 == 1 )
528
                pos = (int)(temp + 0.5);
529
                temp0 = (double)(kernel.get(pos).doubleValue());
530
            }
531

    
532
          return temp0;
533
        }
534

    
535
    }
536

    
537
}