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 / mode / ModeOperation.java @ 43864

History | View | Annotate | Download (16.7 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.mode;
24

    
25
import java.util.ArrayList;
26
import java.util.Iterator;
27
import java.util.List;
28

    
29
import org.gvsig.raster.lib.buffer.api.Band;
30
import org.gvsig.raster.lib.buffer.api.BufferLocator;
31
import org.gvsig.raster.lib.buffer.api.BufferManager;
32
import org.gvsig.raster.lib.buffer.api.NoData;
33
import org.gvsig.raster.lib.buffer.api.exceptions.BandException;
34
import org.gvsig.raster.lib.buffer.api.exceptions.BufferOperationException;
35
import org.gvsig.raster.lib.buffer.api.operations.OperationFactory;
36
import org.gvsig.raster.lib.buffer.api.statistics.Statistics;
37
import org.gvsig.raster.lib.buffer.spi.exceptions.ProcessingOperationException;
38
import org.gvsig.raster.lib.buffer.spi.operations.AbstractSpecifiedBandsOperation;
39

    
40

    
41
/**
42
 * @author fdiaz
43
 *
44
 */
45
public class ModeOperation extends AbstractSpecifiedBandsOperation{
46

    
47
//    static public String STATISTICS_PARAM = "statistics";
48
    static public String SIDE_WINDOW_PARAM = "side_window";
49

    
50
    private Statistics statistics;
51
    private int sideWindow;
52
    private RowProcessor[] rowProcessors;
53
    private int halfSideWindow;
54

    
55
    /**
56
     * @param factory
57
     *
58
     */
59
    public ModeOperation(OperationFactory factory) {
60
        super(factory);
61
    }
62
    
63
    @Override
64
    public void preProcess() throws BufferOperationException {
65
        super.preProcess();
66
        BufferManager manager = BufferLocator.getBufferManager();
67

    
68
        sideWindow = (int) this.getParameter(SIDE_WINDOW_PARAM, 3);
69
        halfSideWindow = (int)(sideWindow/2);
70

    
71
        if (mustCopyUnprocessedBands()) {
72
            try {
73
                this.setOutputBuffer(
74
                    manager.createBuffer(
75
                            this.getInputBuffer().getRows(), 
76
                            this.getInputBuffer().getColumns(), 
77
                            this.getInputBuffer().getBandTypes(),
78
                            this.getInputBuffer().getBandNoData(), 
79
                            this.getInputBuffer().getProjection(), 
80
                            this.getInputBuffer().getEnvelope()));
81
            } catch (Exception e) {
82
                throw new ProcessingOperationException(e);
83
            }
84
        } else {
85
            try {
86
                this.setOutputBuffer(
87
                    manager.createBuffer(
88
                            this.getInputBuffer().getRows(), 
89
                            this.getInputBuffer().getColumns(), 
90
                            this.getProcessableBandTypesAsArray(),
91
                            this.getProcessableBandNoDatasAsArray(), 
92
                            this.getInputBuffer().getProjection(),
93
                            this.getInputBuffer().getEnvelope()));
94
            } catch (Exception e) {
95
                throw new ProcessingOperationException(e);
96
            }
97
        }
98

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

    
130
    @Override
131
    public void process() throws ProcessingOperationException {
132
        super.process();
133
        for (int band=0; band<this.getInputBuffer().getBandCount(); band++){
134
            if (getBandsToProcess().contains(band)) {
135
                Band bufferBand = this.getInputBuffer().getBand(band);
136
                Band outputBufferBand = this.getOutputBuffer().getBand(band);
137

    
138
                for (int row = 0; row < this.getInputBuffer().getRows(); row++) {
139
                    Object rowBuffer = bufferBand.createRowBuffer();
140
                    bufferBand.fetchRow(row, rowBuffer);
141
                    List<Object> bundle = new ArrayList<>();
142
                    int maxr = Math.min(row+halfSideWindow,this.getInputBuffer().getRows()-1);
143
                    for(int r=Math.max(row-halfSideWindow,0); r<=maxr;r++){
144
                        Object bundleRow = bufferBand.createRowBuffer();
145
                        bufferBand.fetchRow(row, bundleRow);
146
                        bundle.add(bundleRow);
147
                    }
148

    
149
                    Object outputRowBuffer = outputBufferBand.createRowBuffer();
150
//                    outputBufferBand.fetchRow(row, outputRowBuffer);
151

    
152
                    rowProcessors[band].processRow(rowBuffer, bundle, outputRowBuffer);
153

    
154
                    outputBufferBand.putRow(row, outputRowBuffer);
155
                }
156
            } else {
157
                if(mustCopyUnprocessedBands()){
158
                try {
159
                    this.getOutputBuffer().getBand(band).copyFrom(this.getInputBuffer().getBand(band));
160
                } catch (BandException e) {
161
                    throw new ProcessingOperationException(e);
162
                }
163
            }
164
        }
165
    }
166
    }
167

    
168
    @Override
169
    public void postProcess()  throws BufferOperationException {
170
        super.postProcess();
171
    }
172

    
173
    interface RowProcessor {
174
        void processRow(Object inputRow, List<Object> bundleRow, Object outputRow);
175
        Number processValue(Number value, List<Number> kernel);
176
    };
177

    
178
    private abstract class AbstractRowProcessor implements RowProcessor {
179
        int band;
180
        NoData noData;
181

    
182
        public AbstractRowProcessor(int band) {
183
            this.band = band;
184
            noData = getInputBuffer().getBand(band).getNoData();
185
            }
186
            }
187

    
188
    private class ByteRowProcessor extends AbstractRowProcessor {
189

    
190

    
191
        public ByteRowProcessor(int band) {
192
            super(band);
193
        }
194

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

    
216
        @Override
217
        public Number processValue(Number value, List<Number> kernel) {
218
            if (noData.isDefined() && noData.getValue().equals(value)) {
219
                return (byte) value;
220
            }
221
            return (byte) (mode(value, kernel).intValue() & 0xFF);
222

    
223
        }
224

    
225
    }
226

    
227
    private class ShortRowProcessor extends AbstractRowProcessor {
228

    
229
        public ShortRowProcessor(int band) {
230
            super(band);
231
        }
232

    
233
        @Override
234
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
235
            Number[] inputShortRow = (Number[])inputRow;
236
            short[] outputShortRow = (short[])outputRow;
237
            for (int i = 0; i < inputShortRow.length; i++) {
238
                List<Number> kernel = new ArrayList<Number>();
239
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
240
                    short[] row = (short[]) iterator.next();
241
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputShortRow.length-1);c++){
242
                        Short value = ((Short) row[c]).shortValue();
243
                        if(noData.isDefined() && noData.getValue().equals(value)){
244
                            continue;
245
                        } else {
246
                            kernel.add(value);
247
                        }
248
                        kernel.add(value);
249
                    }
250
                }
251
                outputShortRow[i] = processValue(inputShortRow[i], kernel).shortValue();
252
            }
253
        }
