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

History | View | Annotate | Download (21 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
        this.factory = factory;
65
    }
66

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

    
73
        if(this.parameters.getDynClass().getDynField(SIDE_WINDOW_PARAM)!=null) {
74
            sideWindow = (Integer)this.parameters.getDynValue(SIDE_WINDOW_PARAM);
75
        } else {
76
            sideWindow = 3;
77
        };
78
        halfSideWindow = (int)(sideWindow/2);
79

    
80
        int bands = this.buffer.getBandCount();
81
        NoData[] noData = this.buffer.getBandNoData();
82
        if (copyUnprocessedBands) {
83
            try {
84
                this.outputBuffer =
85
                    manager.createBuffer(this.buffer.getRows(), this.buffer.getColumns(), this.buffer.getBandTypes(),
86
                        this.buffer.getBandNoData(), this.buffer.getProjection(), this.buffer.getEnvelope());
87
            } catch (LocatorException | BufferException | CreateEnvelopeException e) {
88
                throw new ProcessingOperationException(e);
89
            }
90
        } else {
91
            List<NoData> noDatas = new ArrayList<NoData>();
92
            List<Integer> types = new ArrayList<Integer>();
93
            for (int band = 0; band < bands; band++) {
94
                if (isProcessableBand(band)) {
95
                    noDatas.add(this.buffer.getBandNoData()[band]);
96
                    types.add(this.buffer.getBandTypes()[band]);
97
                }
98
            }
99
            int[] typesInt = new int[types.size()];
100
            for (Iterator<Integer> iterator = types.iterator(); iterator.hasNext();) {
101
                int i = 0;
102
                Integer type = (Integer) iterator.next();
103
                typesInt[i] = type.intValue();
104
            }
105
            try {
106
                this.outputBuffer =
107
                    manager.createBuffer(this.buffer.getRows(), this.buffer.getColumns(), typesInt,
108
                        noDatas.toArray(new NoData[0]), this.buffer.getProjection(), this.buffer.getEnvelope());
109
            } catch (LocatorException | BufferException | CreateEnvelopeException e) {
110
                throw new ProcessingOperationException(e);
111
            }
112
        }
113

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

    
144
    @Override
145
    public void process() throws ProcessingOperationException {
146
        super.process();
147
        for (int band=0; band<this.buffer.getBandCount(); band++){
148
            if (bandsToProcess.contains(band)) {
149
                Band bufferBand = this.buffer.getBand(band);
150
                Band outputBufferBand = this.outputBuffer.getBand(band);
151

    
152

    
153
                for (int row = 0; row < this.buffer.getRows(); row++) {
154
                    Object rowBuffer = bufferBand.createRowBuffer();
155
                    bufferBand.fetchRow(row, rowBuffer);
156
                    List<Object> bundle = new ArrayList<Object>();
157
                    for(int r=Math.max(row-halfSideWindow,0); r<=Math.min(row+halfSideWindow,this.buffer.getRows()-1);r++){
158
                        Object bundleRow = bufferBand.createRowBuffer();
159
                        bufferBand.fetchRow(row, bundleRow);
160
                        bundle.add(bundleRow);
161
                    }
162

    
163
                    Object outputRowBuffer = outputBufferBand.createRowBuffer();
164
//                    outputBufferBand.fetchRow(row, outputRowBuffer);
165

    
166
                    rowProcessors[band].processRow(rowBuffer, bundle, outputRowBuffer);
167

    
168
                    outputBufferBand.putRow(row, outputRowBuffer);
169
                }
170
            } else {
171
                if(copyUnprocessedBands){
172
                    try {
173
                        this.outputBuffer.getBand(band).copyFrom(this.buffer.getBand(band));
174
                    } catch (BandException e) {
175
                        throw new ProcessingOperationException(e);
176
                    }
177
                }
178
            }
179
        }
180
    }
181

    
182
    @Override
183
    public void postProcess()  throws BufferOperationException {
184
        super.postProcess();
185
    }
186

    
187
    /**
188
     * @param band
189
     * @return
190
     */
