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

History | View | Annotate | Download (17.3 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.fmap.geom.exception.CreateEnvelopeException;
30
import org.gvsig.raster.lib.buffer.api.Band;
31
import org.gvsig.raster.lib.buffer.api.BufferLocator;
32
import org.gvsig.raster.lib.buffer.api.BufferManager;
33
import org.gvsig.raster.lib.buffer.api.NoData;
34
import org.gvsig.raster.lib.buffer.api.exceptions.BandException;
35
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
36
import org.gvsig.raster.lib.buffer.api.exceptions.BufferOperationException;
37
import org.gvsig.raster.lib.buffer.api.operations.OperationFactory;
38
import org.gvsig.raster.lib.buffer.api.statistics.Statistics;
39
import org.gvsig.raster.lib.buffer.spi.exceptions.ProcessingOperationException;
40
import org.gvsig.raster.lib.buffer.spi.operations.AbstractSpecifiedBandsOperation;
41
import org.gvsig.tools.locator.LocatorException;
42

    
43

    
44
/**
45
 * @author fdiaz
46
 *
47
 */
48
public class ModeOperation extends AbstractSpecifiedBandsOperation{
49

    
50
//    static public String STATISTICS_PARAM = "statistics";
51
    static public String SIDE_WINDOW_PARAM = "side_window";
52

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

    
58
    /**
59
     * @param factory
60
     *
61
     */
62
    public ModeOperation(OperationFactory factory) {
63
        this.factory = factory;
64
    }
65

    
66
    @Override
67
    public void preProcess() throws BufferOperationException {
68
        super.preProcess();
69
        BufferManager manager = BufferLocator.getBufferManager();
70

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

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

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

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

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

    
160
                    Object outputRowBuffer = outputBufferBand.createRowBuffer();
161
//                    outputBufferBand.fetchRow(row, outputRowBuffer);
162

    
163
                    rowProcessors[band].processRow(rowBuffer, bundle, outputRowBuffer);
164

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

    
179
    @Override
180
    public void postProcess()  throws BufferOperationException {
181
        super.postProcess();
182
    }
183

    
184
    interface RowProcessor {
185
        void processRow(Object inputRow, List<Object> bundleRow, Object outputRow);
186
        Number processValue(Number value, List<Number> kernel);
187
    };
188

    
189
    private abstract class AbstractRowProcessor implements RowProcessor {
190
        int band;
191
        NoData noData;
192

    
193
        public AbstractRowProcessor(int band) {
194
            this.band = band;
195
            noData = buffer.getBand(band).getNoData();
196
            }
197
            }
198

    
199
    private class ByteRowProcessor extends AbstractRowProcessor {
200

    
201

    
202
        public ByteRowProcessor(int band) {
203
            super(band);
204
        }
205

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

    
227
        @Override
228
        public Number processValue(Number value, List<Number> kernel) {
229
            if (noData.isDefined() && noData.getValue().equals(value)) {
230
                return (byte) value;
231
            }
232
            return (byte) (mode(value, kernel).intValue() & 0xFF);
233

    
234
        }
235

    
236
    }
237

    
238
    private class ShortRowProcessor extends AbstractRowProcessor {
239

    
240
        public ShortRowProcessor(int band) {
241
            super(band);
242
        }
243

    
244
        @Override
245
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
246
            Number[] inputShortRow = (Number[])inputRow;
247
            short[] outputShortRow = (short[])outputRow;
248
            for (int i = 0; i < inputShortRow.length; i++) {
249
                List<Number> kernel = new ArrayList<Number>();
250
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
251
                    short[] row = (short[]) iterator.next();
252
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputShortRow.length-1);c++){
253
                        Short value = ((Short) row[c]).shortValue();
254
                        if(noData.isDefined() && noData.getValue().equals(value)){
255
                            continue;
256
                        } else {
257
                            kernel.add(value);
258
                        }
259
                        kernel.add(value);
260
                    }
261
                }
262
                outputShortRow[i] = processValue(inputShortRow[i], kernel).shortValue();
263
            }
264
        }
265

    
266
        @Override
267
        public Number processValue(Number value, List<Number> kernel) {
268
            if(noData.isDefined() && noData.getValue().equals(value)){
269
                return (short)value;
270
            }
271
          return (short)(mode(value, kernel).intValue());
272
        }
