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

History | View | Annotate | Download (15.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.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
        int bandCount = this.getInputBuffer().getBandCount();
144
        int rowCount = this.getInputBuffer().getRows();
145
        for (int band=0; band<bandCount; band++){
146
            if (this.getBandsToProcess().contains(band)) {
147
                this.getTaskStatus().setRangeOfValues(0, rowCount);
148
                this.getTaskStatus().setCurValue(0);
149
                this.getTaskStatus().message("LinearStretch band "+band+"/"+bandCount);
150

    
151
                Band bufferBand = this.getInputBuffer().getBand(band);
152
                Band outputBufferBand = this.getOutputBuffer().getBand(band);
153

    
154
                for (int row = 0; row < rowCount; row++) {
155
                    this.getTaskStatus().setCurValue(row);
156
                    Object rowBuffer = bufferBand.createRowBuffer();
157
                    bufferBand.fetchRow(row, rowBuffer);
158

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

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

    
164
                    outputBufferBand.putRow(row, outputRowBuffer);
165
                }
166
            } else {
167
                try {
168
                    this.getOutputBuffer().getBand(band).copyFrom(this.getInputBuffer().getBand(band));
169
                } catch (BandException e) {
170
                    throw new ProcessingOperationException(e);
171
                }
172
            }
173
        }
174
        this.getTaskStatus().terminate();
175
    }
176

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

    
182
    interface RowProcessor {
183
        void processRow(Object inputRow, Object outputRow);
184
        byte processValue(Object value);
185
    };
186

    
187
    private abstract class AbstractRowProcessor implements RowProcessor {
188
        int band;
189
        double minValue;
190
        double maxValue;
191
        double maxResult = 255;
192
        double minResult = 0;
193
        NoData noData;
194

    
195
        public AbstractRowProcessor(int band) {
196
            this.band = band;
197
            noData = getInputBuffer().getBand(band).getNoData();
198
            if(noData.isDefined()) {
199
                minResult = (byte)1;
200
            }
201
            minValue = statistics.getMin()[band];
202
            maxValue = statistics.getMax()[band];
203

    
204
            if(removeEnds) {
205
                minValue = statistics.getSecondMin()[band];
206
                maxValue = statistics.getSecondMax()[band];
207
            }
208

    
209
            if(tailTrim) {
210
                double[][] tailTrim = statistics.getTailTrimValue(tailTrimPercent);
211
                minValue = tailTrim[band][0];
212
                maxValue = tailTrim[band][1];
213
            }
214
        }
215

    
216
    }
217

    
218
    private class ByteRowProcessor extends AbstractRowProcessor {
219

    
220

    
221
        public ByteRowProcessor(int band) {
222
            super(band);
223
        }
224

    
225
        @Override
226
        public void processRow(Object inputRow, Object outputRow) {
227
            byte[] inputByteRow = (byte[])inputRow;
228
            byte[] outputByteRow = (byte[])outputRow;
229
            for (int i = 0; i < inputByteRow.length; i++) {
230
                outputByteRow[i] = processValue(inputByteRow[i]);
231
            }
232
        }
233

    
234
        @Override
235
        public byte processValue(Object value) {
236
            if(noData.isDefined() && noData.getValue().equals(value)){
237
                return (byte)0;
238
            }
239

    
240
            int iValue = 0xFF & ((Byte) value);
241
            Double dValue = new Double(iValue);
242

    
243
            double result;
244
            if(dValue < minValue){
245
                result = minResult;
246
            } else if (dValue > maxValue){
247
                result = maxResult;
248
            } else {
249
                double ratio = (maxResult - minResult) / (maxValue - minValue);
250
                result = (dValue-minValue) * ratio + minResult;
251
            }
252

    
253
            return (byte)result;
254

    
255
        }
256

    
257
    }
258

    
259
    private class ShortRowProcessor extends AbstractRowProcessor {
260

    
261
        public ShortRowProcessor(int band) {
262
            super(band);
263
        }
264

    
265
        @Override
266
        public void processRow(Object inputRow, Object outputRow) {
267
            short[] inputByteRow = (short[])inputRow;
268
            byte[] outputByteRow = (byte[])outputRow;
269
            for (int i = 0; i < inputByteRow.length; i++) {
270
                outputByteRow[i] = processValue(inputByteRow[i]);
271
            }
272
        }
273

    
274
        @Override
275
        public byte processValue(Object value) {
276
            if(noData.isDefined() && noData.getValue().equals(value)){
277
                return (byte)0;
278
            }
279

    
280
            int iValue = ((Short) value);
281
            Double dValue = ((Number) iValue).doubleValue();
282

    
283
            double result;
284
            if(dValue < minValue){
285
                result = minResult;
286
            } else if (dValue > maxValue){
287
                result = maxResult;
288
            } else {
289
                double ratio = (maxResult - minResult) / (maxValue - minValue);
290
                result = (dValue-minValue) * ratio + minResult;
291
            }
292

    
293
            return (byte)result;
294
        }
295

    
296
    }