191
    private boolean isProcessableBand(int band) {
192
        return bandsToProcess.contains(band);
193
    }
194

    
195

    
196

    
197
    interface RowProcessor {
198
        void processRow(Object inputRow, List<Object> bundleRow, Object outputRow);
199
        Number processValue(Number value, List<Number> kernel);
200
    };
201

    
202
    private abstract class AbstractRowProcessor implements RowProcessor {
203
        int band;
204
        NoData noData;
205

    
206
        public AbstractRowProcessor(int band) {
207
            this.band = band;
208
            noData = buffer.getBand(band).getNoData();
209
        }
210
    }
211

    
212
    private class ByteRowProcessor extends AbstractRowProcessor {
213

    
214

    
215
        public ByteRowProcessor(int band) {
216
            super(band);
217
        }
218

    
219
        @Override
220
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
221
            byte[] inputByteRow = (byte[])inputRow;
222
            byte[] outputByteRow = (byte[])outputRow;
223
            for (int i = 0; i < inputByteRow.length; i++) {
224
                List<Number> kernel = new ArrayList<Number>();
225
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
226
                    byte[] row = (byte[]) iterator.next();
227
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputByteRow.length-1);c++){
228
                        Integer value = 0xFF & ((Byte) row[c]).byteValue();
229
                        if(noData.isDefined() && noData.getValue().equals(value)){
230
                            continue;
231
                        } else {
232
                            kernel.add(value);
233
                        }
234
                    }
235
                }
236
                outputByteRow[i] = processValue(inputByteRow[i], kernel).byteValue();
237
            }
238
        }
239

    
240
        @Override
241
        public Number processValue(Number value, List<Number> kernel) {
242
            if(noData.isDefined() && noData.getValue().equals(value)){
243
                return (byte)value;
244
            }
245
            Collections.sort(kernel,new Comparator<Number>() {
246
                @Override
247
                public int compare(Number o1, Number o2) {
248
                    return o1.intValue()-o2.intValue();
249
                }
250
            });
251

    
252
            int n = kernel.size();
253
            int temp = n / 2;
254
            int pos;
255
            double temp0;
256
            if ( n % 2 == 0 ) {
257
                pos = (int)temp;
258
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
259
            } else { // if ( n % 2 == 1 )
260
                pos = (int)(temp + 0.5);
261
                temp0 = (double)(kernel.get(pos).intValue());
262
            }
263

    
264
          return (byte)(new Double(temp0).intValue() & 0xFF);
265

    
266
        }
267

    
268
    }
269

    
270
    private class ShortRowProcessor extends AbstractRowProcessor {
271

    
272
        public ShortRowProcessor(int band) {
273
            super(band);
274
        }
275

    
276
        @Override
277
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
278
            Number[] inputShortRow = (Number[])inputRow;
279
            short[] outputShortRow = (short[])outputRow;
280
            for (int i = 0; i < inputShortRow.length; i++) {
281
                List<Number> kernel = new ArrayList<Number>();
282
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
283
                    short[] row = (short[]) iterator.next();
284
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputShortRow.length-1);c++){
285
                        Short value = ((Short) row[c]).shortValue();
286
                        if(noData.isDefined() && noData.getValue().equals(value)){
287
                            continue;
288
                        } else {
289
                            kernel.add(value);
290
                        }
291
                        kernel.add(value);
292
                    }
293
                }
294
                outputShortRow[i] = processValue(inputShortRow[i], kernel).shortValue();
295
            }
296
        }
297

    
298
        @Override
299
        public Number processValue(Number value, List<Number> kernel) {
300
            if(noData.isDefined() && noData.getValue().equals(value)){
301
                return (short)value;
302
            }
303
            Collections.sort(kernel,new Comparator<Number>() {
304
                @Override
305
                public int compare(Number o1, Number o2) {
306
                    return ((Short)o1).compareTo((Short)o2);
307
                }
308
            });
309

    
310
            int n = kernel.size();
311
            int temp = n / 2;
312
            int pos;
313
            double temp0;
314
            if ( n % 2 == 0 ) {
315
                pos = (int)temp;
316
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
317
            } else { // if ( n % 2 == 1 )
318
                pos = (int)(temp + 0.5);
319
                temp0 = (double)(kernel.get(pos).intValue());
320
            }
321

    
322
          return (short)(new Double(temp0).intValue());
323
        }