273
    }
274

    
275
    private class UShortRowProcessor extends AbstractRowProcessor {
276

    
277
        public UShortRowProcessor(int band) {
278
            super(band);
279
        }
280

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

    
303
        @Override
304
        public Number processValue(Number value, List<Number> kernel) {
305
            if(noData.isDefined() && noData.getValue().equals(value)){
306
                return (short)value;
307
            }
308
          return (short)(mode(value, kernel).intValue() & 0xFFFF);
309
        }
310
    }
311

    
312
    private class IntRowProcessor extends AbstractRowProcessor {
313

    
314
        public IntRowProcessor(int band) {
315
            super(band);
316
        }
317

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

    
340
        @Override
341
        public Number processValue(Number value, List<Number> kernel) {
342
            if(noData.isDefined() && noData.getValue().equals(value)){
343
                return (int)value;
344
            }
345
          return mode(value, kernel).intValue();
346

    
347
        }
348

    
349
    }
350
    private class FloatRowProcessor extends AbstractRowProcessor {
351

    
352
        public FloatRowProcessor(int band) {
353
            super(band);
354
        }
355

    
356
        @Override
357
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
358
            Number[] inputFloatRow = (Number[])inputRow;
359
            float[] outputFloatRow = (float[])outputRow;
360
            for (int i = 0; i < inputFloatRow.length; i++) {
361
                List<Number> kernel = new ArrayList<Number>();
362
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
363
                    float[] row = (float[]) iterator.next();
364
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputFloatRow.length-1);c++){
365
                        Float value = ((Float) row[c]).floatValue();
366
                        if(noData.isDefined() && noData.getValue().equals(value)){
367
                            continue;
368
                        } else {
369
                            kernel.add(value);
370
                    }
371
                        kernel.add(value);
372
                }
373
                }
374
                outputFloatRow[i] = processValue(inputFloatRow[i], kernel).floatValue();
375
            }
376
        }
377

    
378
        @Override
379
        public Number processValue(Number value, List<Number> kernel) {
380
            if (noData.isDefined() && noData.getValue().equals(value)) {
381
                return (float) value;
382
            }
383
            return mode(value, kernel).floatValue();
384
        }
385

    
386
    }
387
    private class DoubleRowProcessor extends AbstractRowProcessor {
388

    
389

    
390
        public DoubleRowProcessor(int band) {
391
            super(band);
392
        }
393

    
394
        @Override
395
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
396
            Number[] inputDoubleRow = (Number[])inputRow;
397
            double[] outputDoubleRow = (double[])outputRow;
398
            for (int i = 0; i < inputDoubleRow.length; i++) {
399
                List<Number> kernel = new ArrayList<Number>();
400
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
401
                    double[] row = (double[]) iterator.next();
402
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputDoubleRow.length-1);c++){
403
                        Double value = ((Double) row[c]).doubleValue();
404
                        if(noData.isDefined() && noData.getValue().equals(value)){
405
                            continue;
406
                        } else {
407
                            kernel.add(value);
408
                        }
409
                        kernel.add(value);
410
                    }
411
                }
412
                outputDoubleRow[i] = processValue(inputDoubleRow[i], kernel).floatValue();
413
            }
414
        }
415

    
416
        @Override
417
        public Number processValue(Number value, List<Number> kernel) {
418
            if (noData.isDefined() && noData.getValue().equals(value)) {
419
                return (double) value;
420
            }
421
            return mode(value, kernel).doubleValue();
422
        }
423

    
424
    }
425

    
426
    private Number mode(Number value, List<Number> kernel) {
427

    
428
        Number maxValue = null;
429
        int maxCount = 0;
430

    
431
        Number[] kernelArray = kernel.toArray(new Number[0]);
432

    
433
        for (int i = 0; i < kernelArray.length; ++i) {
434
            int count = 0;
435
            for (int j = 0; j < kernelArray.length; ++j) {
436
                if (kernelArray[j] == kernelArray[i]) ++count;
437
            }
438
            if (count > maxCount) {
439
                maxCount = count;
440
                maxValue = kernelArray[i];
441
            }
442
        }
443
        return maxValue;
444
    }
445

    
446
}