297

    
298
    private class UShortRowProcessor extends AbstractRowProcessor {
299

    
300
        public UShortRowProcessor(int band) {
301
            super(band);
302
        }
303

    
304
        @Override
305
        public void processRow(Object inputRow, Object outputRow) {
306
            short[] inputByteRow = (short[])inputRow;
307
            byte[] outputByteRow = (byte[])outputRow;
308
            for (int i = 0; i < inputByteRow.length; i++) {
309
                outputByteRow[i] = processValue(inputByteRow[i]);
310
            }
311
        }
312

    
313
        @Override
314
        public byte processValue(Object value) {
315
            if(noData.isDefined() && noData.getValue().equals(value)){
316
                return (byte)0;
317
            }
318

    
319
            //FIXME ???:
320
            int iValue = 0xFFFF & ((Short) value);
321
            Double dValue = ((Number) iValue).doubleValue();
322

    
323
            double result;
324
            if(dValue < minValue){
325
                result = minResult;
326
            } else if (dValue > maxValue){
327
                result = maxResult;
328
            } else {
329
                double ratio = (maxResult - minResult) / (maxValue - minValue);
330
                result = (dValue-minValue) * ratio + minResult;
331
            }
332

    
333
            return (byte)result;
334
        }
335

    
336
    }
337

    
338
    private class IntRowProcessor extends AbstractRowProcessor {
339

    
340
        public IntRowProcessor(int band) {
341
            super(band);
342
        }
343

    
344
        @Override
345
        public void processRow(Object inputRow, Object outputRow) {
346
            int[] inputByteRow = (int[])inputRow;
347
            byte[] outputByteRow = (byte[])outputRow;
348
            for (int i = 0; i < inputByteRow.length; i++) {
349
                outputByteRow[i] = processValue(inputByteRow[i]);
350
            }
351
        }
352

    
353
        @Override
354
        public byte processValue(Object value) {
355
            if(noData.isDefined() && noData.getValue().equals(value)){
356
                return (byte)0;
357
            }
358

    
359
            Double dValue = ((Number) value).doubleValue();
360

    
361
            double result;
362
            if(dValue < minValue){
363
                result = minResult;
364
            } else if (dValue > maxValue){
365
                result = maxResult;
366
            } else {
367
                double ratio = (maxResult - minResult) / (maxValue - minValue);
368
                result = (dValue-minValue) * ratio + minResult;
369
            }
370

    
371
            return (byte)result;
372
        }
373

    
374
    }
375
    private class FloatRowProcessor extends AbstractRowProcessor {
376

    
377
        public FloatRowProcessor(int band) {
378
            super(band);
379
        }
380

    
381
        @Override
382
        public void processRow(Object inputRow, Object outputRow) {
383
            float[] inputByteRow = (float[])inputRow;
384
            byte[] outputByteRow = (byte[])outputRow;
385
            for (int i = 0; i < inputByteRow.length; i++) {
386
                outputByteRow[i] = processValue(inputByteRow[i]);
387
            }
388
        }
389

    
390
        @Override
391
        public byte processValue(Object value) {
392
            if(noData.isDefined() && noData.getValue().equals(value)){
393
                return (byte)0;
394
            }
395

    
396
            Double dValue = ((Number) value).doubleValue();
397

    
398
            double result;
399
            if(dValue < minValue){
400
                result = minResult;
401
            } else if (dValue > maxValue){
402
                result = maxResult;
403
            } else {
404
                double ratio = (maxResult - minResult) / (maxValue - minValue);
405
                result = (dValue-minValue) * ratio + minResult;
406
            }
407

    
408
            return (byte)result;
409
        }
410

    
411
    }
412
    private class DoubleRowProcessor extends AbstractRowProcessor {
413

    
414

    
415
        public DoubleRowProcessor(int band) {
416
            super(band);
417
        }
418

    
419
        @Override
420
        public void processRow(Object inputRow, Object outputRow) {
421
            double[] inputByteRow = (double[])inputRow;
422
            byte[] outputByteRow = (byte[])outputRow;
423
            for (int i = 0; i < inputByteRow.length; i++) {
424
                outputByteRow[i] = processValue(inputByteRow[i]);
425
            }
426
        }
427

    
428
        @Override
429
        public byte processValue(Object value) {
430
            if(noData.isDefined() && noData.getValue().equals(value)){
431
                return (byte)0;
432
            }
433

    
434
            Double dValue = ((Number) value).doubleValue();
435

    
436
            double result;
437
            if(dValue < minValue){
438
                result = minResult;
439
            } else if (dValue > maxValue){
440
                result = maxResult;
441
            } else {
442
                double ratio = (maxResult - minResult) / (maxValue - minValue);
443
                result = (dValue-minValue) * ratio + minResult;
444
            }
445

    
446
            return (byte)result;
447
        }
448

    
449
    }
450

    
451
}