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 43803 fdiaz
/* 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 43864 jjdelcerro
        super(factory);
61 43803 fdiaz
    }
62 43864 jjdelcerro
63 43803 fdiaz
    @Override
64
    public void preProcess() throws BufferOperationException {
65
        super.preProcess();
66
        BufferManager manager = BufferLocator.getBufferManager();
67
68 43864 jjdelcerro
        sideWindow = (int) this.getParameter(SIDE_WINDOW_PARAM, 3);
69 43803 fdiaz
        halfSideWindow = (int)(sideWindow/2);
70
71 43864 jjdelcerro
        if (mustCopyUnprocessedBands()) {
72 43803 fdiaz
            try {
73 43864 jjdelcerro
                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 43803 fdiaz
                throw new ProcessingOperationException(e);
83
            }
84 43864 jjdelcerro
        } else {
85 43803 fdiaz
            try {
86 43864 jjdelcerro
                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 43803 fdiaz
                throw new ProcessingOperationException(e);
96
            }
97
        }
98
99 43864 jjdelcerro
        int bands = this.getInputBuffer().getBandCount();
100 43803 fdiaz
        rowProcessors = new RowProcessor[bands];
101 43864 jjdelcerro
        for (int band = 0; band < bands; band++) {
102 43803 fdiaz
            if (isProcessableBand(band)) {
103 43864 jjdelcerro
            int bandType = this.getInputBuffer().getBand(band).getDataType();
104 43803 fdiaz
            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 43864 jjdelcerro
        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 43803 fdiaz
138 43864 jjdelcerro
                for (int row = 0; row < this.getInputBuffer().getRows(); row++) {
139 43803 fdiaz
                    Object rowBuffer = bufferBand.createRowBuffer();
140
                    bufferBand.fetchRow(row, rowBuffer);
141 43864 jjdelcerro
                    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 43803 fdiaz
                        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 43864 jjdelcerro
                if(mustCopyUnprocessedBands()){
158 43803 fdiaz
                try {
159 43864 jjdelcerro
                    this.getOutputBuffer().getBand(band).copyFrom(this.getInputBuffer().getBand(band));
160 43803 fdiaz
                } 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 43864 jjdelcerro
            noData = getInputBuffer().getBand(band).getNoData();
185 43803 fdiaz
            }
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 43864 jjdelcerro
                List<Number> kernel = new ArrayList<>();
201 43803 fdiaz
                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 43864 jjdelcerro
                        Integer value = 0xFF & ((Byte) row[c]);
205 43803 fdiaz
                        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
}