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

History | View | Annotate | Download (20.9 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
    interface RowProcessor {
188
        void processRow(Object inputRow, List<Object> bundleRow, Object outputRow);
189
        Number processValue(Number value, List<Number> kernel);
190
    };
191

    
192
    private abstract class AbstractRowProcessor implements RowProcessor {
193
        int band;
194
        NoData noData;
195

    
196
        public AbstractRowProcessor(int band) {
197
            this.band = band;
198
            noData = buffer.getBand(band).getNoData();
199
        }
200
    }
201

    
202
    private class ByteRowProcessor extends AbstractRowProcessor {
203

    
204

    
205
        public ByteRowProcessor(int band) {
206
            super(band);
207
        }
208

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

    
230
        @Override
231
        public Number processValue(Number value, List<Number> kernel) {
232
            if(noData.isDefined() && noData.getValue().equals(value)){
233
                return (byte)value;
234
            }
235
            Collections.sort(kernel,new Comparator<Number>() {
236
                @Override
237
                public int compare(Number o1, Number o2) {
238
                    return o1.intValue()-o2.intValue();
239
                }
240
            });
241

    
242
            int n = kernel.size();
243
            int temp = n / 2;
244
            int pos;
245
            double temp0;
246
            if ( n % 2 == 0 ) {
247
                pos = (int)temp;
248
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
249
            } else { // if ( n % 2 == 1 )
250
                pos = (int)(temp + 0.5);
251
                temp0 = (double)(kernel.get(pos).intValue());
252
            }
253

    
254
          return (byte)(new Double(temp0).intValue() & 0xFF);
255

    
256
        }
257

    
258
    }
259

    
260
    private class ShortRowProcessor extends AbstractRowProcessor {
261

    
262
        public ShortRowProcessor(int band) {
263
            super(band);
264
        }
265

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

    
288
        @Override
289
        public Number processValue(Number value, List<Number> kernel) {
290
            if(noData.isDefined() && noData.getValue().equals(value)){
291
                return (short)value;
292
            }
293
            Collections.sort(kernel,new Comparator<Number>() {
294
                @Override
295
                public int compare(Number o1, Number o2) {
296
                    return ((Short)o1).compareTo((Short)o2);
297
                }
298
            });
299

    
300
            int n = kernel.size();
301
            int temp = n / 2;
302
            int pos;
303
            double temp0;
304
            if ( n % 2 == 0 ) {
305
                pos = (int)temp;
306
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
307
            } else { // if ( n % 2 == 1 )
308
                pos = (int)(temp + 0.5);
309
                temp0 = (double)(kernel.get(pos).intValue());
310
            }
311

    
312
          return (short)(new Double(temp0).intValue());
313
        }
314
    }
315

    
316
    private class UShortRowProcessor extends AbstractRowProcessor {
317

    
318
        public UShortRowProcessor(int band) {
319
            super(band);
320
        }
321

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

    
344
        @Override
345
        public Number processValue(Number value, List<Number> kernel) {
346
            if(noData.isDefined() && noData.getValue().equals(value)){
347
                return (short)value;
348
            }
349
            Collections.sort(kernel,new Comparator<Number>() {
350
                @Override
351
                public int compare(Number o1, Number o2) {
352
                    return o1.intValue()-o2.intValue();
353
                }
354
            });
355

    
356
            int n = kernel.size();
357
            int temp = n / 2;
358
            int pos;
359
            double temp0;
360
            if ( n % 2 == 0 ) {
361
                pos = (int)temp;
362
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
363
            } else { // if ( n % 2 == 1 )
364
                pos = (int)(temp + 0.5);
365
                temp0 = (double)(kernel.get(pos).intValue());
366
            }
367

    
368
          return (short)(new Double(temp0).intValue() & 0xFFFF);
369
        }
370
    }
371

    
372
    private class IntRowProcessor extends AbstractRowProcessor {
373

    
374

    
375
        public IntRowProcessor(int band) {
376
            super(band);
377
        }
378

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

    
401
        @Override
402
        public Number processValue(Number value, List<Number> kernel) {
403
            if(noData.isDefined() && noData.getValue().equals(value)){
404
                return (int)value;
405
            }
406
            Collections.sort(kernel,new Comparator<Number>() {
407
                @Override
408
                public int compare(Number o1, Number o2) {
409
                    return ((Integer)o1).compareTo((Integer)o2);
410
                }
411
            });
412

    
413
            int n = kernel.size();
414
            int temp = n / 2;
415
            int pos;
416
            double temp0;
417
            if ( n % 2 == 0 ) {
418
                pos = (int)temp;
419
                temp0 = (double)(kernel.get(pos).intValue() + kernel.get(pos + 1).intValue())/2;
420
            } else { // if ( n % 2 == 1 )
421
                pos = (int)(temp + 0.5);
422
                temp0 = (double)(kernel.get(pos).intValue());
423
            }
424

    
425
          return new Double(temp0).intValue();
426

    
427
        }
428

    
429
    }
430
    private class FloatRowProcessor extends AbstractRowProcessor {
431

    
432

    
433
        public FloatRowProcessor(int band) {
434
            super(band);
435
        }
436

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

    
459
        @Override
460
        public Number processValue(Number value, List<Number> kernel) {
461
            if(noData.isDefined() && noData.getValue().equals(value)){
462
                return (float)value;
463
            }
464
            Collections.sort(kernel,new Comparator<Number>() {
465
                @Override
466
                public int compare(Number o1, Number o2) {
467
                    return ((Double)o1).compareTo((Double)o2);
468
                }
469
            });
470

    
471
            int n = kernel.size();
472
            int temp = n / 2;
473
            int pos;
474
            double temp0;
475
            if ( n % 2 == 0 ) {
476
                pos = (int)temp;
477
                temp0 = (double)(kernel.get(pos).doubleValue() + kernel.get(pos + 1).doubleValue())/2;
478
            } else { // if ( n % 2 == 1 )
479
                pos = (int)(temp + 0.5);
480
                temp0 = (double)(kernel.get(pos).doubleValue());
481
            }
482

    
483
          return new Double(temp0).floatValue();
484
        }
485

    
486
    }
487
    private class DoubleRowProcessor extends AbstractRowProcessor {
488

    
489

    
490
        public DoubleRowProcessor(int band) {
491
            super(band);
492
        }
493

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

    
516
        @Override
517
        public Number processValue(Number value, List<Number> kernel) {
518
            if(noData.isDefined() && noData.getValue().equals(value)){
519
                return (double)value;
520
            }
521
            Collections.sort(kernel,new Comparator<Number>() {
522
                @Override
523
                public int compare(Number o1, Number o2) {
524
                    return ((Double)o1).compareTo((Double)o2);
525
                }
526
            });
527

    
528
            int n = kernel.size();
529
            int temp = n / 2;
530
            int pos;
531
            double temp0;
532
            if ( n % 2 == 0 ) {
533
                pos = (int)temp;
534
                temp0 = (double)(kernel.get(pos).doubleValue() + kernel.get(pos + 1).doubleValue())/2;
535
            } else { // if ( n % 2 == 1 )
536
                pos = (int)(temp + 0.5);
537
                temp0 = (double)(kernel.get(pos).doubleValue());
538
            }
539

    
540
          return temp0;
541
        }
542

    
543
    }
544

    
545
}