gvsig-raster / org.gvsig.raster / branches / org.gvsig.raster.2.4 / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.buffer / org.gvsig.raster.lib.buffer.impl / src / main / java / org / gvsig / raster / lib / buffer / impl / BufferInterpolation.java @ 8800
History | View | Annotate | Download (28.3 KB)
1 | 5527 | fdiaz | package org.gvsig.raster.lib.buffer.impl; |
---|---|---|---|
2 | |||
3 | import org.gvsig.raster.lib.buffer.api.Band; |
||
4 | import org.gvsig.raster.lib.buffer.api.Band.BandByte; |
||
5 | import org.gvsig.raster.lib.buffer.api.Band.BandDouble; |
||
6 | import org.gvsig.raster.lib.buffer.api.Band.BandFloat; |
||
7 | import org.gvsig.raster.lib.buffer.api.Band.BandInt; |
||
8 | import org.gvsig.raster.lib.buffer.api.Band.BandShort; |
||
9 | import org.gvsig.raster.lib.buffer.api.Buffer; |
||
10 | import org.gvsig.raster.lib.buffer.api.BufferManager; |
||
11 | import org.gvsig.tools.ToolsLocator; |
||
12 | import org.gvsig.tools.task.SimpleTaskStatus; |
||
13 | 6318 | fdiaz | |
14 | 5531 | llmarques | import org.slf4j.Logger; |
15 | import org.slf4j.LoggerFactory; |
||
16 | 5527 | fdiaz | |
17 | /**
|
||
18 | * @author fdiaz
|
||
19 | *
|
||
20 | */
|
||
21 | public class BufferInterpolation { |
||
22 | 5539 | fdiaz | |
23 | 5531 | llmarques | private static final Logger LOG = LoggerFactory.getLogger(BufferInterpolation.class); |
24 | 5527 | fdiaz | |
25 | /**
|
||
26 | * @param buf
|
||
27 | */
|
||
28 | public BufferInterpolation() {
|
||
29 | } |
||
30 | |||
31 | /**
|
||
32 | * Interpolates the buffer "source" to a number of columns and a number of rows
|
||
33 | * and stores the result in the buffer "targer" according to the nearest interpolation method.
|
||
34 | *
|
||
35 | * @param source
|
||
36 | * @param rows
|
||
37 | * @param columns
|
||
38 | * @param target
|
||
39 | * @param status
|
||
40 | */
|
||
41 | 5539 | fdiaz | public void nearestNeighbourInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
42 | 5527 | fdiaz | boolean isMyStatus = false; |
43 | if (status == null) { |
||
44 | status = |
||
45 | ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Nearest neighbour interpolation");
|
||
46 | status.add(); |
||
47 | isMyStatus = true;
|
||
48 | } else {
|
||
49 | status.push(); |
||
50 | } |
||
51 | try {
|
||
52 | 5539 | fdiaz | int rows = target.getRows();
|
53 | int columns = target.getColumns();
|
||
54 | 5527 | fdiaz | |
55 | double stepX = (double) columns / (double) source.getColumns(); |
||
56 | double stepY = (double) rows / (double) source.getRows(); |
||
57 | |||
58 | status.setRangeOfValues(0, source.getBandCount() * source.getRows() * source.getColumns());
|
||
59 | status.message("Calculating interpolation");
|
||
60 | int count = 0; |
||
61 | |||
62 | for (int iBand = 0; iBand < source.getBandCount(); iBand++) { |
||
63 | Band sourceBand = source.getBand(iBand); |
||
64 | Band targetBand = target.getBand(iBand); |
||
65 | 6325 | fdiaz | if (stepY < 1) {// submuestreo Y |
66 | int previousTargetRow = -1; |
||
67 | for (int sourceRow = 0; sourceRow < source.getRows(); sourceRow++) { |
||
68 | int targetRow = (int) (sourceRow * stepY); |
||
69 | 6318 | fdiaz | if (targetRow != previousTargetRow) {
|
70 | 6325 | fdiaz | if (stepX < 1) { // submuestreo X |
71 | submuestreoX(source, stepX, sourceBand, targetBand, sourceRow, targetRow); |
||
72 | } else {
|
||
73 | supermuestreoX(columns, stepX, sourceBand, targetBand, sourceRow, targetRow); |
||
74 | 5527 | fdiaz | } |
75 | 6325 | fdiaz | status.setCurValue(count+=source.getColumns()); |
76 | if (status.isCancelled()) {
|
||
77 | status.abort(); |
||
78 | return;
|
||
79 | } |
||
80 | previousTargetRow = targetRow; |
||
81 | 6318 | fdiaz | } else {
|
82 | count += source.getColumns(); |
||
83 | status.setCurValue(count); |
||
84 | 5527 | fdiaz | } |
85 | } |
||
86 | 6325 | fdiaz | } else { // supermuestreo Y |
87 | for (int targetRow = 0; targetRow < rows; targetRow++) { |
||
88 | int sourceRow = (int) (targetRow / stepY); |
||
89 | if (stepX < 1) { // submuestreo X |
||
90 | submuestreoX(source, stepX, sourceBand, targetBand, sourceRow, targetRow); |
||
91 | } else {
|
||
92 | supermuestreoX(columns, stepX, sourceBand, targetBand, sourceRow, targetRow); |
||
93 | 5527 | fdiaz | } |
94 | 6325 | fdiaz | status.setCurValue(count+=source.getColumns()); |
95 | if (status.isCancelled()) {
|
||
96 | status.abort(); |
||
97 | return;
|
||
98 | } |
||
99 | 5527 | fdiaz | } |
100 | } |
||
101 | } |
||
102 | |||
103 | if (isMyStatus) {
|
||
104 | status.terminate(); |
||
105 | } else {
|
||
106 | status.pop(); |
||
107 | } |
||
108 | } catch (Exception e) { |
||
109 | status.abort(); |
||
110 | throw e;
|
||
111 | } |
||
112 | return;
|
||
113 | |||
114 | } |
||
115 | |||
116 | /**
|
||
117 | 6325 | fdiaz | * @param columns
|
118 | * @param stepX
|
||
119 | * @param sourceBand
|
||
120 | * @param targetBand
|
||
121 | * @param sourceRow
|
||
122 | * @param targetRow
|
||
123 | */
|
||
124 | private void supermuestreoX(int columns, double stepX, Band sourceBand, Band targetBand, int sourceRow, |
||
125 | int targetRow) {
|
||
126 | for (int targetCol = 0; targetCol < columns; targetCol++) { |
||
127 | int sourceColumn = (int) (targetCol / stepX); |
||
128 | targetBand.set(targetRow, targetCol, sourceBand.get(sourceRow, sourceColumn)); |
||
129 | } |
||
130 | } |
||
131 | |||
132 | /**
|
||
133 | * @param source
|
||
134 | * @param stepX
|
||
135 | * @param sourceBand
|
||
136 | * @param targetBand
|
||
137 | * @param sourceRow
|
||
138 | * @param targetRow
|
||
139 | */
|
||
140 | private void submuestreoX(Buffer source, double stepX, Band sourceBand, Band targetBand, int sourceRow, int targetRow) { |
||
141 | int previousTargetColumn = -1; |
||
142 | for (int sourceCol = 0; sourceCol < source.getColumns(); sourceCol++) { |
||
143 | int targetColumn = (int) (sourceCol * stepX); |
||
144 | if (targetColumn != previousTargetColumn) {
|
||
145 | Object value = sourceBand.get(sourceRow, sourceCol);
|
||
146 | targetBand.set(targetRow, targetColumn, value); |
||
147 | previousTargetColumn = targetColumn; |
||
148 | } |
||
149 | } |
||
150 | } |
||
151 | |||
152 | /**
|
||
153 | 5527 | fdiaz | * Interpolates the buffer "source" to a number of columns and a number of rows
|
154 | * and stores the result in the buffer "targer" according to the bilinear interpolation method.
|
||
155 | *
|
||
156 | * Promedia el valor de cuatro pixeles adyacentes.
|
||
157 | * <P>
|
||
158 | * Para cada pixel del raster A:(x, y) obtiene el B:(x + 1, y), C:(x, y +
|
||
159 | * 1), D:(x + 1, y + 1) Para cada valor del kernel se calcula un valor 'd'
|
||
160 | * que es un peso dependiendo de su posici?n. Este peso depende de la
|
||
161 | * posici?n del pixel destino dentro del origen. La posici?n del pixel
|
||
162 | * destino en el origen es un valor decimal que puede ir de 0 a 1. Si est?
|
||
163 | * muy pegado a la esquina superior izquierda estar? cercano a 0 y si est?
|
||
164 | * muy pegado a la esquina inferior derecha estar? cercano a 1. Este valor
|
||
165 | * est? representado por 'dx' y 'dy'.
|
||
166 | * </P>
|
||
167 | * <P>
|
||
168 | * Los pesos aplicados son a
|
||
169 | * <UL>
|
||
170 | * <LI>A (1-dx) * (1-dy)</LI>
|
||
171 | * <LI>B dx * (1-dy)</LI>
|
||
172 | * <LI>C (1-dx) * dy</LI>
|
||
173 | * <LI>D dx * dy</LI>
|
||
174 | * </UL>
|
||
175 | * La variable 'z' contiene el valor acumulado de cada peso por el valor del
|
||
176 | * pixel. La variable 'n' contiene el valor acumulado de los pesos de los
|
||
177 | * cuatro pixeles. El valor final del pixel ser? 'z/n', es decir un promedio
|
||
178 | * del valor de los cuatro teniendo en cuenta el peso de cada uno.
|
||
179 | * </P>
|
||
180 | * @param source
|
||
181 | * @param rows
|
||
182 | * @param columns
|
||
183 | * @param target
|
||
184 | * @param status
|
||
185 | *
|
||
186 | */
|
||
187 | 5539 | fdiaz | public void bilinearInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
188 | 5527 | fdiaz | |
189 | boolean isMyStatus = false; |
||
190 | if (status == null) { |
||
191 | status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Bilinear interpolation");
|
||
192 | status.add(); |
||
193 | isMyStatus = true;
|
||
194 | } else {
|
||
195 | status.push(); |
||
196 | } |
||
197 | try {
|
||
198 | 5539 | fdiaz | int rows = target.getRows();
|
199 | int columns = target.getColumns();
|
||
200 | 5527 | fdiaz | |
201 | double pxSizeX = (double) source.getColumns() / (double) columns; |
||
202 | double pxSizeY = (double) source.getRows() / (double) rows; |
||
203 | |||
204 | status.setRangeOfValues(0, source.getBandCount() * source.getRows() * source.getColumns());
|
||
205 | status.message("Calculating interpolation");
|
||
206 | int count = 0; |
||
207 | double posX, posY;
|
||
208 | double dx = 0D, dy = 0D; |
||
209 | |||
210 | for (int iBand = 0; iBand < source.getBandCount(); iBand++) { |
||
211 | posY = pxSizeY / 2D;
|
||
212 | Band sourceBand = source.getBand(iBand); |
||
213 | Band targetBand = target.getBand(iBand); |
||
214 | 5531 | llmarques | for (int iRow = 0; iRow < rows; iRow++) { |
215 | 5527 | fdiaz | dy = posY - ((int) posY);
|
216 | posX = pxSizeX / 2D;
|
||
217 | 5531 | llmarques | for (int iCol = 0; iCol < columns; iCol++) { |
218 | 5527 | fdiaz | status.setCurValue(count++); |
219 | if (status.isCancelled()) {
|
||
220 | status.abort(); |
||
221 | return;
|
||
222 | } |
||
223 | dx = posX - ((int) posX);
|
||
224 | try {
|
||
225 | 6220 | dmartinezizquierdo | double[] kernel = getKernel((int) posY, (int) posX, sourceBand); |
226 | 5527 | fdiaz | setBandValueFromDouble(iRow, iCol, targetBand, getBilinearValue(dx, dy, kernel)); |
227 | } catch (ArrayIndexOutOfBoundsException e) { |
||
228 | 5531 | llmarques | LOG.warn( |
229 | "Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
|
||
230 | new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow, |
||
231 | iCol, dx, dy}); |
||
232 | 5527 | fdiaz | } |
233 | posX += pxSizeX; |
||
234 | } |
||
235 | posY += pxSizeY; |
||
236 | } |
||
237 | } |
||
238 | |||
239 | if (isMyStatus) {
|
||
240 | status.terminate(); |
||
241 | } else {
|
||
242 | status.pop(); |
||
243 | } |
||
244 | } catch (Exception e) { |
||
245 | status.abort(); |
||
246 | throw e;
|
||
247 | } |
||
248 | return;
|
||
249 | } |
||
250 | |||
251 | /**
|
||
252 | * Interpolates the buffer "source" to a number of columns and a number of rows
|
||
253 | * and stores the result in the buffer "targer" according to the inverse distance interpolation method.
|
||
254 | *
|
||
255 | * Asigna el valor de un pixel en funci?n inversa de la distancia.
|
||
256 | * <P>
|
||
257 | * Para cada pixel del raster A:(x, y) obtiene el B:(x + 1, y), C:(x, y +
|
||
258 | * 1), D:(x + 1, y + 1) Para cada valor del kernel se calcula un valor 'd'
|
||
259 | * que es un peso dependiendo de su posici?n. Este peso ser? dependiente de
|
||
260 | * la posici?n del pixel destino dentro del origen. La posici?n del pixel
|
||
261 | * destino en el origen es un valor decimal que puede ir de 0 a 1. Si est?
|
||
262 | * muy pegado a la esquina superior izquierda estar? cercano a 0 y si est?
|
||
263 | * muy pegado a la esquina inferior derecha estar? cercano a 1. Este valor
|
||
264 | * est? representado por 'dx' y 'dy'. En este caso, y a diferencia del
|
||
265 | * m?todo bilinear el peso vendr? representado por la inversa de la
|
||
266 | * distancia entre la posici?n dentro del pixel y el origen del mismo.
|
||
267 | * </P>
|
||
268 | * <P>
|
||
269 | * Los pesos aplicados son a
|
||
270 | * <UL>
|
||
271 | * <LI>A 1 / sqrt((1-dx) * (1-dy))</LI>
|
||
272 | * <LI>B 1 / sqrt(dx * (1-dy))</LI>
|
||
273 | * <LI>C 1 / sqrt((1-dx) * dy)</LI>
|
||
274 | * <LI>D 1 / sqrt(dx * dy)</LI>
|
||
275 | * </UL>
|
||
276 | * La variable 'z' contiene el valor acumulado de cada peso por el valor del
|
||
277 | * pixel. La variable 'n' contiene el valor acumulado de los pesos de los
|
||
278 | * cuatro pixeles. El valor final del pixel ser? 'z/n', es decir un promedio
|
||
279 | * del valor de los cuatro teniendo en cuenta el peso de cada uno.
|
||
280 | * </P>
|
||
281 | * @param source
|
||
282 | * @param rows
|
||
283 | * @param columns
|
||
284 | * @param target
|
||
285 | * @param status
|
||
286 | */
|
||
287 | 5539 | fdiaz | public void inverseDistanceInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
288 | 5527 | fdiaz | |
289 | boolean isMyStatus = false; |
||
290 | if (status == null) { |
||
291 | status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Inverse distance interpolation");
|
||
292 | status.add(); |
||
293 | isMyStatus = true;
|
||
294 | } else {
|
||
295 | status.push(); |
||
296 | } |
||
297 | try {
|
||
298 | 5539 | fdiaz | int rows = target.getRows();
|
299 | int columns = target.getColumns();
|
||
300 | 5527 | fdiaz | |
301 | double pxSizeX = (double) source.getColumns() / (double) columns; |
||
302 | double pxSizeY = (double) source.getRows() / (double) rows; |
||
303 | |||
304 | status.setRangeOfValues(0, source.getBandCount() * source.getRows() * source.getColumns());
|
||
305 | status.message("Calculating interpolation");
|
||
306 | int count = 0; |
||
307 | double posX, posY;
|
||
308 | double dx = 0D, dy = 0D; |
||
309 | |||
310 | for (int iBand = 0; iBand < source.getBandCount(); iBand++) { |
||
311 | posY = pxSizeY / 2D;
|
||
312 | Band sourceBand = source.getBand(iBand); |
||
313 | Band targetBand = target.getBand(iBand); |
||
314 | 5531 | llmarques | for (int iRow = 0; iRow < rows; iRow++) { |
315 | 5527 | fdiaz | dy = posY - ((int) posY);
|
316 | posX = pxSizeX / 2D;
|
||
317 | 5531 | llmarques | for (int iCol = 0; iCol < columns; iCol++) { |
318 | 5527 | fdiaz | status.setCurValue(count++); |
319 | if (status.isCancelled()) {
|
||
320 | status.abort(); |
||
321 | return;
|
||
322 | } |
||
323 | dx = posX - ((int) posX);
|
||
324 | try {
|
||
325 | 6220 | dmartinezizquierdo | double[] kernel = getKernel(((int) posY), ((int) posX), sourceBand); |
326 | 5527 | fdiaz | setBandValueFromDouble(iRow, iCol, targetBand, getInverseDistanceValue(dx, dy, kernel)); |
327 | } catch (ArrayIndexOutOfBoundsException e) { |
||
328 | 5531 | llmarques | LOG.warn( |
329 | "Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
|
||
330 | new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow, |
||
331 | iCol, dx, dy}); |
||
332 | 5527 | fdiaz | } |
333 | posX += pxSizeX; |
||
334 | } |
||
335 | posY += pxSizeY; |
||
336 | } |
||
337 | } |
||
338 | |||
339 | if (isMyStatus) {
|
||
340 | status.terminate(); |
||
341 | } else {
|
||
342 | status.pop(); |
||
343 | } |
||
344 | } catch (Exception e) { |
||
345 | status.abort(); |
||
346 | throw e;
|
||
347 | } |
||
348 | return;
|
||
349 | } |
||
350 | |||
351 | /**
|
||
352 | * Interpolates the buffer "source" to a number of columns and a number of rows
|
||
353 | * and stores the result in the buffer "targer" according to the bicubic spline interpolation method.
|
||
354 | * el valor de cuatro pixeles adyacentes.
|
||
355 | * @param source
|
||
356 | * @param rows
|
||
357 | * @param columns
|
||
358 | * @param target
|
||
359 | * @param status
|
||
360 | */
|
||
361 | 5539 | fdiaz | public void bicubicSplineInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
362 | 5527 | fdiaz | boolean isMyStatus = false; |
363 | if (status == null) { |
||
364 | status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Bicubic spline interpolation");
|
||
365 | status.add(); |
||
366 | isMyStatus = true;
|
||
367 | } else {
|
||
368 | status.push(); |
||
369 | } |
||
370 | try {
|
||
371 | 5539 | fdiaz | int rows = target.getRows();
|
372 | int columns = target.getColumns();
|
||
373 | 5527 | fdiaz | |
374 | double pxSizeX = (double) source.getColumns() / (double) columns; |
||
375 | double pxSizeY = (double) source.getRows() / (double) rows; |
||
376 | |||
377 | status.setRangeOfValues(0, source.getBandCount() * source.getRows() * source.getColumns());
|
||
378 | status.message("Calculating interpolation");
|
||
379 | int count = 0; |
||
380 | double posX, posY;
|
||
381 | double dx = 0D, dy = 0D; |
||
382 | |||
383 | for (int iBand = 0; iBand < source.getBandCount(); iBand++) { |
||
384 | posY = pxSizeY / 2D;
|
||
385 | Band sourceBand = source.getBand(iBand); |
||
386 | Band targetBand = target.getBand(iBand); |
||
387 | 5531 | llmarques | for (int iRow = 0; iRow < rows; iRow++) { |
388 | 5527 | fdiaz | dy = posY - ((int) posY);
|
389 | posX = pxSizeX / 2D;
|
||
390 | 5531 | llmarques | for (int iCol = 0; iCol < columns; iCol++) { |
391 | 5527 | fdiaz | status.setCurValue(count++); |
392 | if (status.isCancelled()) {
|
||
393 | status.abort(); |
||
394 | return;
|
||
395 | } |
||
396 | dx = posX - ((int) posX);
|
||
397 | try {
|
||
398 | double[][] submatrix = get4x4Submatrix(((int) posY), ((int) posX), source, sourceBand); |
||
399 | if (submatrix == null) { |
||
400 | double[] kernel = getKernel((int) posY, (int) posX, sourceBand); |
||
401 | setBandValueFromDouble(iRow, iCol, targetBand, getBilinearValue(dx, dy, kernel)); |
||
402 | } else {
|
||
403 | setBandValueFromDouble(iRow, iCol, targetBand, getBSplineValue(dx, dy, submatrix)); |
||
404 | } |
||
405 | } catch (ArrayIndexOutOfBoundsException e) { |
||
406 | 5531 | llmarques | LOG.warn( |
407 | "Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
|
||
408 | new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow, |
||
409 | iCol, dx, dy}); |
||
410 | 5527 | fdiaz | } |
411 | posX += pxSizeX; |
||
412 | } |
||
413 | posY += pxSizeY; |
||
414 | } |
||
415 | } |
||
416 | |||
417 | if (isMyStatus) {
|
||
418 | status.terminate(); |
||
419 | } else {
|
||
420 | status.pop(); |
||
421 | } |
||
422 | } catch (Exception e) { |
||
423 | status.abort(); |
||
424 | throw e;
|
||
425 | } |
||
426 | return;
|
||
427 | } |
||
428 | |||
429 | /**
|
||
430 | * Interpolates the buffer "source" to a number of columns and a number of rows
|
||
431 | * and stores the result in the buffer "targer" according to the bSplineInterpolation method.
|
||
432 | * @param source
|
||
433 | * @param rows
|
||
434 | * @param columns
|
||
435 | * @param target
|
||
436 | * @param status
|
||
437 | */
|
||
438 | 5539 | fdiaz | public void bSplineInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
439 | 5527 | fdiaz | |
440 | boolean isMyStatus = false; |
||
441 | if (status == null) { |
||
442 | status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("BSpline interpolation");
|
||
443 | status.add(); |
||
444 | isMyStatus = true;
|
||
445 | } else {
|
||
446 | status.push(); |
||
447 | } |
||
448 | try {
|
||
449 | 5539 | fdiaz | int rows = target.getRows();
|
450 | int columns = target.getColumns();
|
||
451 | 5527 | fdiaz | |
452 | double pxSizeX = (double) source.getColumns() / (double) columns; |
||
453 | double pxSizeY = (double) source.getRows() / (double) rows; |
||
454 | |||
455 | status.setRangeOfValues(0, source.getBandCount() * source.getRows() * source.getColumns());
|
||
456 | status.message("Calculating interpolation");
|
||
457 | int count = 0; |
||
458 | double posX, posY;
|
||
459 | double dx = 0D, dy = 0D; |
||
460 | |||
461 | for (int iBand = 0; iBand < source.getBandCount(); iBand++) { |
||
462 | posY = pxSizeY / 2D;
|
||
463 | Band sourceBand = source.getBand(iBand); |
||
464 | Band targetBand = target.getBand(iBand); |
||
465 | 5531 | llmarques | for (int iRow = 0; iRow < rows; iRow++) { |
466 | 5527 | fdiaz | dy = posY - ((int) posY);
|
467 | posX = pxSizeX / 2D;
|
||
468 | 5531 | llmarques | for (int iCol = 0; iCol < columns; iCol++) { |
469 | 5527 | fdiaz | status.setCurValue(count++); |
470 | if (status.isCancelled()) {
|
||
471 | status.abort(); |
||
472 | return;
|
||
473 | } |
||
474 | dx = posX - ((int) posX);
|
||
475 | try {
|
||
476 | double[][] submatrix = get4x4Submatrix(((int) posY), ((int) posX), source, sourceBand); |
||
477 | if (submatrix == null) { |
||
478 | 6220 | dmartinezizquierdo | double[] kernel = getKernel( ((int) posY), ((int) posX),sourceBand); |
479 | 5527 | fdiaz | setBandValueFromDouble(iRow, iCol, targetBand, getBilinearValue(dx, dy, kernel)); |
480 | } else {
|
||
481 | setBandValueFromDouble(iRow, iCol, targetBand, getBicubicSplineValue(dx, dy, submatrix)); |
||
482 | } |
||
483 | } catch (ArrayIndexOutOfBoundsException e) { |
||
484 | 5531 | llmarques | LOG.warn( |
485 | "Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
|
||
486 | new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow, |
||
487 | iCol, dx, dy }); |
||
488 | 5527 | fdiaz | } |
489 | posX += pxSizeX; |
||
490 | } |
||
491 | posY += pxSizeY; |
||
492 | } |
||
493 | } |
||
494 | |||
495 | if (isMyStatus) {
|
||
496 | status.terminate(); |
||
497 | } else {
|
||
498 | status.pop(); |
||
499 | } |
||
500 | } catch (Exception e) { |
||
501 | status.abort(); |
||
502 | throw e;
|
||
503 | } |
||
504 | return;
|
||
505 | } |
||
506 | |||
507 | /**
|
||
508 | *
|
||
509 | * @param dx
|
||
510 | * @param dy
|
||
511 | * @param kernel
|
||
512 | * @return
|
||
513 | */
|
||
514 | private double getBicubicSplineValue(double dx, double dy, double[][] kernel) { |
||
515 | int i;
|
||
516 | double a0, a2, a3, b1, b2, b3;
|
||
517 | double[] c = new double[4]; |
||
518 | |||
519 | for (i = 0; i < 4; i++) { |
||
520 | a0 = kernel[0][i] - kernel[1][i]; |
||
521 | a2 = kernel[2][i] - kernel[1][i]; |
||
522 | a3 = kernel[3][i] - kernel[1][i]; |
||
523 | |||
524 | b1 = -a0 / 3.0 + a2 - a3 / 6.0; |
||
525 | b2 = a0 / 2.0 + a2 / 2.0; |
||
526 | b3 = -a0 / 6.0 - a2 / 2.0 + a3 / 6.0; |
||
527 | |||
528 | c[i] = kernel[1][i] + b1 * dx + b2 * (dx * dx) + b3 * (dx * dx * dx);
|
||
529 | } |
||
530 | |||
531 | a0 = c[0] - c[1]; |
||
532 | a2 = c[2] - c[1]; |
||
533 | a3 = c[3] - c[1]; |
||
534 | |||
535 | b1 = -a0 / 3.0 + a2 - a3 / 6.0; |
||
536 | b2 = a0 / 2.0 + a2 / 2.0; |
||
537 | b3 = -a0 / 6.0 - a2 / 2.0 + a3 / 6.0; |
||
538 | |||
539 | return (c[1] + b1 * dy + b2 * (dy * dy) + b3 * (dy * dy * dy)); |
||
540 | } |
||
541 | |||
542 | /**
|
||
543 | *
|
||
544 | * @param dx
|
||
545 | * @param dy
|
||
546 | * @param kernel
|
||
547 | * @return
|
||
548 | */
|
||
549 | private double getBSplineValue(double dx, double dy, double[][] kernel) { |
||
550 | int i = 0, ix = 0, iy = 0; |
||
551 | double px = 0, py = 0, z = 0; |
||
552 | double[] Rx = new double[4]; |
||
553 | double[] Ry = new double[4]; |
||
554 | |||
555 | for (i = 0, px = -1.0 - dx, py = -1.0 - dy; i < 4; i++, px++, py++) { |
||
556 | Rx[i] = 0.0;
|
||
557 | Ry[i] = 0.0;
|
||
558 | |||
559 | if ((z = px + 2.0) > 0.0) |
||
560 | Rx[i] += z * z * z; |
||
561 | if ((z = px + 1.0) > 0.0) |
||
562 | Rx[i] += -4.0 * z * z * z;
|
||
563 | if ((z = px + 0.0) > 0.0) |
||
564 | Rx[i] += 6.0 * z * z * z;
|
||
565 | if ((z = px - 1.0) > 0.0) |
||
566 | Rx[i] += -4.0 * z * z * z;
|
||
567 | if ((z = py + 2.0) > 0.0) |
||
568 | Ry[i] += z * z * z; |
||
569 | if ((z = py + 1.0) > 0.0) |
||
570 | Ry[i] += -4.0 * z * z * z;
|
||
571 | if ((z = py + 0.0) > 0.0) |
||
572 | Ry[i] += 6.0 * z * z * z;
|
||
573 | if ((z = py - 1.0) > 0.0) |
||
574 | Ry[i] += -4.0 * z * z * z;
|
||
575 | |||
576 | Rx[i] /= 6.0;
|
||
577 | Ry[i] /= 6.0;
|
||
578 | } |
||
579 | |||
580 | for (iy = 0, z = 0.0; iy < 4; iy++) { |
||
581 | for (ix = 0; ix < 4; ix++) { |
||
582 | z += kernel[ix][iy] * Rx[ix] * Ry[iy]; |
||
583 | } |
||
584 | } |
||
585 | return z;
|
||
586 | } |
||
587 | |||
588 | /**
|
||
589 | * Calcula los valores N y Z para el m?todo bilinear y obtiene el valor del
|
||
590 | * pixel como
|
||
591 | * Z / N
|
||
592 | *
|
||
593 | * @param dx
|
||
594 | * distancia en X desde el centro del pixel hasta el punto. Es un
|
||
595 | * valor entre 0 y 1
|
||
596 | * @param dy
|
||
597 | * distancia en Y desde el centro del pixel hasta el punto. Es un
|
||
598 | * valor entre 0 y 1
|
||
599 | * @param kernel
|
||
600 | * valor del pixel y alrededor
|
||
601 | * @return valor del pixel
|
||
602 | */
|
||
603 | private double getBilinearValue(double dx, double dy, double[] kernel) { |
||
604 | double z = 0.0, n = 0.0, d; |
||
605 | d = (1.0 - dx) * (1.0 - dy); |
||
606 | z += d * kernel[0];
|
||
607 | n += d; |
||
608 | |||
609 | d = dx * (1.0 - dy);
|
||
610 | z += d * kernel[1];
|
||
611 | n += d; |
||
612 | |||
613 | d = (1.0 - dx) * dy;
|
||
614 | z += d * kernel[2];
|
||
615 | n += d; |
||
616 | |||
617 | d = dx * dy; |
||
618 | z += d * kernel[3];
|
||
619 | n += d; |
||
620 | |||
621 | double b = 0; |
||
622 | if (n > 0.0) { |
||
623 | b = (z / n); |
||
624 | } |
||
625 | return b;
|
||
626 | } |
||
627 | |||
628 | /**
|
||
629 | * Calcula los valores N y Z para el m?todo de distancia inversa y calcula
|
||
630 | * el valor del
|
||
631 | * pixel como Z / N.
|
||
632 | *
|
||
633 | * @param dx
|
||
634 | * distancia en X desde el centro del pixel hasta el punto. Es un
|
||
635 | * valor entre 0 y 1
|
||
636 | * @param dy
|
||
637 | * distancia en Y desde el centro del pixel hasta el punto. Es un
|
||
638 | * valor entre 0 y 1
|
||
639 | * @param kernel
|
||
640 | * valor del pixel y alrededor
|
||
641 | * @return valor del pixel
|
||
642 | */
|
||
643 | private double getInverseDistanceValue(double dx, double dy, double[] kernel) { |
||
644 | double z = 0.0, n = 0.0, d; |
||
645 | double t = Math.sqrt(dx * dx + dy * dy); |
||
646 | d = 1.0 / ((t == 0) ? 0.5 : t); |
||
647 | z += d * kernel[0];
|
||
648 | n += d; |
||
649 | |||
650 | t = Math.sqrt((1.0 - dx) * (1.0 - dx) + dy * dy); |
||
651 | d = 1.0 / ((t == 0) ? 0.5 : t); |
||
652 | z += d * kernel[1];
|
||
653 | n += d; |
||
654 | |||
655 | t = Math.sqrt(dx * dx + (1.0 - dy) * (1.0 - dy)); |
||
656 | d = 1.0 / ((t == 0) ? 0.5 : t); |
||
657 | z += d * kernel[2];
|
||
658 | n += d; |
||
659 | |||
660 | t = Math.sqrt((1.0 - dx) * (1.0 - dx) + (1.0 - dy) * (1.0 - dy)); |
||
661 | d = 1.0 / ((t == 0) ? 0.5 : t); |
||
662 | z += d * kernel[3];
|
||
663 | n += d; |
||
664 | |||
665 | double b = 0; |
||
666 | if (n > 0.0) { |
||
667 | b = (z / n); |
||
668 | } |
||
669 | return b;
|
||
670 | } |
||
671 | |||
672 | /**
|
||
673 | * Obtiene un kernel de 4x4 elementos. Si alguno de los elementos se sale de
|
||
674 | * la imagen
|
||
675 | * , por ejemplo en los bordes devuelve null.
|
||
676 | *
|
||
677 | * @param column
|
||
678 | * @param row
|
||
679 | * @param band
|
||
680 | * @return
|
||
681 | */
|
||
682 | private double[][] get4x4Submatrix( int row, int column, Buffer buffer, Band band) { |
||
683 | int ix, iy, px, py;
|
||
684 | double[][] z_xy = new double[4][4]; |
||
685 | |||
686 | for (iy = 0, py = row - 1; iy < 4; iy++, py++) { |
||
687 | for (ix = 0, px = column - 1; ix < 4; ix++, px++) { |
||
688 | if (!buffer.isInside(px, py)) {
|
||
689 | return null; |
||
690 | } else {
|
||
691 | z_xy[ix][iy] = getBandValueToDouble(py, px, band); |
||
692 | } |
||
693 | } |
||
694 | } |
||
695 | return z_xy;
|
||
696 | } |
||
697 | |||
698 | /**
|
||
699 | * Obtiene un kernel de cuatro elemento que corresponden a los pixeles (x,
|
||
700 | * y), (x + 1, y),
|
||
701 | * (x, y + 1), (x + 1, y + 1). Si los pixeles x + 1 o y + 1 se salen del
|
||
702 | * raster de origen
|
||
703 | * se tomar? x e y.
|
||
704 | *
|
||
705 | * @param x
|
||
706 | * Coordenada X del pixel inicial
|
||
707 | * @param y
|
||
708 | * Coordenada Y del pixel inicial
|
||
709 | * @param band
|
||
710 | * the band
|
||
711 | * @return Kernel solicitado en forma de array.
|
||
712 | */
|
||
713 | private double[] getKernel(int row, int column, Band band) { |
||
714 | double[] d = new double[4]; |
||
715 | d[0] = getBandValueToDouble(row, column, band);
|
||
716 | int nextColumn = ((column + 1) >= band.getColumns()) ? column : (column + 1); |
||
717 | int nextRow = ((row + 1) >= band.getRows()) ? row : (row + 1); |
||
718 | d[1] = getBandValueToDouble(row, nextColumn, band);
|
||
719 | d[2] = getBandValueToDouble(nextRow, column, band);
|
||
720 | d[3] = getBandValueToDouble(nextRow, nextColumn, band);
|
||
721 | return d;
|
||
722 | } |
||
723 | |||
724 | private double getBandValueToDouble(int row, int column, Band band) { |
||
725 | switch (band.getDataType()) {
|
||
726 | case BufferManager.TYPE_BYTE:
|
||
727 | return ((BandByte) band).getValue(row, column) & 0xff; |
||
728 | case BufferManager.TYPE_SHORT:
|
||
729 | case BufferManager.TYPE_USHORT:
|
||
730 | return ((BandShort) band).getValue(row, column) & 0xffff; |
||
731 | case BufferManager.TYPE_INT:
|
||
732 | return ((BandInt) band).getValue(row, column) & 0xffffffff; |
||
733 | case BufferManager.TYPE_FLOAT:
|
||
734 | return ((BandFloat) band).getValue(row, column);
|
||
735 | case BufferManager.TYPE_DOUBLE:
|
||
736 | return ((BandDouble) band).getValue(row, column);
|
||
737 | default:
|
||
738 | throw new IllegalArgumentException("Unknow dataType " + band.getDataType() + "."); |
||
739 | } |
||
740 | } |
||
741 | |||
742 | private void setBandValueFromDouble(int row, int column, Band band, Number value) { |
||
743 | switch (band.getDataType()) {
|
||
744 | case BufferManager.TYPE_BYTE:
|
||
745 | 5531 | llmarques | ((BandByte) band).setValue(row, column, value.byteValue()); |
746 | break;
|
||
747 | 5527 | fdiaz | case BufferManager.TYPE_SHORT:
|
748 | case BufferManager.TYPE_USHORT:
|
||
749 | 5531 | llmarques | ((BandShort) band).setValue(row, column, value.shortValue()); |
750 | break;
|
||
751 | 5527 | fdiaz | case BufferManager.TYPE_INT:
|
752 | 5531 | llmarques | ((BandInt) band).setValue(row, column, value.intValue()); |
753 | break;
|
||
754 | 5527 | fdiaz | case BufferManager.TYPE_FLOAT:
|
755 | 5531 | llmarques | ((BandFloat) band).setValue(row, column, value.floatValue()); |
756 | break;
|
||
757 | 5527 | fdiaz | case BufferManager.TYPE_DOUBLE:
|
758 | 5531 | llmarques | ((BandDouble) band).setValue(row, column, value.doubleValue()); |
759 | break;
|
||
760 | 5527 | fdiaz | default:
|
761 | throw new IllegalArgumentException("Unknow dataType " + band.getDataType() + "."); |
||
762 | } |
||
763 | } |
||
764 | } |