324
    }
325

    
326
    private class UShortRowProcessor extends AbstractRowProcessor {
327

    
328
        public UShortRowProcessor(int band) {
329
            super(band);
330
        }
331

    
332
        @Override
333
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
334
            Number[] inputShortRow = (Number[])inputRow;
335
            short[] outputShortRow = (short[])outputRow;
336
            for (int i = 0; i < inputShortRow.length; i++) {
337
                List<Number> kernel = new ArrayList<Number>();
338
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
339
                    short[] row = (short[]) iterator.next();
340
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputShortRow.length-1);c++){
341
                        Integer value = 0xFFFF & ((Short) row[c]).shortValue();
342
                        if(noData.isDefined() && noData.getValue().equals(value)){
343
                            continue;
344
                        } else {
345
                            kernel.add(value);
346
                        }
347
                        kernel.add(value);
348
                    }
349
                }
350
                outputShortRow[i] = processValue(inputShortRow[i], kernel).shortValue();
351
            }
352
        }
353

    
354
        @Override
355
        public Number processValue(Number value, List<Number> kernel) {
356
            if(noData.isDefined() && noData.getValue().equals(value)){
357
                return (short)value;
358
            }
359
            Collections.sort(kernel,new Comparator<Number>() {
360
                @Override
361
                public int compare(Number o1, Number o2) {
362
                    return o1.intValue()-o2.intValue();
363
                }
364
            });
365

    
366
            int n = kernel.size();
367
            int temp = n / 2;
368
            int pos;
369
            double temp0;
370
            if ( n % 2 == 0 ) {
371
                pos = (int)temp;
372
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
373
            } else { // if ( n % 2 == 1 )
374
                pos = (int)(temp + 0.5);
375
                temp0 = (double)(kernel.get(pos).intValue());
376
            }
377

    
378
          return (short)(new Double(temp0).intValue() & 0xFFFF);
379
        }
380
    }
381

    
382
    private class IntRowProcessor extends AbstractRowProcessor {
383

    
384

    
385
        public IntRowProcessor(int band) {
386
            super(band);
387
        }
388

    
389
        @Override
390
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
391
            Number[] inputIntRow = (Number[])inputRow;
392
            int[] outputIntRow = (int[])outputRow;
393
            for (int i = 0; i < inputIntRow.length; i++) {
394
                List<Number> kernel = new ArrayList<Number>();
395
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
396
                    int[] row = (int[]) iterator.next();
397
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputIntRow.length-1);c++){
398
                        Integer value = ((Integer) row[c]).intValue();
399
                        if(noData.isDefined() && noData.getValue().equals(value)){
400
                            continue;
401
                        } else {
402
                            kernel.add(value);
403
                        }
404
                        kernel.add(value);
405
                    }
406
                }
407
                outputIntRow[i] = processValue(inputIntRow[i], kernel).intValue();
408
            }
409
        }
410

    
411
        @Override
412
        public Number processValue(Number value, List<Number> kernel) {
413
            if(noData.isDefined() && noData.getValue().equals(value)){
414
                return (int)value;
415
            }
416
            Collections.sort(kernel,new Comparator<Number>() {
417
                @Override
418
                public int compare(Number o1, Number o2) {
419
                    return ((Integer)o1).compareTo((Integer)o2);
420
                }
421
            });
422

    
423
            int n = kernel.size();
424
            int temp = n / 2;
425
            int pos;
426
            double temp0;
427
            if ( n % 2 == 0 ) {
428
                pos = (int)temp;
429
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
430
            } else { // if ( n % 2 == 1 )
431
                pos = (int)(temp + 0.5);
432
                temp0 = (double)(kernel.get(pos).intValue());
433
            }
434

    
435
          return new Double(temp0).intValue();
436

    
437
        }
