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

History | View | Annotate | Download (17.5 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
    /**
185
     * @param band
186
     * @return
187
     */
188
    private boolean isProcessableBand(int band) {
189
        return bandsToProcess.contains(band);
190
    }
191

    
192

    
193

    
194
    interface RowProcessor {
195
        void processRow(Object inputRow, List<Object> bundleRow, Object outputRow);
196
        Number processValue(Number value, List<Number> kernel);
197
    };
198

    
199
    private abstract class AbstractRowProcessor implements RowProcessor {
200
        int band;
201
        NoData noData;
202

    
203
        public AbstractRowProcessor(int band) {
204
            this.band = band;
205
            noData = buffer.getBand(band).getNoData();
206
            }
207
            }
208

    
209
    private class ByteRowProcessor extends AbstractRowProcessor {
210

    
211

    
212
        public ByteRowProcessor(int band) {
213
            super(band);
214
        }
215

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

    
237
        @Override
238
        public Number processValue(Number value, List<Number> kernel) {
239
            if (noData.isDefined() && noData.getValue().equals(value)) {
240
                return (byte) value;
241
            }
242
            return (byte) (mode(value, kernel).intValue() & 0xFF);
243

    
244
        }
245

    
246
    }
247

    
248
    private class ShortRowProcessor extends AbstractRowProcessor {
249

    
250
        public ShortRowProcessor(int band) {
251
            super(band);
252
        }
253

    
254
        @Override
255
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
256
            Number[] inputShortRow = (Number[])inputRow;
257
            short[] outputShortRow = (short[])outputRow;
258
            for (int i = 0; i < inputShortRow.length; i++) {
259
                List<Number> kernel = new ArrayList<Number>();
260
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
261
                    short[] row = (short[]) iterator.next();
262
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputShortRow.length-1);c++){
263
                        Short value = ((Short) row[c]).shortValue();
264
                        if(noData.isDefined() && noData.getValue().equals(value)){
265
                            continue;
266
                        } else {
267
                            kernel.add(value);
268
                        }
269
                        kernel.add(value);
270
                    }
271
                }
272
                outputShortRow[i] = processValue(inputShortRow[i], kernel).shortValue();
273
            }
274
        }
275

    
276
        @Override
277
        public Number processValue(Number value, List<Number> kernel) {
278
            if(noData.isDefined() && noData.getValue().equals(value)){
279
                return (short)value;
280
            }
281
          return (short)(mode(value, kernel).intValue());
282
        }
283
    }
284

    
285
    private class UShortRowProcessor extends AbstractRowProcessor {
286

    
287
        public UShortRowProcessor(int band) {
288
            super(band);
289
        }
290

    
291
        @Override
292
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
293
            Number[] inputShortRow = (Number[])inputRow;
294
            short[] outputShortRow = (short[])outputRow;
295
            for (int i = 0; i < inputShortRow.length; i++) {
296
                List<Number> kernel = new ArrayList<Number>();
297
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
298
                    short[] row = (short[]) iterator.next();
299
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputShortRow.length-1);c++){
300
                        Integer value = 0xFFFF & ((Short) row[c]).shortValue();
301
                        if(noData.isDefined() && noData.getValue().equals(value)){
302
                            continue;
303
                        } else {
304
                            kernel.add(value);
305
            }
306
                        kernel.add(value);
307
        }
308
                }
309
                outputShortRow[i] = processValue(inputShortRow[i], kernel).shortValue();
310
            }
311
        }
312

    
313
        @Override
314
        public Number processValue(Number value, List<Number> kernel) {
315
            if(noData.isDefined() && noData.getValue().equals(value)){
316
                return (short)value;
317
            }
318
          return (short)(mode(value, kernel).intValue() & 0xFFFF);
319
        }
320
    }
321

    
322
    private class IntRowProcessor extends AbstractRowProcessor {
323

    
324
        public IntRowProcessor(int band) {
325
            super(band);
326
        }
327

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

    
350
        @Override
351
        public Number processValue(Number value, List<Number> kernel) {
352
            if(noData.isDefined() && noData.getValue().equals(value)){
353
                return (int)value;
354
            }
355
          return mode(value, kernel).intValue();
356

    
357
        }
358

    
359
    }
360
    private class FloatRowProcessor extends AbstractRowProcessor {
361

    
362
        public FloatRowProcessor(int band) {
363
            super(band);
364
        }
365

    
366
        @Override
367
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
368
            Number[] inputFloatRow = (Number[])inputRow;
369
            float[] outputFloatRow = (float[])outputRow;
370
            for (int i = 0; i < inputFloatRow.length; i++) {
371
                List<Number> kernel = new ArrayList<Number>();
372
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
373
                    float[] row = (float[]) iterator.next();
374
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputFloatRow.length-1);c++){
375
                        Float value = ((Float) row[c]).floatValue();
376
                        if(noData.isDefined() && noData.getValue().equals(value)){
377
                            continue;
378
                        } else {
379
                            kernel.add(value);
380
                    }
381
                        kernel.add(value);
382
                }
383
                }
384
                outputFloatRow[i] = processValue(inputFloatRow[i], kernel).floatValue();
385
            }
386
        }
387

    
388
        @Override
389
        public Number processValue(Number value, List<Number> kernel) {
390
            if (noData.isDefined() && noData.getValue().equals(value)) {
391
                return (float) value;
392
            }
393
            return mode(value, kernel).floatValue();
394
        }
395

    
396
    }
397
    private class DoubleRowProcessor extends AbstractRowProcessor {
398

    
399

    
400
        public DoubleRowProcessor(int band) {
401
            super(band);
402
        }
403

    
404
        @Override
405
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
406
            Number[] inputDoubleRow = (Number[])inputRow;
407
            double[] outputDoubleRow = (double[])outputRow;
408
            for (int i = 0; i < inputDoubleRow.length; i++) {
409
                List<Number> kernel = new ArrayList<Number>();
410
                for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
411
                    double[] row = (double[]) iterator.next();
412
                    for(int c=Math.max(i-halfSideWindow,0); c<=Math.min(i+halfSideWindow,inputDoubleRow.length-1);c++){
413
                        Double value = ((Double) row[c]).doubleValue();
414
                        if(noData.isDefined() && noData.getValue().equals(value)){
415
                            continue;
416
                        } else {
417
                            kernel.add(value);
418
                        }
419
                        kernel.add(value);
420
                    }
421
                }
422
                outputDoubleRow[i] = processValue(inputDoubleRow[i], kernel).floatValue();
423
            }
424
        }
425

    
426
        @Override
427
        public Number processValue(Number value, List<Number> kernel) {
428
            if (noData.isDefined() && noData.getValue().equals(value)) {
429
                return (double) value;
430
            }
431
            return mode(value, kernel).doubleValue();
432
        }
433

    
434
    }
435

    
436
    private Number mode(Number value, List<Number> kernel) {
437

    
438
        Number maxValue = null;
439
        int maxCount = 0;
440

    
441
        Number[] kernelArray = kernel.toArray(new Number[0]);
442

    
443
        for (int i = 0; i < kernelArray.length; ++i) {
444
            int count = 0;
445
            for (int j = 0; j < kernelArray.length; ++j) {
446
                if (kernelArray[j] == kernelArray[i]) ++count;
447
            }
448
            if (count > maxCount) {
449
                maxCount = count;
450
                maxValue = kernelArray[i];
451
            }
452
        }
453
        return maxValue;
454
    }
455

    
456
}