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 / linearstretchenhancement / LinearStretchEnhancementOperation.java @ 43864

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

    
25
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
26
import org.gvsig.raster.lib.buffer.api.Band;
27
import org.gvsig.raster.lib.buffer.api.BufferLocator;
28
import org.gvsig.raster.lib.buffer.api.BufferManager;
29
import org.gvsig.raster.lib.buffer.api.NoData;
30
import org.gvsig.raster.lib.buffer.api.exceptions.BandException;
31
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
32
import org.gvsig.raster.lib.buffer.api.exceptions.BufferOperationException;
33
import org.gvsig.raster.lib.buffer.api.operations.OperationFactory;
34
import org.gvsig.raster.lib.buffer.api.statistics.Statistics;
35
import org.gvsig.raster.lib.buffer.impl.DefaultNoData;
36
import org.gvsig.raster.lib.buffer.spi.exceptions.ProcessingOperationException;
37
import org.gvsig.raster.lib.buffer.spi.operations.AbstractSpecifiedBandsOperation;
38
import org.gvsig.tools.locator.LocatorException;
39

    
40

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

    
47
    static public String STATISTICS_PARAM = "statistics";
48
    static public String REMOVE_ENDS_PARAM = "remove_ends";
49
    static public String TAIL_TRIM_PARAM = "tail_trim";
50
    static public String TAIL_TRIM_PERCENT_PARAM = "tail_trim_percent";
51

    
52
    private Statistics statistics;
53
    private boolean removeEnds;
54
    private boolean tailTrim;
55
    private double tailTrimPercent;
56
    private RowProcessor[] rowProcessors;
57

    
58
    /**
59
     * @param factory
60
     *
61
     */
62
    public LinearStretchEnhancementOperation(OperationFactory factory) {
63
        super(factory);
64
    }
65

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

    
71
        statistics = (Statistics) this.getParameter(STATISTICS_PARAM, null);
72
        if (statistics == null) {
73
            statistics = this.getInputBuffer().getStatistics(null);
74
        }
75
        removeEnds = (boolean) this.getParameter(REMOVE_ENDS_PARAM, false);
76
        tailTrim = (boolean) this.getParameter(TAIL_TRIM_PARAM, false);
77
        tailTrimPercent = (double) this.getParameter(TAIL_TRIM_PERCENT_PARAM, 0);
78
        tailTrimPercent = (tailTrimPercent>100)?100:tailTrimPercent;
79
        tailTrimPercent = (tailTrimPercent<0)?0:tailTrimPercent;
80

    
81
        int bands = this.getInputBuffer().getBandCount();
82
        rowProcessors = new RowProcessor[bands];
83
        int [] bandTypes = new int[bands];
84
        //FIXME: Falta la gesti?n del par?metro copyUnprocessedBands, de momento se copian sin tenerlo en cuenta
85
        for (int i = 0; i < bandTypes.length; i++) {
86
            if(this.getBandsToProcess().contains(i)){
87
                bandTypes[i] = BufferManager.TYPE_BYTE;
88
            } else {
89
                bandTypes[i] = this.getInputBuffer().getBandTypes()[i];
90
            }
91
        }
92
        NoData[] noData = this.getInputBuffer().getBandNoData();
93
        NoData[] resultNoData = new NoData[noData.length];
94
        for (int band = 0; band < noData.length; band++) {
95
            int bandType = this.getInputBuffer().getBand(band).getDataType();
96
            switch (bandType) {
97
            case BufferManager.TYPE_BYTE:
98
                rowProcessors[band] = new ByteRowProcessor(band);
99
                break;
100
            case BufferManager.TYPE_USHORT:
101
                rowProcessors[band] = new UShortRowProcessor(band);
102
                break;
103
            case BufferManager.TYPE_SHORT:
104
                rowProcessors[band] = new ShortRowProcessor(band);
105
                break;
106
            case BufferManager.TYPE_INT:
107
                rowProcessors[band] = new IntRowProcessor(band);
108
                break;
109
            case BufferManager.TYPE_FLOAT:
110
                rowProcessors[band] = new FloatRowProcessor(band);
111
                break;
112
            case BufferManager.TYPE_DOUBLE:
113
                rowProcessors[band] = new DoubleRowProcessor(band);
114
                break;
115
            default:
116
                throw new IllegalArgumentException("Unknow type of band '"+band+"'");
117
            }
118

    
119
            if(noData[band].isDefined()){
120
                resultNoData[band] = new DefaultNoData((byte)0);
121
                resultNoData[band] = manager.createNoData((byte)0,(byte)0);
122
            } else {
123
                resultNoData[band]=manager.createNoData(null, null);
124
            }
125
        }
