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 | 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.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 | 43864 | jjdelcerro | super(factory);
|
64 | 43803 | fdiaz | } |
65 | |||
66 | @Override
|
||
67 | public void preProcess() throws BufferOperationException { |
||
68 | super.preProcess();
|
||
69 | BufferManager manager = BufferLocator.getBufferManager(); |
||
70 | |||
71 | 43864 | jjdelcerro | statistics = (Statistics) this.getParameter(STATISTICS_PARAM, null); |
72 | 43803 | fdiaz | if (statistics == null) { |
73 | 43864 | jjdelcerro | 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 | 43803 | fdiaz | |
81 | 43864 | jjdelcerro | int bands = this.getInputBuffer().getBandCount(); |
82 | 43803 | fdiaz | 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 | 43864 | jjdelcerro | if(this.getBandsToProcess().contains(i)){ |
87 | 43803 | fdiaz | bandTypes[i] = BufferManager.TYPE_BYTE; |
88 | } else {
|
||
89 | 43864 | jjdelcerro | bandTypes[i] = this.getInputBuffer().getBandTypes()[i];
|
90 | 43803 | fdiaz | } |
91 | } |
||
92 | 43864 | jjdelcerro | NoData[] noData = this.getInputBuffer().getBandNoData(); |
93 | 43803 | fdiaz | NoData[] resultNoData = new NoData[noData.length]; |
94 | for (int band = 0; band < noData.length; band++) { |
||
95 | 43864 | jjdelcerro | int bandType = this.getInputBuffer().getBand(band).getDataType(); |
96 | 43803 | fdiaz | 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 | 43864 | jjdelcerro | this.setOutputBuffer( manager.createBuffer(
|
129 | this.getInputBuffer().getRows(),
|
||
130 | this.getInputBuffer().getColumns(),
|
||
131 | 43803 | fdiaz | bandTypes, |
132 | resultNoData, |
||
133 | 43864 | jjdelcerro | this.getInputBuffer().getProjection(),
|
134 | this.getInputBuffer().getEnvelope()));
|
||
135 | 43803 | fdiaz | } 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 | 43867 | jjdelcerro | int bandCount = this.getInputBuffer().getBandCount(); |
144 | int rowCount = this.getInputBuffer().getRows(); |
||
145 | for (int band=0; band<bandCount; band++){ |
||
146 | 43864 | jjdelcerro | if (this.getBandsToProcess().contains(band)) { |
147 | 43867 | jjdelcerro | this.getTaskStatus().setRangeOfValues(0, rowCount); |
148 | this.getTaskStatus().setCurValue(0); |
||
149 | this.getTaskStatus().message("LinearStretch band "+band+"/"+bandCount); |
||
150 | |||
151 | 43864 | jjdelcerro | Band bufferBand = this.getInputBuffer().getBand(band);
|
152 | Band outputBufferBand = this.getOutputBuffer().getBand(band);
|
||
153 | 43803 | fdiaz | |
154 | 43867 | jjdelcerro | for (int row = 0; row < rowCount; row++) { |
155 | this.getTaskStatus().setCurValue(row);
|
||
156 | 43803 | fdiaz | 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 | 43864 | jjdelcerro | this.getOutputBuffer().getBand(band).copyFrom(this.getInputBuffer().getBand(band)); |
169 | 43803 | fdiaz | } catch (BandException e) {
|
170 | throw new ProcessingOperationException(e); |
||
171 | } |
||
172 | } |
||
173 | } |
||
174 | 43867 | jjdelcerro | this.getTaskStatus().terminate();
|
175 | 43803 | fdiaz | } |
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 | 43864 | jjdelcerro | noData = getInputBuffer().getBand(band).getNoData(); |
198 | 43803 | fdiaz | 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 | 43864 | jjdelcerro | int iValue = 0xFF & ((Byte) value); |
241 | 43803 | fdiaz | 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 | 43864 | jjdelcerro | int iValue = ((Short) value); |
281 | 43803 | fdiaz | 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 | 43864 | jjdelcerro | int iValue = 0xFFFF & ((Short) value); |
321 | 43803 | fdiaz | 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 | } |