438

    
439
    }
440
    private class FloatRowProcessor extends AbstractRowProcessor {
441

    
442

    
443
        public FloatRowProcessor(int band) {
444
            super(band);
445
        }
446

    
447
        @Override
448
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
449
            Number[] inputFloatRow = (Number[])inputRow;
450
            float[] outputFloatRow = (float[])outputRow;
451
            for (int i = 0; i < inputFloatRow.length; i++) {
452
                List<Number> kernel = new ArrayList<Number>();
453
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
454
                    float[] row = (float[]) iterator.next();
455
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputFloatRow.length-1);c++){
456
                        Float value = ((Float) row[c]).floatValue();
457
                        if(noData.isDefined() && noData.getValue().equals(value)){
458
                            continue;
459
                        } else {
460
                            kernel.add(value);
461
                        }
462
                        kernel.add(value);
463
                    }
464
                }
465
                outputFloatRow[i] = processValue(inputFloatRow[i], kernel).floatValue();
466
            }
467
        }
468

    
469
        @Override
470
        public Number processValue(Number value, List<Number> kernel) {
471
            if(noData.isDefined() && noData.getValue().equals(value)){
472
                return (float)value;
473
            }
474
            Collections.sort(kernel,new Comparator<Number>() {
475
                @Override
476
                public int compare(Number o1, Number o2) {
477
                    return ((Double)o1).compareTo((Double)o2);
478
                }
479
            });
480

    
481
            int n = kernel.size();
482
            int temp = n / 2;
483
            int pos;
484
            double temp0;
485
            if ( n % 2 == 0 ) {
486
                pos = (int)temp;
487
                temp0 = (double)(kernel.get(pos).doubleValue() + kernel.get(pos + 1).doubleValue())/2;
488
            } else { // if ( n % 2 == 1 )
489
                pos = (int)(temp + 0.5);
490
                temp0 = (double)(kernel.get(pos).doubleValue());
491
            }
492

    
493
          return new Double(temp0).floatValue();
494
        }
495

    
496
    }
497
    private class DoubleRowProcessor extends AbstractRowProcessor {
498

    
499

    
500
        public DoubleRowProcessor(int band) {
501
            super(band);
502
        }
503

    
504
        @Override
505
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
506
            Number[] inputDoubleRow = (Number[])inputRow;
507
            double[] outputDoubleRow = (double[])outputRow;
508
            for (int i = 0; i < inputDoubleRow.length; i++) {
509
                List<Number> kernel = new ArrayList<Number>();
510
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
511
                    double[] row = (double[]) iterator.next();
512
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputDoubleRow.length-1);c++){
513
                        Double value = ((Double) row[c]).doubleValue();
514
                        if(noData.isDefined() && noData.getValue().equals(value)){
515
                            continue;
516
                        } else {
517
                            kernel.add(value);
518
                        }
519
                        kernel.add(value);
520
                    }
521
                }
522
                outputDoubleRow[i] = processValue(inputDoubleRow[i], kernel).floatValue();
523
            }
524
        }
525

    
526
        @Override
527
        public Number processValue(Number value, List<Number> kernel) {
528
            if(noData.isDefined() && noData.getValue().equals(value)){
529
                return (double)value;
530
            }
531
            Collections.sort(kernel,new Comparator<Number>() {
532
                @Override
533
                public int compare(Number o1, Number o2) {
534
                    return ((Double)o1).compareTo((Double)o2);
535
                }
536
            });
537

    
538
            int n = kernel.size();
539
            int temp = n / 2;
540
            int pos;
541
            double temp0;
542
            if ( n % 2 == 0 ) {
543
                pos = (int)temp;
544
                temp0 = (double)(kernel.get(pos).doubleValue() + kernel.get(pos + 1).doubleValue())/2;
545
            } else { // if ( n % 2 == 1 )
546
                pos = (int)(temp + 0.5);
547
                temp0 = (double)(kernel.get(pos).doubleValue());
548
            }
549

    
550
          return temp0;
551
        }
552

    
553
    }
554

    
555
}