/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
* http://www.geo-solutions.it/
* Copyright 2014 GeoSolutions
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package it.geosolutions.jaiext.interpolators;
import it.geosolutions.jaiext.range.Range;
import java.awt.Rectangle;
import java.awt.image.DataBuffer;
import javax.media.jai.InterpolationTable;
import javax.media.jai.RasterAccessor;
import javax.media.jai.iterator.RandomIter;
public class InterpolationBicubic extends InterpolationTable implements InterpolationNoData{
/** serialVersionUID */
private static final long serialVersionUID = -3699824574811467489L;
/**
* Default value for precision bits
* */
public static final int PRECISION_BITS = 8;
/** The scaled (by 2<sup>precisionBits</sup>) value of 0.5 for rounding */
private int round;
/** Range of NO DATA values to be checked */
private Range noDataRange;
/** ROI bounds used for checking the position of the pixel */
private Rectangle roiBounds;
/** Boolean for checking if the ROI Accessor must be used by the interpolator */
private boolean useROIAccessor;
/**
* Destination NO DATA value used when the image pixel is outside of the ROI or is contained in the NO DATA range
* */
private double destinationNoData;
/** This value is the destination NO DATA values for binary images */
private int black;
/** Image data Type */
private int dataType;
/** Boolean used for indicating that the No Data Range is not degenarated(useful only for NaN check inside Float or Double Range) */
private boolean isNotPointRange;
private boolean isBicubic2;
/**
* Simple interpolator object used for Bicubic/Bicubic2 interpolation. On construction it is possible to set a range for no data values that will
* be considered in the interpolation method.
*/
public InterpolationBicubic(int subsampleBits, Range noDataRange,
boolean useROIAccessor, double destinationNoData, int dataType, boolean bicubic2Disabled, int precisionBits) {
super(1, 1, 4, 4, subsampleBits, subsampleBits, precisionBits, dataHelper(subsampleBits,
bicubic2Disabled), null);
if (noDataRange != null) {
this.noDataRange = noDataRange;
this.isNotPointRange = !noDataRange.isPoint();
}
this.useROIAccessor = useROIAccessor;
this.destinationNoData = destinationNoData;
black = ((int) destinationNoData) & 1;
this.dataType = dataType;
if (precisionBits > 0) {
round = 1 << (precisionBits - 1);
}
this.isBicubic2 = !bicubic2Disabled;
}
public void setROIBounds(Rectangle roiBounds){
this.roiBounds = roiBounds;
}
public double getDestinationNoData() {
return destinationNoData;
}
public void setDestinationNoData(double destinationNoData) {
this.destinationNoData = destinationNoData;
}
public Range getNoDataRange() {
return noDataRange;
}
public void setNoDataRange(Range noDataRange) {
if (noDataRange != null) {
this.noDataRange = noDataRange;
this.isNotPointRange = !noDataRange.isPoint();
}
}
public boolean getUseROIAccessor() {
return useROIAccessor;
}
public void setUseROIAccessor(boolean useROIAccessor) {
this.useROIAccessor = useROIAccessor;
}
public boolean isBicubic2(){
return isBicubic2;
}
public int getDataType() {
return dataType;
}
public static float[] dataHelper(int subsampleBits, boolean bicubic2Disabled) {
int one = 1 << subsampleBits;
int arrayLength = one * 4;
float tableValues[] = new float[arrayLength];
float f;
float onef = (float) one;
// float t;
int count = 0;
for (int i = 0; i < one; i++) {
// t = (float) i;
f = (i / onef);
tableValues[count++] = bicubic(f + 1.0F, bicubic2Disabled);
tableValues[count++] = bicubic(f, bicubic2Disabled);
tableValues[count++] = bicubic(f - 1.0F, bicubic2Disabled);
tableValues[count++] = bicubic(f - 2.0F, bicubic2Disabled);
}
return tableValues;
}
/** Returns the bicubic polynomial value at a certain value of x. */
public static float bicubic(float x, boolean bicubic2Disabled) {
if (x < 0) {
x = -x;
}
float A = 0;
// If bicubic2Disabled is true, the parameters used are those of the bicubic interpolation.
// If bicubic2Disabled is false, the parameters used are those of the bicubic2 interpolation.
if (bicubic2Disabled) {
// The parameter "a" for the bicubic polynomial
A = -0.5F;
} else {
// The parameter "a" for the bicubic2 polynomial
A = -1.0F;
}
// Define all of the polynomial coefficients in terms of "a"
float A3 = A + 2.0F;
float A2 = -(A + 3.0F);
float A0 = 1.0F;
float B3 = A;
float B2 = -(5.0F * A);
float B1 = 8.0F * A;
float B0 = -(4.0F * A);
// Evaluate with Horner's rule
if (x >= 1) {
return (((B3 * x) + B2) * x + B1) * x + B0;
} else {
return ((A3 * x) + A2) * x * x + A0;
}
}
public Number interpolate(RasterAccessor src, int bandIndex, int dnumbands, int posx, int posy,
Number[] fracValues, Integer yValueROI, RasterAccessor roi, RandomIter roiIter, boolean setNoData) {
// If this pixel doesn't need any computation, destination NO DATA is returned.
if (setNoData) {
return destinationNoData;
}
// ------------------------------DATA-INITIALIZATION------------------------------
// Value used for setting the position of the pixel inside the interpolation kernel
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
// Position of the interpolation pixel kernel
// x axis
int posxlow = posx - srcPixelStride;
int posxhigh = posx + srcPixelStride;
int posxhigh2 = posxhigh + srcPixelStride;
// y axis
int posylow = posy - srcScanlineStride;
int posyhigh = posy + srcScanlineStride;
int posyhigh2 = posyhigh + srcScanlineStride;
// Pixel initialization. For float and double dataType, different pixel are used
int s__ = 0, s_0 = 0, s_1 = 0, s_2 = 0;
int s0_ = 0, s00 = 0, s01 = 0, s02 = 0;
int s1_ = 0, s10 = 0, s11 = 0, s12 = 0;
int s2_ = 0, s20 = 0, s21 = 0, s22 = 0;
float s__f = 0, s_0f = 0, s_1f = 0, s_2f = 0;
float s0_f = 0, s00f = 0, s01f = 0, s02f = 0;
float s1_f = 0, s10f = 0, s11f = 0, s12f = 0;
float s2_f = 0, s20f = 0, s21f = 0, s22f = 0;
double s__d = 0, s_0d = 0, s_1d = 0, s_2d = 0;
double s0_d = 0, s00d = 0, s01d = 0, s02d = 0;
double s1_d = 0, s10d = 0, s11d = 0, s12d = 0;
double s2_d = 0, s20d = 0, s21d = 0, s22d = 0;
// src data array initialization
byte[] srcDataByte;
short[] srcDataShort;
int[] srcDataInt;
float[] srcDataFloat;
double[] srcDataDouble;
// Fractional Value
int xfrac = 0;
int yfrac = 0;
// Offset initialization for interpolation on X axis.
int offsetX = 0;
// Offset initialization for interpolation on Y axis.
int offsetY = 0;
// All the data are inserted into an array for simplify the code.
int[][] kernelArray = new int[4][4];
float[][] kernelArrayF = new float[4][4];
double[][] kernelArrayD = new double[4][4];
// Get the sixteen surrounding pixel values (same code, only the dataType is changed)
switch (dataType) {
case DataBuffer.TYPE_BYTE:
// Src data
srcDataByte = src.getByteDataArray(bandIndex);
// Selection of the 16 values from the src data
kernelArray[0][0] = s__ = srcDataByte[posxlow + posylow] & 0xff;
kernelArray[0][1] = s_0 = srcDataByte[posx + posylow] & 0xff;
kernelArray[0][2] = s_1 = srcDataByte[posxhigh + posylow] & 0xff;
kernelArray[0][3] = s_2 = srcDataByte[posxhigh2 + posylow] & 0xff;
kernelArray[1][0] = s0_ = srcDataByte[posxlow + posy] & 0xff;
kernelArray[1][1] = s00 = srcDataByte[posx + posy] & 0xff;
kernelArray[1][2] = s01 = srcDataByte[posxhigh + posy] & 0xff;
kernelArray[1][3] = s02 = srcDataByte[posxhigh2 + posy] & 0xff;
kernelArray[2][0] = s1_ = srcDataByte[posxlow + posyhigh] & 0xff;
kernelArray[2][1] = s10 = srcDataByte[posx + posyhigh] & 0xff;
kernelArray[2][2] = s11 = srcDataByte[posxhigh + posyhigh] & 0xff;
kernelArray[2][3] = s12 = srcDataByte[posxhigh2 + posyhigh] & 0xff;
kernelArray[3][0] = s2_ = srcDataByte[posxlow + posyhigh2] & 0xff;
kernelArray[3][1] = s20 = srcDataByte[posx + posyhigh2] & 0xff;
kernelArray[3][2] = s21 = srcDataByte[posxhigh + posyhigh2] & 0xff;
kernelArray[3][3] = s22 = srcDataByte[posxhigh2 + posyhigh2] & 0xff;
// fractional x and y value
xfrac = fracValues[0].intValue();
yfrac = fracValues[1].intValue();
// offset calculated from the fractional values
offsetX = 4 * xfrac;
offsetY = 4 * yfrac;
break;
case DataBuffer.TYPE_USHORT:
srcDataShort = src.getShortDataArray(bandIndex);
kernelArray[0][0] = s__ = srcDataShort[posxlow + posylow] & 0xffff;
kernelArray[0][1] = s_0 = srcDataShort[posx + posylow] & 0xffff;
kernelArray[0][2] = s_1 = srcDataShort[posxhigh + posylow] & 0xffff;
kernelArray[0][3] = s_2 = srcDataShort[posxhigh2 + posylow] & 0xffff;
kernelArray[1][0] = s0_ = srcDataShort[posxlow + posy] & 0xffff;
kernelArray[1][1] = s00 = srcDataShort[posx + posy] & 0xffff;
kernelArray[1][2] = s01 = srcDataShort[posxhigh + posy] & 0xffff;
kernelArray[1][3] = s02 = srcDataShort[posxhigh2 + posy] & 0xffff;
kernelArray[2][0] = s1_ = srcDataShort[posxlow + posyhigh] & 0xffff;
kernelArray[2][1] = s10 = srcDataShort[posx + posyhigh] & 0xffff;
kernelArray[2][2] = s11 = srcDataShort[posxhigh + posyhigh] & 0xffff;
kernelArray[2][3] = s12 = srcDataShort[posxhigh2 + posyhigh] & 0xffff;
kernelArray[3][0] = s2_ = srcDataShort[posxlow + posyhigh2] & 0xffff;
kernelArray[3][1] = s20 = srcDataShort[posx + posyhigh2] & 0xffff;
kernelArray[3][2] = s21 = srcDataShort[posxhigh + posyhigh2] & 0xffff;
kernelArray[3][3] = s22 = srcDataShort[posxhigh2 + posyhigh2] & 0xffff;
xfrac = fracValues[0].intValue();
yfrac = fracValues[1].intValue();
offsetX = 4 * xfrac;
offsetY = 4 * yfrac;
break;
case DataBuffer.TYPE_SHORT:
srcDataShort = src.getShortDataArray(bandIndex);
kernelArray[0][0] = s__ = srcDataShort[posxlow + posylow];
kernelArray[0][1] = s_0 = srcDataShort[posx + posylow];
kernelArray[0][2] = s_1 = srcDataShort[posxhigh + posylow];
kernelArray[0][3] = s_2 = srcDataShort[posxhigh2 + posylow];
kernelArray[1][0] = s0_ = srcDataShort[posxlow + posy];
kernelArray[1][1] = s00 = srcDataShort[posx + posy];
kernelArray[1][2] = s01 = srcDataShort[posxhigh + posy];
kernelArray[1][3] = s02 = srcDataShort[posxhigh2 + posy];
kernelArray[2][0] = s1_ = srcDataShort[posxlow + posyhigh];
kernelArray[2][1] = s10 = srcDataShort[posx + posyhigh];
kernelArray[2][2] = s11 = srcDataShort[posxhigh + posyhigh];
kernelArray[2][3] = s12 = srcDataShort[posxhigh2 + posyhigh];
kernelArray[3][0] = s2_ = srcDataShort[posxlow + posyhigh2];
kernelArray[3][1] = s20 = srcDataShort[posx + posyhigh2];
kernelArray[3][2] = s21 = srcDataShort[posxhigh + posyhigh2];
kernelArray[3][3] = s22 = srcDataShort[posxhigh2 + posyhigh2];
xfrac = fracValues[0].intValue();
yfrac = fracValues[1].intValue();
offsetX = 4 * xfrac;
offsetY = 4 * yfrac;
break;
case DataBuffer.TYPE_INT:
srcDataInt = src.getIntDataArray(bandIndex);
kernelArray[0][0] = s__ = srcDataInt[posxlow + posylow];
kernelArray[0][1] = s_0 = srcDataInt[posx + posylow];
kernelArray[0][2] = s_1 = srcDataInt[posxhigh + posylow];
kernelArray[0][3] = s_2 = srcDataInt[posxhigh2 + posylow];
kernelArray[1][0] = s0_ = srcDataInt[posxlow + posy];
kernelArray[1][1] = s00 = srcDataInt[posx + posy];
kernelArray[1][2] = s01 = srcDataInt[posxhigh + posy];
kernelArray[1][3] = s02 = srcDataInt[posxhigh2 + posy];
kernelArray[2][0] = s1_ = srcDataInt[posxlow + posyhigh];
kernelArray[2][1] = s10 = srcDataInt[posx + posyhigh];
kernelArray[2][2] = s11 = srcDataInt[posxhigh + posyhigh];
kernelArray[2][3] = s12 = srcDataInt[posxhigh2 + posyhigh];
kernelArray[3][0] = s2_ = srcDataInt[posxlow + posyhigh2];
kernelArray[3][1] = s20 = srcDataInt[posx + posyhigh2];
kernelArray[3][2] = s21 = srcDataInt[posxhigh + posyhigh2];
kernelArray[3][3] = s22 = srcDataInt[posxhigh2 + posyhigh2];
long xfracL = fracValues[0].longValue();
long yfracL = fracValues[1].longValue();
offsetX = (int) (4 * xfracL);
offsetY = (int) (4 * yfracL);
break;
case DataBuffer.TYPE_FLOAT:
srcDataFloat = src.getFloatDataArray(bandIndex);
kernelArrayF[0][0] = s__f = srcDataFloat[posxlow + posylow];
kernelArrayF[0][1] = s_0f = srcDataFloat[posx + posylow];
kernelArrayF[0][2] = s_1f = srcDataFloat[posxhigh + posylow];
kernelArrayF[0][3] = s_2f = srcDataFloat[posxhigh2 + posylow];
kernelArrayF[1][0] = s0_f = srcDataFloat[posxlow + posy];
kernelArrayF[1][1] = s00f = srcDataFloat[posx + posy];
kernelArrayF[1][2] = s01f = srcDataFloat[posxhigh + posy];
kernelArrayF[1][3] = s02f = srcDataFloat[posxhigh2 + posy];
kernelArrayF[2][0] = s1_f = srcDataFloat[posxlow + posyhigh];
kernelArrayF[2][1] = s10f = srcDataFloat[posx + posyhigh];
kernelArrayF[2][2] = s11f = srcDataFloat[posxhigh + posyhigh];
kernelArrayF[2][3] = s12f = srcDataFloat[posxhigh2 + posyhigh];
kernelArrayF[3][0] = s2_f = srcDataFloat[posxlow + posyhigh2];
kernelArrayF[3][1] = s20f = srcDataFloat[posx + posyhigh2];
kernelArrayF[3][2] = s21f = srcDataFloat[posxhigh + posyhigh2];
kernelArrayF[3][3] = s22f = srcDataFloat[posxhigh2 + posyhigh2];
xfrac = (int) (fracValues[0].floatValue()*subsampleBitsH);
yfrac = (int) (fracValues[1].floatValue()*subsampleBitsH);
offsetX = 4 * xfrac;
offsetY = 4 * yfrac;
break;
case DataBuffer.TYPE_DOUBLE:
srcDataDouble = src.getDoubleDataArray(bandIndex);
kernelArrayD[0][0] = s__d = srcDataDouble[posxlow + posylow];
kernelArrayD[0][1] = s_0d = srcDataDouble[posx + posylow];
kernelArrayD[0][2] = s_1d = srcDataDouble[posxhigh + posylow];
kernelArrayD[0][3] = s_2d = srcDataDouble[posxhigh2 + posylow];
kernelArrayD[1][0] = s0_d = srcDataDouble[posxlow + posy];
kernelArrayD[1][1] = s00d = srcDataDouble[posx + posy];
kernelArrayD[1][2] = s01d = srcDataDouble[posxhigh + posy];
kernelArrayD[1][3] = s02d = srcDataDouble[posxhigh2 + posy];
kernelArrayD[2][0] = s1_d = srcDataDouble[posxlow + posyhigh];
kernelArrayD[2][1] = s10d = srcDataDouble[posx + posyhigh];
kernelArrayD[2][2] = s11d = srcDataDouble[posxhigh + posyhigh];
kernelArrayD[2][3] = s12d = srcDataDouble[posxhigh2 + posyhigh];
kernelArrayD[3][0] = s2_d = srcDataDouble[posxlow + posyhigh2];
kernelArrayD[3][1] = s20d = srcDataDouble[posx + posyhigh2];
kernelArrayD[3][2] = s21d = srcDataDouble[posxhigh + posyhigh2];
kernelArrayD[3][3] = s22d = srcDataDouble[posxhigh2 + posyhigh2];
xfrac = (int) (fracValues[0].doubleValue()*subsampleBitsH);
yfrac = (int) (fracValues[1].doubleValue()*subsampleBitsH);
offsetX = 4 * xfrac;
offsetY = 4 * yfrac;
break;
default:
break;
}
// Weight initialization
double[][] weightArray = new double[4][4];
int weightArrayLength = weightArray.length;
// ------------------------------ROI-CONTROL---------------------------------------------------
// Temporary ROI values initialization
byte tempValueB = 0;
short tempValueS = 0;
// int tempValueI = 0;
// float tempValueF = 0;
double tempValueD = 0;
if (useROIAccessor) {
if (yValueROI == null || roi == null) {
throw new IllegalArgumentException(
"If rasterAccessor is set, ROI value must be provided");
}
// ROI scan line stride used for selecting the 4 surrounding pixels
int roiScanLineStride = roi.getScanlineStride();
int[][] weightArrayIndex = new int[4][4];
int baseIndex = (posx / dnumbands) + (yValueROI);
// cycle for filling all the ROI index by shifting of 1 on the x axis
// and by roiscanlinestride on the y axis.
for (int i = 0; i < weightArrayIndex.length; i++) {
for (int j = 0; j < weightArrayIndex.length; j++) {
weightArrayIndex[i][j] = baseIndex - 1 + j + (i - 1) * (roiScanLineStride);
}
}
// Array length initialization
int roiDataLength = 0;
// Check if the selected index belongs to the roi data array: if it is not present, the weight is 0,
// Otherwise it takes the related value.
byte[] roiDataArrayByte = roi.getByteDataArray(0);
roiDataLength = roiDataArrayByte.length;
if(baseIndex>roiDataLength || roiDataArrayByte[baseIndex]==0){
return destinationNoData;
}
switch (dataType) {
case DataBuffer.TYPE_BYTE:
for (int i = 0; i < weightArrayIndex.length; i++) {
for (int j = 0; j < weightArrayIndex.length; j++) {
if (weightArrayIndex[i][j] < roiDataLength) {
// Save the roi value in a temporary image.
tempValueB = (byte) (roiDataArrayByte[weightArrayIndex[i][j]] & 0xff);
// Multiply the pixel weight to the new ROI weight.
weightArray[i][j] = (tempValueB != 0 ? 1 : 0);
} else {
weightArray[i][j] = 0;
}
}
}
break;
case DataBuffer.TYPE_USHORT:
// short[] roiDataArrayUShort = roi.getShortDataArray(bandIndex);
// roiDataLength = roiDataArrayUShort.length;
for (int i = 0; i < weightArrayIndex.length; i++) {
for (int j = 0; j < weightArrayIndex.length; j++) {
if (weightArrayIndex[i][j] < roiDataLength) {
tempValueS = (short) (roiDataArrayByte[weightArrayIndex[i][j]] & 0xffff);
weightArray[i][j] = (tempValueS != 0 ? 1 : 0);
} else {
weightArray[i][j] = 0;
}
}
}
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_INT:
case DataBuffer.TYPE_FLOAT:
case DataBuffer.TYPE_DOUBLE:
for (int i = 0; i < weightArrayIndex.length; i++) {
for (int j = 0; j < weightArrayIndex.length; j++) {
if (weightArrayIndex[i][j] < roiDataLength) {
tempValueD = roiDataArrayByte[weightArrayIndex[i][j]];
weightArray[i][j] = (tempValueD != 0 ? 1 : 0);
} else {
weightArray[i][j] = 0;
}
}
}
break;
default:
break;
}
// If all the pixel values are outside the ROI, the destination NO DATA value is returned.
if (sumZero(weightArray)==0) {
return destinationNoData;
}
} else if (roiBounds != null) {
int srcBandOffset = src.getBandOffset(bandIndex);
// Central pixel positions
int x0 = src.getX() + posx / srcPixelStride;
int y0 = src.getY() + (posy - srcBandOffset) / srcScanlineStride;
// ROI control
if (roiBounds.contains(x0, y0)) {
switch (dataType) {
case DataBuffer.TYPE_BYTE:
for (int i = 0; i < weightArray.length; i++) {
for (int j = 0; j < weightArray.length; j++) {
tempValueB = (byte) (roiIter.getSample(x0 + j - 1, y0 + i - 1, 0) & 0xFF);
weightArray[i][j] = (tempValueB != 0 ? 1 : 0);
}
}
break;
case DataBuffer.TYPE_USHORT:
for (int i = 0; i < weightArray.length; i++) {
for (int j = 0; j < weightArray.length; j++) {
tempValueS = (short) (roiIter.getSample(x0 + j - 1, y0 + i - 1, 0) & 0xFFFF);
weightArray[i][j] = (tempValueS != 0 ? 1 : 0);
}
}
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_INT:
case DataBuffer.TYPE_FLOAT:
case DataBuffer.TYPE_DOUBLE:
for (int i = 0; i < weightArray.length; i++) {
for (int j = 0; j < weightArray.length; j++) {
tempValueD = roiIter.getSample(x0 + j - 1, y0 + i - 1, 0);
weightArray[i][j] = (tempValueD != 0 ? 1 : 0);
}
}
break;
default:
break;
}
// If all the pixel values are outside the ROI, the destination NO DATA value is returned.
if (sumZero(weightArray)==0) {
return destinationNoData;
}
} else {
return destinationNoData;
}
}
// If The pixel is not outside the ROI
for (int i = 0; i < weightArrayLength; i++) {
for (int j = 0; j < weightArrayLength; j++) {
weightArray[i][j] = 1;
}
}
// -------------------------NO-DATA-CONTROL--------------------------------
if (noDataRange != null) {
switch (dataType) {
case DataBuffer.TYPE_BYTE:
// Range cast to the selcted data Type
Range rangeB = noDataRange;
// Every pixel is tested if it is a NO DATA.
// If so, the associated weight is set to 0, else to 1.
for (int i = 0; i < weightArrayLength; i++) {
for (int j = 0; j < weightArrayLength; j++) {
if (rangeB.contains((byte) kernelArray[i][j])) {
weightArray[i][j] *= 0;
}
}
}
break;
case DataBuffer.TYPE_USHORT:
case DataBuffer.TYPE_SHORT:
Range rangeS = noDataRange;
for (int i = 0; i < weightArrayLength; i++) {
for (int j = 0; j < weightArrayLength; j++) {
if (rangeS.contains((short) kernelArray[i][j])) {
weightArray[i][j] *= 0;
}
}
}
break;
case DataBuffer.TYPE_INT:
Range rangeI = noDataRange;
for (int i = 0; i < weightArrayLength; i++) {
for (int j = 0; j < weightArrayLength; j++) {
if (rangeI.contains((int) kernelArray[i][j])) {
weightArray[i][j] *= 0;
}
}
}
break;
case DataBuffer.TYPE_FLOAT:
Range rangeF = noDataRange;
for (int i = 0; i < weightArrayLength; i++) {
for (int j = 0; j < weightArrayLength; j++) {
if (rangeF.contains(kernelArrayF[i][j])|| (isNotPointRange && Float.isNaN(kernelArrayF[i][j]))) {
weightArray[i][j] *= 0;
}
}
}
break;
case DataBuffer.TYPE_DOUBLE:
Range rangeD = noDataRange;
for (int i = 0; i < weightArrayLength; i++) {
for (int j = 0; j < weightArrayLength; j++) {
if (rangeD.contains(kernelArrayD[i][j])|| (isNotPointRange && Double.isNaN(kernelArrayD[i][j]))) {
weightArray[i][j] *= 0;
}
}
}
break;
default:
break;
}
}
// If all the pixel values are NO DATA, the destination NO DATA value is returned.
if (sumZero(weightArray)==0) {
return destinationNoData;
}
// -----------------BICUBIC-INTERPOLATION---------------------------------------
// Initial sum value.
long sum = 0;
double sumd = 0;
// Interpolate in X
int offsetX1 = offsetX + 1;
int offsetX2 = offsetX + 2;
int offsetX3 = offsetX + 3;
// Interpolate in y
int offsetY1 = offsetY + 1;
int offsetY2 = offsetY + 2;
int offsetY3 = offsetY + 3;
//boolean array for evaluating if every weight line is composed by 0
boolean[] weight0 = new boolean[4];
// Array containg only 1 value, an array of all the
for(int ii =0;ii<4;ii++){
double[][] lineArray={weightArray[ii]};
if(sumZero(lineArray)==0){
weight0[ii]=true;
}else{
weight0[ii]=false;
}
}
switch (dataType) {
case DataBuffer.TYPE_BYTE:
case DataBuffer.TYPE_USHORT:
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_INT:
//Inpainting of the no data values by substituting them with the neighbor values
long[] valueArray_=bicubicInpainting(s__, s_0, s_1, s_2, weightArray[0], null);
long[] valueArray0=bicubicInpainting(s0_, s00, s01, s02, weightArray[1], null);
long[] valueArray1=bicubicInpainting(s1_, s10, s11, s12, weightArray[2], null);
long[] valueArray2=bicubicInpainting(s2_, s20, s21, s22, weightArray[3], null);
// Interpolation on the X axis
long sum_ = dataHi[offsetX] * valueArray_[0];
sum_ += dataHi[offsetX1] * valueArray_[1];
sum_ += dataHi[offsetX2] * valueArray_[2];
sum_ += dataHi[offsetX3] * valueArray_[3];
long sum0 = dataHi[offsetX] * valueArray0[0];
sum0 += dataHi[offsetX1] * valueArray0[1];
sum0 += dataHi[offsetX2] * valueArray0[2];
sum0 += dataHi[offsetX3] * valueArray0[3];
long sum1 = dataHi[offsetX] * valueArray1[0];
sum1 += dataHi[offsetX1] * valueArray1[1];
sum1 += dataHi[offsetX2] * valueArray1[2];
sum1 += dataHi[offsetX3] * valueArray1[3];
long sum2 = dataHi[offsetX] * valueArray2[0];
sum2 += dataHi[offsetX1] * valueArray2[1];
sum2 += dataHi[offsetX2] * valueArray2[2];
sum2 += dataHi[offsetX3] * valueArray2[3];
// Intermediate rounding
sum_ = (sum_ + round) >> precisionBits;
sum0 = (sum0 + round) >> precisionBits;
sum1 = (sum1 + round) >> precisionBits;
sum2 = (sum2 + round) >> precisionBits;
//Inpainting of the no data values by substituting them with the neighbor values
long[] valueArrayV=bicubicInpainting(sum_, sum0, sum1, sum2, null,weight0);
// Interpolation on the Y axis
sum = dataVi[offsetY] * valueArrayV[0];
sum += dataVi[offsetY1] * valueArrayV[1];
sum += dataVi[offsetY2] * valueArrayV[2];
sum += dataVi[offsetY3] * valueArrayV[3];
break;
case DataBuffer.TYPE_FLOAT:
//Inpainting of the no data values by substituting them with the neighbor values
float[] valueArrayf_=bicubicInpaintingFloat(s__f, s_0f, s_1f, s_2f, weightArray[0], null);
float[] valueArrayf0=bicubicInpaintingFloat(s0_f, s00f, s01f, s02f, weightArray[1], null);
float[] valueArrayf1=bicubicInpaintingFloat(s1_f, s10f, s11f, s12f, weightArray[2], null);
float[] valueArrayf2=bicubicInpaintingFloat(s2_f, s20f, s21f, s22f, weightArray[3], null);
// Interpolation on the X axis
double sum_f = dataHf[offsetX] * valueArrayf_[0];
sum_f += dataHf[offsetX1] * valueArrayf_[1];
sum_f += dataHf[offsetX2] * valueArrayf_[2];
sum_f += dataHf[offsetX3] * valueArrayf_[3];
double sum0f = dataHf[offsetX] * valueArrayf0[0];
sum0f += dataHf[offsetX1] * valueArrayf0[1];
sum0f += dataHf[offsetX2] * valueArrayf0[2];
sum0f += dataHf[offsetX3] * valueArrayf0[3];
double sum1f = dataHf[offsetX] * valueArrayf1[0];
sum1f += dataHf[offsetX1] * valueArrayf1[1];
sum1f += dataHf[offsetX2] * valueArrayf1[2];
sum1f += dataHf[offsetX3] * valueArrayf1[3];
double sum2f = dataHf[offsetX] * valueArrayf2[0];
sum2f += dataHf[offsetX1] * valueArrayf2[1];
sum2f += dataHf[offsetX2] * valueArrayf2[2];
sum2f += dataHf[offsetX3] * valueArrayf2[3];
//Inpainting of the no data values by substituting them with the neighbor values
double[] valueArrayVf=bicubicInpaintingDouble(sum_f, sum0f, sum1f, sum2f, null,weight0);
// Interpolation on the Y axis
sumd = dataVf[offsetY] * valueArrayVf[0];
sumd += dataVf[offsetY + 1] * valueArrayVf[1];
sumd += dataVf[offsetY + 2] * valueArrayVf[2];
sumd += dataVf[offsetY + 3] * valueArrayVf[3];
// Data Clamping
if (sumd > Float.MAX_VALUE) {
sumd = Float.MAX_VALUE;
} else if (sumd < -Float.MAX_VALUE) {
sumd = -Float.MAX_VALUE;
}
return sumd;
case DataBuffer.TYPE_DOUBLE:
//Inpainting of the no data values by substituting them with the neighbor values
double[] valueArrayd_=bicubicInpaintingDouble(s__d, s_0d, s_1d, s_2d, weightArray[0], null);
double[] valueArrayd0=bicubicInpaintingDouble(s0_d, s00d, s01d, s02d, weightArray[0], null);
double[] valueArrayd1=bicubicInpaintingDouble(s1_d, s10d, s11d, s12d, weightArray[0], null);
double[] valueArrayd2=bicubicInpaintingDouble(s2_d, s20d, s21d, s22d, weightArray[0], null);
// Interpolation on the X axis
double sum_d = dataHd[offsetX] * valueArrayd_[0];
sum_d += dataHd[offsetX1] * valueArrayd_[1];
sum_d += dataHd[offsetX2] * valueArrayd_[2];
sum_d += dataHd[offsetX3] * valueArrayd_[3];
double sum0d = dataHd[offsetX] * valueArrayd0[0];
sum0d += dataHd[offsetX1] * valueArrayd0[1];
sum0d += dataHd[offsetX2] * valueArrayd0[2];
sum0d += dataHd[offsetX3] * valueArrayd0[3];
double sum1d = dataHd[offsetX] * valueArrayd1[0];
sum1d += dataHd[offsetX1] * valueArrayd1[1];
sum1d += dataHd[offsetX2] * valueArrayd1[2];
sum1d += dataHd[offsetX3] * valueArrayd1[3];
double sum2d = dataHd[offsetX] * valueArrayd2[0];
sum2d += dataHd[offsetX1] * valueArrayd2[1];
sum2d += dataHd[offsetX2] * valueArrayd2[2];
sum2d += dataHd[offsetX3] * valueArrayd2[3];
//Inpainting of the no data values by substituting them with the neighbor values
double[] valueArrayVd=bicubicInpaintingDouble(sum_d, sum0d, sum1d, sum2d, null,weight0);
// Interpolation on the Y axis
sumd = dataVd[offsetY] * valueArrayVd[0];
sumd += dataVd[offsetY + 1] * valueArrayVd[1];
sumd += dataVd[offsetY + 2] * valueArrayVd[2];
sumd += dataVd[offsetY + 3] * valueArrayVd[3];
return sumd;
default:
break;
}
// Result calculation (only for integer/short/ushort/byte)
int s = (int) ((sum + round) >> precisionBits);
// Data Clamping
switch (dataType) {
case DataBuffer.TYPE_BYTE:
if (s > 255) {
s = 255;
} else if (s < 0) {
s = 0;
}
break;
case DataBuffer.TYPE_USHORT:
if (s > 65536) {
s = 65536;
} else if (s < 0) {
s = 0;
}
break;
case DataBuffer.TYPE_SHORT:
if (s > Short.MAX_VALUE) {
s = Short.MAX_VALUE;
} else if (s < Short.MIN_VALUE) {
s = Short.MIN_VALUE;
}
break;
case DataBuffer.TYPE_INT:
break;
}
return s;
}
//This method is used for filling the no data values inside the interpolation kernel with the values of the adjacent pixels
private long[] bicubicInpainting(long s_, long s0, long s1, long s2, double[] weightArray, boolean[] weight0){
if(weightArray == null){
weightArray=new double[4];
if(s_==0 && weight0[0]){
weightArray[0]=0;
}else{
weightArray[0]=1;
}
if(s0==0 && weight0[1]){
weightArray[1]=0;
}else{
weightArray[1]=1;
}
if(s1==0 && weight0[2]){
weightArray[2]=0;
}else{
weightArray[2]=1;
}
if(s2==0 && weight0[3]){
weightArray[3]=0;
}else{
weightArray[3]=1;
}
}
double[][] array = {weightArray};
//empty array containing the final values of the selected 4 pixels
long[] emptyArray=new long[4];
//Calculation of the number of data
int sum = (int) sumZero(array);
// mean value used in calculations
long meanValue=0;
switch(sum){
// All the 4 pixels are no data, an array of 0 data is returned
case 0:
return emptyArray;
// Only one pixel is a valid data, all the pixel of the line have the same value.
case 1:
long validData=0;
if(weightArray[0]==1){
validData=s_;
}else if(weightArray[1]==1){
validData=s0;
}else if(weightArray[2]==1){
validData=s1;
}else{
validData=s2;
}
emptyArray[0]=validData;
emptyArray[1]=validData;
emptyArray[2]=validData;
emptyArray[3]=validData;
return emptyArray;
// Only 2 pixels are valid data. If the No Data are on the border, they takes the value of the adjacent pixel,
// else , they take an average of the 2 neighbor pixels with valid data. A String representation is provided for a better
// comprehension. 0 is no Data and x is valid data.
case 2:
// 0 0 x x
if(weightArray[0]==0 && weightArray[1]==0){
emptyArray[0]=s1;
emptyArray[1]=s1;
emptyArray[2]=s1;
emptyArray[3]=s2;
// 0 x 0 x
}else if(weightArray[0]==0 && weightArray[2]==0){
meanValue= (s0 + s2)/2;
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// 0 x x 0
}else if(weightArray[0]==0 && weightArray[3]==0){
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s1;
// x 0 0 x
}else if(weightArray[1]==0 && weightArray[2]==0){
meanValue= (s_ + s2)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// x 0 x 0
}else if(weightArray[1]==0 && weightArray[3]==0){
meanValue= (s_ + s1)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=s1;
emptyArray[3]=s1;
// x x 0 0
}else{
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s0;
emptyArray[3]=s0;
}
return emptyArray;
// Only one pixel is a No Data. If it is at the boundaries, then it replicates the value
// of the adjacent pixel, else if takes an average of the 2 neighbor pixels.A String representation is provided for a better
// comprehension. 0 is no Data and x is valid data.
case 3:
// 0 x x x
if(weightArray[0]==0){
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s2;
// x 0 x x
}else if(weightArray[1]==0){
meanValue= (s_ + s1)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=s1;
emptyArray[3]=s2;
// x x 0 x
}else if(weightArray[2]==0){
meanValue= (s0 + s2)/2;
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// x x x 0
}else{
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s1;
}
return emptyArray;
// Absence of No Data, the pixels are returned.
case 4:
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s2;
return emptyArray;
default:
throw new IllegalArgumentException("The input array cannot have more than 4 pixels");
}
}
//This method is used for filling the no data values inside the interpolation kernel with the values of the adjacent pixels
private float[] bicubicInpaintingFloat(float s_, float s0, float s1, float s2, double[] weightArray, boolean[] weight0){
if(weightArray == null){
weightArray=new double[4];
if(s_==0 && weight0[0]){
weightArray[0]=0;
}else{
weightArray[0]=1;
}
if(s0==0 && weight0[1]){
weightArray[1]=0;
}else{
weightArray[1]=1;
}
if(s1==0 && weight0[2]){
weightArray[2]=0;
}else{
weightArray[2]=1;
}
if(s2==0 && weight0[3]){
weightArray[3]=0;
}else{
weightArray[3]=1;
}
}
double[][] array = {weightArray};
//empty array containing the final values of the selected 4 pixels
float[] emptyArray=new float[4];
//Calculation of the number of data
int sum = (int) sumZero(array);
// mean value used in calculations
float meanValue=0;
switch(sum){
// All the 4 pixels are no data, an array of 0 data is returned
case 0:
return emptyArray;
// Only one pixel is a valid data, all the pixel of the line have the same value.
case 1:
float validData=0;
if(weightArray[0]==1){
validData=s_;
}else if(weightArray[1]==1){
validData=s0;
}else if(weightArray[2]==1){
validData=s1;
}else{
validData=s2;
}
emptyArray[0]=validData;
emptyArray[1]=validData;
emptyArray[2]=validData;
emptyArray[3]=validData;
return emptyArray;
// Only 2 pixels are valid data. If the No Data are on the border, they takes the value of the adjacent pixel,
// else , they take an average of the 2 neighbor pixels with valid data. A String representation is provided for a better
// comprehension. 0 is no Data and x is valid data.
case 2:
// 0 0 x x
if(weightArray[0]==0 && weightArray[1]==0){
emptyArray[0]=s1;
emptyArray[1]=s1;
emptyArray[2]=s1;
emptyArray[3]=s2;
// 0 x 0 x
}else if(weightArray[0]==0 && weightArray[2]==0){
meanValue= (s0 + s2)/2;
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// 0 x x 0
}else if(weightArray[0]==0 && weightArray[3]==0){
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s1;
// x 0 0 x
}else if(weightArray[1]==0 && weightArray[2]==0){
meanValue= (s_ + s2)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// x 0 x 0
}else if(weightArray[1]==0 && weightArray[3]==0){
meanValue= (s_ + s1)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=s1;
emptyArray[3]=s1;
// x x 0 0
}else{
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s0;
emptyArray[3]=s0;
}
return emptyArray;
// Only one pixel is a No Data. If it is at the boundaries, then it replicates the value
// of the adjacent pixel, else if takes an average of the 2 neighbor pixels.A String representation is provided for a better
// comprehension. 0 is no Data and x is valid data.
case 3:
// 0 x x x
if(weightArray[0]==0){
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s2;
// x 0 x x
}else if(weightArray[1]==0){
meanValue= (s_ + s1)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=s1;
emptyArray[3]=s2;
// x x 0 x
}else if(weightArray[2]==0){
meanValue= (s0 + s2)/2;
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// x x x 0
}else{
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s1;
}
return emptyArray;
// Absence of No Data, the pixels are returned.
case 4:
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s2;
return emptyArray;
default:
throw new IllegalArgumentException("The input array cannot have more than 4 pixels");
}
}
//This method is used for filling the no data values inside the interpolation kernel with the values of the adjacent pixels
private double[] bicubicInpaintingDouble(double s_, double s0, double s1, double s2, double[] weightArray, boolean[] weight0){
if(weightArray == null){
weightArray=new double[4];
if(s_==0 && weight0[0]){
weightArray[0]=0;
}else{
weightArray[0]=1;
}
if(s0==0 && weight0[1]){
weightArray[1]=0;
}else{
weightArray[1]=1;
}
if(s1==0 && weight0[2]){
weightArray[2]=0;
}else{
weightArray[2]=1;
}
if(s2==0 && weight0[3]){
weightArray[3]=0;
}else{
weightArray[3]=1;
}
}
double[][] array = {weightArray};
//empty array containing the final values of the selected 4 pixels
double[] emptyArray=new double[4];
//Calculation of the number of data
int sum = (int) sumZero(array);
// mean value used in calculations
double meanValue=0;
switch(sum){
// All the 4 pixels are no data, an array of 0 data is returned
case 0:
return emptyArray;
// Only one pixel is a valid data, all the pixel of the line have the same value.
case 1:
double validData=0;
if(weightArray[0]==1){
validData=s_;
}else if(weightArray[1]==1){
validData=s0;
}else if(weightArray[2]==1){
validData=s1;
}else{
validData=s2;
}
emptyArray[0]=validData;
emptyArray[1]=validData;
emptyArray[2]=validData;
emptyArray[3]=validData;
return emptyArray;
// Only 2 pixels are valid data. If the No Data are on the border, they takes the value of the adjacent pixel,
// else , they take an average of the 2 neighbor pixels with valid data. A String representation is provided for a better
// comprehension. 0 is no Data and x is valid data.
case 2:
// 0 0 x x
if(weightArray[0]==0 && weightArray[1]==0){
emptyArray[0]=s1;
emptyArray[1]=s1;
emptyArray[2]=s1;
emptyArray[3]=s2;
// 0 x 0 x
}else if(weightArray[0]==0 && weightArray[2]==0){
meanValue= (s0 + s2)/2;
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// 0 x x 0
}else if(weightArray[0]==0 && weightArray[3]==0){
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s1;
// x 0 0 x
}else if(weightArray[1]==0 && weightArray[2]==0){
meanValue= (s_ + s2)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// x 0 x 0
}else if(weightArray[1]==0 && weightArray[3]==0){
meanValue= (s_ + s1)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=s1;
emptyArray[3]=s1;
// x x 0 0
}else{
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s0;
emptyArray[3]=s0;
}
return emptyArray;
// Only one pixel is a No Data. If it is at the boundaries, then it replicates the value
// of the adjacent pixel, else if takes an average of the 2 neighbor pixels.A String representation is provided for a better
// comprehension. 0 is no Data and x is valid data.
case 3:
// 0 x x x
if(weightArray[0]==0){
emptyArray[0]=s0;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s2;
// x 0 x x
}else if(weightArray[1]==0){
meanValue= (s_ + s1)/2;
emptyArray[0]=s_;
emptyArray[1]=meanValue;
emptyArray[2]=s1;
emptyArray[3]=s2;
// x x 0 x
}else if(weightArray[2]==0){
meanValue= (s0 + s2)/2;
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=meanValue;
emptyArray[3]=s2;
// x x x 0
}else{
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s1;
}
return emptyArray;
// Absence of No Data, the pixels are returned.
case 4:
emptyArray[0]=s_;
emptyArray[1]=s0;
emptyArray[2]=s1;
emptyArray[3]=s2;
return emptyArray;
default:
throw new IllegalArgumentException("The input array cannot have more than 4 pixels");
}
}
// This method compute the sum of all the elements inside the array
private double sumZero(double[][] values) {
// sum initialization
double sum = 0;
// cycle through all the values and update the sum value
for (int i = 0; i < values.length; i++) {
for (int j = 0; j < values[i].length; j++) {
sum += values[i][j];
}
}
return sum;
}
public int interpolateBinary(int xNextBitNo, Number[] sourceData, int xfrac, int yfrac,
int sourceYOffset, int sourceScanlineStride, int[] coordinates,int[] roiDataArray, int roiYOffset, int roiScanlineStride, RandomIter roiIter) {
// -----------------DATA-INITIALIZATION------------------------------------------------
// 16 surrounding pixel initialization
int[][] bitArray = new int[4][4];
int[] byteshift=null;
int[] shortshift=null;
int[] intshift=null;
// xNextBitNo is the shift inside the pixel element, to the bit on the right of the selected one
// Calculates the bit number of the selected pixel's position
int sbitnum = xNextBitNo - 1;
// Shift inside the pixel element, to the bit on the left of the selected one.
int xBeforeBitNo = sbitnum - 1;
// Shift inside the pixel element, to the second bit on the right of the selected one.
int xNextBitNo2 = sbitnum + 2;
// initialization of the shift bit array
int[] bitshift = new int[4];
// Offset initialization for interpolation on X axis.
int offsetX = 0;
// Offset initialization for interpolation on Y axis.
int offsetY = 0;
// Calculates the interpolation for every type of data that allows binary images.
switch (dataType) {
case DataBuffer.TYPE_BYTE:
// initialization of the shift byte array
byteshift = new int[4];
// This value is used for searching the selected pixel inside the element.
bitshift[1] = 7 - (sbitnum & 7);
// Conversion from bit to Byte for searching the element in which the selected pixel is found.
byteshift[1] = sbitnum >> 3;
// int sbytenum = sbitnum >> 3;
// This value is used for searching the pixel on the right of the selected one inside the element.
bitshift[2] = 7 - (xNextBitNo & 7);
// Conversion from bit to Byte for searching the element of the pixel on the right of the selected one.
byteshift[2] = xNextBitNo >> 3;
// int xNextByteNo = xNextBitNo >> 3;
// This value is used for searching the pixel on the left of the selected one inside the element.
bitshift[0] = 7 - (xBeforeBitNo & 7);
// Conversion from bit to Byte for searching the element of the pixel on the left of the selected one.
byteshift[0] = xBeforeBitNo >> 3;
// int xBeforeByteNo = xBeforeBitNo >> 3;
// This value is used for searching the second pixel on the right of the selected one inside the element.
bitshift[3] = 7 - (xNextBitNo2 & 7);
// Conversion from bit to Byte for searching the element of the second pixel on the right of the selected one.
byteshift[3] = xNextBitNo2 >> 3;
// int xNextByteNo2 = xNextBitNo2 >> 3;
// Searching of the 16 pixels surrounding the selected one.
for (int i = 0; i < bitArray.length; i++) {
for (int j = 0; j < bitArray.length; j++) {
bitArray[i][j] = (sourceData[sourceYOffset + ((i - 1) * sourceScanlineStride)
+ byteshift[j]].byteValue() >> bitshift[j]) & 0x01;
}
}
break;
case DataBuffer.TYPE_USHORT:
case DataBuffer.TYPE_SHORT:
// initialization of the shift byte array
shortshift = new int[4];
// This value is used for searching the selected pixel inside the element.
bitshift[1] = 15 - (sbitnum & 15);
// Conversion from bit to Short.
shortshift[1] = sbitnum >> 4;
// This value is used for searching the pixel on the right of the selected one inside the element.
bitshift[2] = 15 - (xNextBitNo & 15);
// Conversion from bit to Short.
shortshift[2] = xNextBitNo >> 4;
// This value is used for searching the pixel on the left of the selected one inside the element.
bitshift[0] = 15 - (xBeforeBitNo & 15);
// Conversion from bit to Short.
shortshift[0] = xBeforeBitNo >> 4;
// This value is used for searching the second pixel on the right of the selected one inside the element.
bitshift[3] = 15 - (xNextBitNo2 & 15);
// Conversion from bit to Short.
shortshift[3] = xNextBitNo2 >> 4;
// Searching of the 16 pixels surrounding the selected one.
for (int i = 0; i < bitArray.length; i++) {
for (int j = 0; j < bitArray.length; j++) {
bitArray[i][j] = (sourceData[sourceYOffset + ((i - 1) * sourceScanlineStride)
+ shortshift[j]].shortValue() >> bitshift[j]) & 0x01;
}
}
break;
case DataBuffer.TYPE_INT:
// initialization of the shift byte array
intshift = new int[4];
// This value is used for searching the selected pixel inside the element.
bitshift[1] = 31 - (sbitnum & 31);
// Conversion from bit to Integer.
intshift[1] = sbitnum >> 5;
// This value is used for searching the pixel on the right of the selected one inside the element.
bitshift[2] = 31 - (xNextBitNo & 31);
// Conversion from bit to Integer.
intshift[2] = xNextBitNo >> 5;
// This value is used for searching the pixel on the left of the selected one inside the element.
bitshift[0] = 31 - (xBeforeBitNo & 31);
// Conversion from bit to Integer.
intshift[0] = xBeforeBitNo >> 5;
// This value is used for searching the second pixel on the right of the selected one inside the element.
bitshift[3] = 31 - (xNextBitNo2 & 31);
// Conversion from bit to Integer.
intshift[3] = xNextBitNo2 >> 5;
// Searching of the 16 pixels surrounding the selected one.
for (int i = 0; i < bitArray.length; i++) {
for (int j = 0; j < bitArray.length; j++) {
bitArray[i][j] = (sourceData[sourceYOffset + ((i - 1) * sourceScanlineStride)
+ intshift[j]].intValue() >> bitshift[j]) & 0x01;
}
}
break;
default:
break;
}
// --------------------------ROI-CONTROL------------------------------------------------------
// If an image ROI has been saved, this ROI is used for checking if
// all the surrounding pixel belongs to the ROI.
// Initial weight array as an array of ones.
int[][] weightArray = new int[4][4];
for (int i = 0; i < weightArray.length; i++) {
for (int j = 0; j < weightArray.length; j++) {
weightArray[i][j] = 1;
}
}
if(useROIAccessor){
int roiDataLength=roiDataArray.length;
int[] sbyteShortIntShift = null;
switch(dataType){
case DataBuffer.TYPE_BYTE:
sbyteShortIntShift=byteshift;
break;
case DataBuffer.TYPE_USHORT:
case DataBuffer.TYPE_SHORT:
sbyteShortIntShift=shortshift;
break;
case DataBuffer.TYPE_INT:
sbyteShortIntShift=intshift;
break;
}
int sum = 0;
for (int i = 0; i < weightArray.length; i++) {
for (int j = 0; j < weightArray.length; j++) {
int windex = roiYOffset + sbyteShortIntShift[j] + (i-1)*roiScanlineStride;
if((windex>roiDataLength || (roiDataArray[windex]>> bitshift[j] & 0x01)==0) && (i==1&&j==1) ){
return black;
}
weightArray[i][j]=windex<roiDataLength ? roiDataArray[windex]>> bitshift[j] & 0x01 : 0;
sum += weightArray[i][j];
}
}
if (sum == 0) {
return black;
}
}else if (coordinates != null && roiBounds != null) {
// Central pixel positions
int x0 = coordinates[0];
int y0 = coordinates[1];
// ROI control
if (roiBounds.contains(x0, y0)) {
// Total weight sum
int sum = 0;
// Temporary variable for storing the iterators result
int valueIter = 0;
for (int i = 0; i < weightArray.length; i++) {
for (int j = 0; j < weightArray.length; j++) {
valueIter = roiIter.getSample(x0 + j - 1, y0 + i - 1, 0) & 0x01;
sum += valueIter;
weightArray[i][j] = valueIter;
}
}
// If the total weight sum is 0 no more computations are performed
if (sum == 0) {
return black;
}
} else {// If the pixel is outside the ROI no more computations are performed
return black;
}
}
// -----------------BICUBIC-INTERPOLATION-----------------------------------------------------
long[] sumH = new long[4];
long sum = 0;
for (int i = 0; i < sumH.length; i++) {
sumH[i] = 0;
for (int j = 0; j < sumH.length; j++) {
// Interpolation on the X axis
sumH[i] += (long) dataHi[offsetX + j] * bitArray[i][j];
}
// Intermediate rounding
sumH[i] = (sumH[i] + round) >> precisionBits;
// Interpolation on the Y axis
sum += (long) dataVi[offsetY + i] * sumH[i];
}
return (int)((sum + round) >> precisionBits);
}
}