254

    
255
        @Override
256
        public Number processValue(Number value, List<Number> kernel) {
257
            if(noData.isDefined() && noData.getValue().equals(value)){
258
                return (short)value;
259
            }
260
          return (short)(mode(value, kernel).intValue());
261
        }
262
    }
263

    
264
    private class UShortRowProcessor extends AbstractRowProcessor {
265

    
266
        public UShortRowProcessor(int band) {
267
            super(band);
268
        }
269

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

    
292
        @Override
293
        public Number processValue(Number value, List<Number> kernel) {
294
            if(noData.isDefined() && noData.getValue().equals(value)){
295
                return (short)value;
296
            }
297
          return (short)(mode(value, kernel).intValue() & 0xFFFF);
298
        }
299
    }
300

    
301
    private class IntRowProcessor extends AbstractRowProcessor {
302

    
303
        public IntRowProcessor(int band) {
304
            super(band);
305
        }
306

    
307
        @Override
308
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
309
            Number[] inputIntRow = (Number[])inputRow;
310
            int[] outputIntRow = (int[])outputRow;
311
            for (int i = 0; i < inputIntRow.length; i++) {
312
                List<Number> kernel = new ArrayList<Number>();
313
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
314
                    int[] row = (int[]) iterator.next();
315
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputIntRow.length-1);c++){
316
                        Integer value = ((Integer) row[c]).intValue();
317
                        if(noData.isDefined() && noData.getValue().equals(value)){
318
                            continue;
319
                        } else {
320
                            kernel.add(value);
321
                    }
322
                        kernel.add(value);
323
                    }
324
                }
325
                outputIntRow[i] = processValue(inputIntRow[i], kernel).intValue();
326
            }
327
        }
328

    
329
        @Override
330
        public Number processValue(Number value, List<Number> kernel) {
331
            if(noData.isDefined() && noData.getValue().equals(value)){
332
                return (int)value;
333
            }
334
          return mode(value, kernel).intValue();
335

    
336
        }
337

    
338
    }
339
    private class FloatRowProcessor extends AbstractRowProcessor {
340

    
341
        public FloatRowProcessor(int band) {
342
            super(band);
343
        }
344

    
345
        @Override
346
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
347
            Number[] inputFloatRow = (Number[])inputRow;
348
            float[] outputFloatRow = (float[])outputRow;
349
            for (int i = 0; i < inputFloatRow.length; i++) {
350
                List<Number> kernel = new ArrayList<Number>();
351
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
352
                    float[] row = (float[]) iterator.next();
353
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputFloatRow.length-1);c++){
354
                        Float value = ((Float) row[c]).floatValue();
355
                        if(noData.isDefined() && noData.getValue().equals(value)){
356
                            continue;
357
                        } else {
358
                            kernel.add(value);
359
                    }
360
                        kernel.add(value);
361
                }
362
                }
363
                outputFloatRow[i] = processValue(inputFloatRow[i], kernel).floatValue();
364
            }
365
        }
366

    
367
        @Override
368
        public Number processValue(Number value, List<Number> kernel) {
369
            if (noData.isDefined() && noData.getValue().equals(value)) {
370
                return (float) value;
371
            }
372
            return mode(value, kernel).floatValue();
373
        }
374

    
375
    }
376
    private class DoubleRowProcessor extends AbstractRowProcessor {
377

    
378

    
379
        public DoubleRowProcessor(int band) {
380
            super(band);
381
        }
382

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

    
405
        @Override
406
        public Number processValue(Number value, List<Number> kernel) {
407
            if (noData.isDefined() && noData.getValue().equals(value)) {
408
                return (double) value;
409
            }
410
            return mode(value, kernel).doubleValue();
411
        }
412

    
413
    }
414

    
415
    private Number mode(Number value, List<Number> kernel) {
416

    
417
        Number maxValue = null;
418
        int maxCount = 0;
419

    
420
        Number[] kernelArray = kernel.toArray(new Number[0]);
421

    
422
        for (int i = 0; i < kernelArray.length; ++i) {
423
            int count = 0;
424
            for (int j = 0; j < kernelArray.length; ++j) {
425
                if (kernelArray[j] == kernelArray[i]) ++count;
426
            }
427
            if (count > maxCount) {
428
                maxCount = count;
429
                maxValue = kernelArray[i];
430
            }
431
        }
432
        return maxValue;
433
    }
434

    
435
}