126

    
127
        try {
128
            this.setOutputBuffer( manager.createBuffer(
129
                this.getInputBuffer().getRows(),
130
                this.getInputBuffer().getColumns(),
131
                bandTypes,
132
                resultNoData,
133
                this.getInputBuffer().getProjection(),
134
                this.getInputBuffer().getEnvelope()));
135
        } catch (LocatorException | BufferException | CreateEnvelopeException e) {
136
            throw new ProcessingOperationException(e);
137
        }
138
    }
139

    
140
    @Override
141
    public void process() throws ProcessingOperationException {
142
        super.process();
143
        for (int band=0; band<this.getInputBuffer().getBandCount(); band++){
144
            if (this.getBandsToProcess().contains(band)) {
145
                Band bufferBand = this.getInputBuffer().getBand(band);
146
                Band outputBufferBand = this.getOutputBuffer().getBand(band);
147

    
148
                for (int row = 0; row < this.getInputBuffer().getRows(); row++) {
149
                    Object rowBuffer = bufferBand.createRowBuffer();
150
                    bufferBand.fetchRow(row, rowBuffer);
151

    
152
                    Object outputRowBuffer = outputBufferBand.createRowBuffer();
153
                    outputBufferBand.fetchRow(row, outputRowBuffer);
154

    
155
                    rowProcessors[band].processRow(rowBuffer, outputRowBuffer);
156

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

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

    
174
    interface RowProcessor {
175
        void processRow(Object inputRow, Object outputRow);
176
        byte processValue(Object value);
177
    };
178

    
179
    private abstract class AbstractRowProcessor implements RowProcessor {
180
        int band;
181
        double minValue;
182
        double maxValue;
183
        double maxResult = 255;
184
        double minResult = 0;
185
        NoData noData;
186

    
187
        public AbstractRowProcessor(int band) {
188
            this.band = band;
189
            noData = getInputBuffer().getBand(band).getNoData();
190
            if(noData.isDefined()) {
191
                minResult = (byte)1;
192
            }
193
            minValue = statistics.getMin()[band];
194
            maxValue = statistics.getMax()[band];
195

    
196
            if(removeEnds) {
197
                minValue = statistics.getSecondMin()[band];
198
                maxValue = statistics.getSecondMax()[band];
199
            }
200

    
201
            if(tailTrim) {
202
                double[][] tailTrim = statistics.getTailTrimValue(tailTrimPercent);
203
                minValue = tailTrim[band][0];
204
                maxValue = tailTrim[band][1];
205
            }
206
        }
207

    
208
    }
209

    
210
    private class ByteRowProcessor extends AbstractRowProcessor {
211

    
212

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

    
217
        @Override
218
        public void processRow(Object inputRow, Object outputRow) {
219
            byte[] inputByteRow = (byte[])inputRow;
220
            byte[] outputByteRow = (byte[])outputRow;
221
            for (int i = 0; i < inputByteRow.length; i++) {
222
                outputByteRow[i] = processValue(inputByteRow[i]);
223
            }
224
        }
225

    
226
        @Override
227
        public byte processValue(Object value) {
228
            if(noData.isDefined() && noData.getValue().equals(value)){
229
                return (byte)0;
230
            }
231

    
232
            int iValue = 0xFF & ((Byte) value);
233
            Double dValue = new Double(iValue);
234

    
235
            double result;
236
            if(dValue < minValue){
237
                result = minResult;
238
            } else if (dValue > maxValue){
239
                result = maxResult;
240
            } else {
241
                double ratio = (maxResult - minResult) / (maxValue - minValue);
242
                result = (dValue-minValue) * ratio + minResult;
243
            }
244

    
245
            return (byte)result;
246

    
247
        }
248

    
249
    }
250

    
251
    private class ShortRowProcessor extends AbstractRowProcessor {
252

    
253
        public ShortRowProcessor(int band) {
254
            super(band);
255
        }
256

    
257
        @Override
258
        public void processRow(Object inputRow, Object outputRow) {
259
            short[] inputByteRow = (short[])inputRow;
260
            byte[] outputByteRow = (byte[])outputRow;
261
            for (int i = 0; i < inputByteRow.length; i++) {
262
                outputByteRow[i] = processValue(inputByteRow[i]);
263
            }
264
        }
265

    
266
        @Override
267
        public byte processValue(Object value) {
268
            if(noData.isDefined() && noData.getValue().equals(value)){
269
                return (byte)0;
270
            }
271

    
272
            int iValue = ((Short) value);
273
            Double dValue = ((Number) iValue).doubleValue();
274

    
275
            double result;
276
            if(dValue < minValue){
277
                result = minResult;
278
            } else if (dValue > maxValue){
279
                result = maxResult;
280
            } else {
281
                double ratio = (maxResult - minResult) / (maxValue - minValue);
282
                result = (dValue-minValue) * ratio + minResult;
283
            }
284

    
285
            return (byte)result;
286
        }
287

    
288
    }
289

    
290
    private class UShortRowProcessor extends AbstractRowProcessor {
291

    
292
        public UShortRowProcessor(int band) {
293
            super(band);
294
        }
295

    
296
        @Override
297
        public void processRow(Object inputRow, Object outputRow) {
298
            short[] inputByteRow = (short[])inputRow;
299
            byte[] outputByteRow = (byte[])outputRow;
300
            for (int i = 0; i < inputByteRow.length; i++) {
301
                outputByteRow[i] = processValue(inputByteRow[i]);
302
            }
303
        }
304

    
305
        @Override
306
        public byte processValue(Object value) {
307
            if(noData.isDefined() && noData.getValue().equals(value)){
308
                return (byte)0;
309
            }
310

    
311
            //FIXME ???:
312
            int iValue = 0xFFFF & ((Short) value);
313
            Double dValue = ((Number) iValue).doubleValue();
314

    
315
            double result;
316
            if(dValue < minValue){
317
                result = minResult;
318
            } else if (dValue > maxValue){
319
                result = maxResult;
320
            } else {
321
                double ratio = (maxResult - minResult) / (maxValue - minValue);
322
                result = (dValue-minValue) * ratio + minResult;
323
            }
324

    
325
            return (byte)result;
326
        }
327

    
328
    }
329

    
330
    private class IntRowProcessor extends AbstractRowProcessor {
331

    
332
        public IntRowProcessor(int band) {
333
            super(band);
334
        }
335

    
336
        @Override
337
        public void processRow(Object inputRow, Object outputRow) {
338
            int[] inputByteRow = (int[])inputRow;
339
            byte[] outputByteRow = (byte[])outputRow;
340
            for (int i = 0; i < inputByteRow.length; i++) {
341
                outputByteRow[i] = processValue(inputByteRow[i]);
342
            }
343
        }
344

    
345
        @Override
346
        public byte processValue(Object value) {
347
            if(noData.isDefined() && noData.getValue().equals(value)){
348
                return (byte)0;
349
            }
350

    
351
            Double dValue = ((Number) value).doubleValue();
352

    
353
            double result;
354
            if(dValue < minValue){
355
                result = minResult;
356
            } else if (dValue > maxValue){
357
                result = maxResult;
358
            } else {
359
                double ratio = (maxResult - minResult) / (maxValue - minValue);
360
                result = (dValue-minValue) * ratio + minResult;
361
            }
362

    
363
            return (byte)result;
364
        }
365

    
366
    }
367
    private class FloatRowProcessor extends AbstractRowProcessor {
368

    
369
        public FloatRowProcessor(int band) {
370
            super(band);
371
        }
372

    
373
        @Override
374
        public void processRow(Object inputRow, Object outputRow) {
375
            float[] inputByteRow = (float[])inputRow;
376
            byte[] outputByteRow = (byte[])outputRow;
377
            for (int i = 0; i < inputByteRow.length; i++) {
378
                outputByteRow[i] = processValue(inputByteRow[i]);
379
            }
380
        }
381

    
382
        @Override
383
        public byte processValue(Object value) {
384
            if(noData.isDefined() && noData.getValue().equals(value)){
385
                return (byte)0;
386
            }
387

    
388
            Double dValue = ((Number) value).doubleValue();
389

    
390
            double result;
391
            if(dValue < minValue){
392
                result = minResult;
393
            } else if (dValue > maxValue){
394
                result = maxResult;
395
            } else {
396
                double ratio = (maxResult - minResult) / (maxValue - minValue);
397
                result = (dValue-minValue) * ratio + minResult;
398
            }
399

    
400
            return (byte)result;
401
        }
402

    
403
    }
404
    private class DoubleRowProcessor extends AbstractRowProcessor {
405

    
406

    
407
        public DoubleRowProcessor(int band) {
408
            super(band);
409
        }
410

    
411
        @Override
412
        public void processRow(Object inputRow, Object outputRow) {
413
            double[] inputByteRow = (double[])inputRow;
414
            byte[] outputByteRow = (byte[])outputRow;
415
            for (int i = 0; i < inputByteRow.length; i++) {
416
                outputByteRow[i] = processValue(inputByteRow[i]);
417
            }
418
        }
419

    
420
        @Override
421
        public byte processValue(Object value) {
422
            if(noData.isDefined() && noData.getValue().equals(value)){
423
                return (byte)0;
424
            }
425

    
426
            Double dValue = ((Number) value).doubleValue();
427

    
428
            double result;
429
            if(dValue < minValue){
430
                result = minResult;
431
            } else if (dValue > maxValue){
432
                result = maxResult;
433
            } else {
434
                double ratio = (maxResult - minResult) / (maxValue - minValue);
435
                result = (dValue-minValue) * ratio + minResult;
436
            }
437

    
438
            return (byte)result;
439
        }
440

    
441
    }
442

    
443
}