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 / BufferInterpolation.java @ 43867
History | View | Annotate | Download (28.2 KB)
1 |
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 |
|
14 |
import org.slf4j.Logger; |
15 |
import org.slf4j.LoggerFactory; |
16 |
|
17 |
/**
|
18 |
* @author fdiaz
|
19 |
*
|
20 |
*/
|
21 |
public class BufferInterpolation { |
22 |
|
23 |
private static final Logger LOG = LoggerFactory.getLogger(BufferInterpolation.class); |
24 |
|
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 |
public void nearestNeighbourInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
42 |
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 |
int rows = target.getRows();
|
53 |
int columns = target.getColumns();
|
54 |
|
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 |
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 |
if (targetRow != previousTargetRow) {
|
70 |
if (stepX < 1) { // submuestreo X |
71 |
submuestreoX(source, stepX, sourceBand, targetBand, sourceRow, targetRow); |
72 |
} else {
|
73 |
supermuestreoX(columns, stepX, sourceBand, targetBand, sourceRow, targetRow); |
74 |
} |
75 |
status.setCurValue(count+=source.getColumns()); |
76 |
if (status.isCancelled()) {
|
77 |
status.abort(); |
78 |
return;
|
79 |
} |
80 |
previousTargetRow = targetRow; |
81 |
} else {
|
82 |
count += source.getColumns(); |
83 |
status.setCurValue(count); |
84 |
} |
85 |
} |
86 |
} 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 |
} |
94 |
status.setCurValue(count+=source.getColumns()); |
95 |
if (status.isCancelled()) {
|
96 |
status.abort(); |
97 |
return;
|
98 |
} |
99 |
} |
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 |
* @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 |
* 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 |
public void bilinearInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
188 |
|
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 |
status.add(); |
198 |
try {
|
199 |
int rows = target.getRows();
|
200 |
int columns = target.getColumns();
|
201 |
|
202 |
double pxSizeX = (double) source.getColumns() / (double) columns; |
203 |
double pxSizeY = (double) source.getRows() / (double) rows; |
204 |
|
205 |
double posX, posY;
|
206 |
double dx = 0D, dy = 0D; |
207 |
int bandCount = source.getBandCount();
|
208 |
for (int iBand = 0; iBand < bandCount; iBand++) { |
209 |
status.setRangeOfValues(0, source.getRows());
|
210 |
status.message("Interpolating, band "+iBand+"/"+ bandCount); |
211 |
status.setCurValue(0);
|
212 |
posY = pxSizeY / 2D;
|
213 |
Band sourceBand = source.getBand(iBand); |
214 |
Band targetBand = target.getBand(iBand); |
215 |
for (int iRow = 0; iRow < rows; iRow++) { |
216 |
status.setCurValue(iRow); |
217 |
if (status.isCancelled()) {
|
218 |
status.abort(); |
219 |
return;
|
220 |
} |
221 |
dy = posY - ((int) posY);
|
222 |
posX = pxSizeX / 2D;
|
223 |
for (int iCol = 0; iCol < columns; iCol++) { |
224 |
dx = posX - ((int) posX);
|
225 |
try {
|
226 |
double[] kernel = getKernel((int) posY, (int) posX, sourceBand); |
227 |
setBandValueFromDouble(iRow, iCol, targetBand, getBilinearValue(dx, dy, kernel)); |
228 |
} catch (ArrayIndexOutOfBoundsException e) { |
229 |
LOG.warn( |
230 |
"Array index out of bounds exception. [band rows: {} band cols: {} row: {} col: {} dx: {} dy: {}]",
|
231 |
new Object[] { targetBand.getRows(), targetBand.getColumns(), iRow, |
232 |
iCol, dx, dy}); |
233 |
} |
234 |
posX += pxSizeX; |
235 |
} |
236 |
posY += pxSizeY; |
237 |
} |
238 |
} |
239 |
|
240 |
if (isMyStatus) {
|
241 |
status.terminate(); |
242 |
} else {
|
243 |
status.pop(); |
244 |
} |
245 |
} catch (Exception e) { |
246 |
status.abort(); |
247 |
throw e;
|
248 |
} |
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 |
public void inverseDistanceInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
288 |
|
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 |
int rows = target.getRows();
|
299 |
int columns = target.getColumns();
|
300 |
|
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 |
for (int iRow = 0; iRow < rows; iRow++) { |
315 |
dy = posY - ((int) posY);
|
316 |
posX = pxSizeX / 2D;
|
317 |
for (int iCol = 0; iCol < columns; iCol++) { |
318 |
status.setCurValue(count++); |
319 |
if (status.isCancelled()) {
|
320 |
status.abort(); |
321 |
return;
|
322 |
} |
323 |
dx = posX - ((int) posX);
|
324 |
try {
|
325 |
double[] kernel = getKernel(((int) posY), ((int) posX), sourceBand); |
326 |
setBandValueFromDouble(iRow, iCol, targetBand, getInverseDistanceValue(dx, dy, kernel)); |
327 |
} catch (ArrayIndexOutOfBoundsException e) { |
328 |
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 |
} |
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 |
public void bicubicSplineInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
362 |
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 |
int rows = target.getRows();
|
372 |
int columns = target.getColumns();
|
373 |
|
374 |
double pxSizeX = (double) source.getColumns() / (double) columns; |
375 |
double pxSizeY = (double) source.getRows() / (double) rows; |
376 |
|
377 |
status.setRangeOfValues(0, source.getRows()*source.getBandCount());
|
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 |
for (int iRow = 0; iRow < rows; iRow++) { |
388 |
status.setCurValue(count++); |
389 |
if (status.isCancelled()) {
|
390 |
status.abort(); |
391 |
return;
|
392 |
} |
393 |
dy = posY - ((int) posY);
|
394 |
posX = pxSizeX / 2D;
|
395 |
for (int iCol = 0; iCol < columns; iCol++) { |
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 |
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 |
} |
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 |
public void bSplineInterpolation(Buffer source, Buffer target, SimpleTaskStatus status) { |
439 |
|
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 |
int rows = target.getRows();
|
450 |
int columns = target.getColumns();
|
451 |
|
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 |
for (int iRow = 0; iRow < rows; iRow++) { |
466 |
dy = posY - ((int) posY);
|
467 |
posX = pxSizeX / 2D;
|
468 |
for (int iCol = 0; iCol < columns; iCol++) { |
469 |
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 |
double[] kernel = getKernel( ((int) posY), ((int) posX),sourceBand); |
479 |
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 |
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 |
} |
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 |
((BandByte) band).setValue(row, column, value.byteValue()); |
746 |
break;
|
747 |
case BufferManager.TYPE_SHORT:
|
748 |
case BufferManager.TYPE_USHORT:
|
749 |
((BandShort) band).setValue(row, column, value.shortValue()); |
750 |
break;
|
751 |
case BufferManager.TYPE_INT:
|
752 |
((BandInt) band).setValue(row, column, value.intValue()); |
753 |
break;
|
754 |
case BufferManager.TYPE_FLOAT:
|
755 |
((BandFloat) band).setValue(row, column, value.floatValue()); |
756 |
break;
|
757 |
case BufferManager.TYPE_DOUBLE:
|
758 |
((BandDouble) band).setValue(row, column, value.doubleValue()); |
759 |
break;
|
760 |
default:
|
761 |
throw new IllegalArgumentException("Unknow dataType " + band.getDataType() + "."); |
762 |
} |
763 |
} |
764 |
} |