/* 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.warp; import it.geosolutions.jaiext.range.Range; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.IndexColorModel; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.util.Map; import javax.media.jai.BorderExtender; import javax.media.jai.ImageLayout; import javax.media.jai.Interpolation; import javax.media.jai.InterpolationTable; import javax.media.jai.PlanarImage; import javax.media.jai.ROI; import javax.media.jai.RasterAccessor; import javax.media.jai.Warp; import javax.media.jai.iterator.RandomIter; /** * An <code>OpImage</code> implementing the general "Warp" operation as described in <code>javax.media.jai.operator.WarpDescriptor</code>. It supports * the bicubic interpolation. * * <p> * The layout for the destination image may be specified via the <code>ImageLayout</code> parameter. However, only those settings suitable for this * operation will be used. The unsuitable settings will be replaced by default suitable values. An optional ROI object and a NoData Range can be used. * If a backward mapped pixel lies outside ROI or it is a NoData, then the destination pixel value is a background value. * * * @since EA2 * @see javax.media.jai.Warp * @see javax.media.jai.WarpOpImage * @see javax.media.jai.operator.WarpDescriptor * @see WarpRIF * */ @SuppressWarnings("unchecked") final class WarpBicubicOpImage extends WarpOpImage { /** Constant holding the bicubic kernel value */ private static final int KERNEL_LINE_DIM = 4; /** * Unsigned short Max Value */ protected static final int USHORT_MAX_VALUE = Short.MAX_VALUE - Short.MIN_VALUE; /** Color table representing source's IndexColorModel. */ private byte[][] ctable = null; /** LookupTable used for a faster NoData check */ private boolean[] booleanLookupTable; /** Integer coeffs for horizontal interpolation */ private int[] dataHi; /** Integer coeffs for vertical interpolation */ private int[] dataVi; /** Float coeffs for horizontal interpolation */ private float[] dataHf; /** Float coeffs for vertical interpolation */ private float[] dataVf; /** Double coeffs for horizontal interpolation */ private double[] dataHd; /** Double coeffs for vertical interpolation */ private double[] dataVd; /** Shift used in integer computations */ private int shift; /** Integer value used for rounding integer computations */ private int round; /** Precision bits used for expanding the integer interpolation */ private int precisionBits; /** * Constructs a WarpBilinearOpImage. * * @param source The source image. * @param extender A BorderExtender, or null. * @param config RenderingHints used in calculations. * @param layout The destination image layout. * @param warp An object defining the warp algorithm. * @param interp An object describing the interpolation method. * @param roi input ROI object used. * @param noData NoData Range object used for checking if NoData are present. */ public WarpBicubicOpImage(final RenderedImage source, final BorderExtender extender, final Map<?, ?> config, final ImageLayout layout, final Warp warp, final Interpolation interp, final ROI sourceROI, Range noData, double[] bkg) { super(source, layout, config, false, extender, interp, warp, bkg, sourceROI, noData); /* * If the source has IndexColorModel, get the RGB color table. Note, in this case, the source should have an integral data type. And dest * always has data type byte. */ final ColorModel srcColorModel = source.getColorModel(); if (srcColorModel instanceof IndexColorModel) { final IndexColorModel icm = (IndexColorModel) srcColorModel; ctable = new byte[3][icm.getMapSize()]; icm.getReds(ctable[0]); icm.getGreens(ctable[1]); icm.getBlues(ctable[2]); } /* * Selection of a destinationNoData value for each datatype */ //backgroundValues[b] = backgroundValues[0]; SampleModel sm = source.getSampleModel(); // Source image data Type int srcDataType = sm.getDataType(); // Creation of a lookuptable containing the values to use for no data if (srcDataType == DataBuffer.TYPE_BYTE && hasNoData) { booleanLookupTable = new boolean[256]; for (int i = 0; i < booleanLookupTable.length; i++) { byte value = (byte) i; booleanLookupTable[i] = noDataRange.contains(value); } } // Selection of the interpolation coefficients InterpolationTable interpCubic = (InterpolationTable) interp; switch (srcDataType) { case DataBuffer.TYPE_BYTE: case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_INT: dataHi = interpCubic.getHorizontalTableData(); dataVi = interpCubic.getVerticalTableData(); break; case DataBuffer.TYPE_FLOAT: dataHf = interpCubic.getHorizontalTableDataFloat(); dataVf = interpCubic.getVerticalTableDataFloat(); break; case DataBuffer.TYPE_DOUBLE: dataHd = interpCubic.getHorizontalTableDataDouble(); dataVd = interpCubic.getVerticalTableDataDouble(); break; default: throw new IllegalArgumentException("Wrong data Type"); } // Subsample bits used shift = 1 << interp.getSubsampleBitsH(); precisionBits = interpCubic.getPrecisionBits(); if (precisionBits > 0) { round = 1 << (precisionBits - 1); } // Definition of the padding leftPad = 1; rightPad = 2; topPad = 1; bottomPad = 2; } protected void computeRectByte(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator initialization, taking into account the presence of the borderExtender RandomIter iterSource; final int minX, maxX, minY, maxY; if (extended) { // Creation of an iterator on the image extended by the padding factors iterSource = getRandomIterator(src, leftPad, rightPad, topPad, bottomPad, extender); // Definition of the image bounds minX = src.getMinX(); maxX = src.getMaxX(); minY = src.getMinY(); maxY = src.getMaxY(); } else { // Creation of an iterator on the image iterSource = getRandomIterator(src, null); // Definition of the image bounds minX = src.getMinX() + leftPad; // Left padding maxX = src.getMaxX() - rightPad; // Right padding minY = src.getMinY() + topPad; // Top padding maxY = src.getMaxY() - bottomPad; // Bottom padding } final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final byte[][] data = dst.getByteDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // Creation of an iterator for the ROI Image if(hasROI && !roiContainsTile && roiIter == null){ throw new IllegalArgumentException("Error on creating the ROI iterator"); } if (ctable == null) { // source does not have IndexColorModel // ONLY VALID DATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NO ROI // for (int b = 0; b < dstBands; b++) { // Interpolation long result = (bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, null)); // Clamp if (result > 255) { result = 255; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (byte) (result & 0xff); } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { for (int b = 0; b < dstBands; b++) { // Interpolation long result = (bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, null)); // Clamp if (result > 255) { result = 255; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (byte) (result & 0xff); } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = iterSource.getSample(xint + (i - 1), yint + (j - 1), b) & 0xFF; pixelKernel[j][i] = sample; if (booleanLookupTable[sample]) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > 255) { result = 255; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (byte) (result & 0xff); } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // BOTH ROI AND NODATA } else { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = iterSource.getSample(xint + (i - 1), yint + (j - 1), b) & 0xFF; pixelKernel[j][i] = sample; if (booleanLookupTable[sample]) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > 255) { result = 255; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (byte) (result & 0xff); } } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP } } else {// source has IndexColorModel // ONLY VALID DATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NO ROI // for (int b = 0; b < dstBands; b++) { final byte[] t = ctable[b]; // Interpolation long result = (bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, t)); // Clamp if (result > 255) { result = 255; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (byte) (result & 0xff); } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { for (int b = 0; b < dstBands; b++) { final byte[] t = ctable[b]; // Interpolation long result = (bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, t)); // Clamp if (result > 255) { result = 255; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (byte) (result & 0xff); } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { final byte[] t = ctable[b]; // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = t[iterSource.getSample(xint + (i - 1), yint + (j - 1), 0) & 0xFF] & 0xFF; pixelKernel[j][i] = sample; if (booleanLookupTable[sample]) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > 255) { result = 255; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (byte) (result & 0xff); } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // BOTH ROI AND NODATA } else { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { final byte[] t = ctable[b]; // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = t[iterSource.getSample(xint + (i - 1), yint + (j - 1), 0) & 0xFF] & 0xFF; pixelKernel[j][i] = sample; if (booleanLookupTable[sample]) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > 255) { result = 255; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (byte) (result & 0xff); } } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP } } iterSource.done(); } protected void computeRectUShort(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator initialization, taking into account the presence of the borderExtender RandomIter iterSource; final int minX, maxX, minY, maxY; if (extended) { // Creation of an iterator on the image extended by the padding factors iterSource = getRandomIterator(src, leftPad, rightPad, topPad, bottomPad, extender); // Definition of the image bounds minX = src.getMinX(); maxX = src.getMaxX(); minY = src.getMinY(); maxY = src.getMaxY(); } else { // Creation of an iterator on the image iterSource = getRandomIterator(src, null); // Definition of the image bounds minX = src.getMinX() + leftPad; // Left padding maxX = src.getMaxX() - rightPad; // Right padding minY = src.getMinY() + topPad; // Top padding maxY = src.getMaxY() - bottomPad; // Bottom padding } final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final short[][] data = dst.getShortDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // Creation of an iterator for the ROI Image if(hasROI && !roiContainsTile && roiIter == null){ throw new IllegalArgumentException("Error on creating the ROI iterator"); } // source does not have IndexColorModel // ONLY VALID DATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NO ROI // for (int b = 0; b < dstBands; b++) { // Interpolation long result = (bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, null)); // Clamp if (result > USHORT_MAX_VALUE) { result = USHORT_MAX_VALUE; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (short) (result & 0xFFFF); } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { for (int b = 0; b < dstBands; b++) { // Interpolation long result = (bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, null)); // Clamp if (result > USHORT_MAX_VALUE) { result = USHORT_MAX_VALUE; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (short) (result & 0xFFFF); } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = iterSource.getSample(xint + (i - 1), yint + (j - 1), b) & 0xFFFF; pixelKernel[j][i] = sample; if (noDataRange.contains((short) sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > USHORT_MAX_VALUE) { result = USHORT_MAX_VALUE; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (short) (result & 0xFFFF); } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // BOTH ROI AND NODATA } else { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = iterSource.getSample(xint + (i - 1), yint + (j - 1), b) & 0xFFFF; pixelKernel[j][i] = sample; if (noDataRange.contains((short) sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > USHORT_MAX_VALUE) { result = USHORT_MAX_VALUE; } else if (result < 0) { result = 0; } data[b][pixelOffset + bandOffsets[b]] = (short) (result & 0xFFFF); } } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP } iterSource.done(); } protected void computeRectShort(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator initialization, taking into account the presence of the borderExtender RandomIter iterSource; final int minX, maxX, minY, maxY; if (extended) { // Creation of an iterator on the image extended by the padding factors iterSource = getRandomIterator(src, leftPad, rightPad, topPad, bottomPad, extender); // Definition of the image bounds minX = src.getMinX(); maxX = src.getMaxX(); minY = src.getMinY(); maxY = src.getMaxY(); } else { // Creation of an iterator on the image iterSource = getRandomIterator(src, null); // Definition of the image bounds minX = src.getMinX() + leftPad; // Left padding maxX = src.getMaxX() - rightPad; // Right padding minY = src.getMinY() + topPad; // Top padding maxY = src.getMaxY() - bottomPad; // Bottom padding } final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final short[][] data = dst.getShortDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // Creation of an iterator for the ROI Image if(hasROI && !roiContainsTile && roiIter == null){ throw new IllegalArgumentException("Error on creating the ROI iterator"); } // source does not have IndexColorModel // ONLY VALID DATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NO ROI // for (int b = 0; b < dstBands; b++) { // Interpolation long result = bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, null); // Clamp if (result > Short.MAX_VALUE) { result = Short.MAX_VALUE; } else if (result < Short.MIN_VALUE) { result = Short.MIN_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (short) (result); } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { for (int b = 0; b < dstBands; b++) { // Interpolation long result = bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, null); // Clamp if (result > Short.MAX_VALUE) { result = Short.MAX_VALUE; } else if (result < Short.MIN_VALUE) { result = Short.MIN_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (short) (result); } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = iterSource.getSample(xint + (i - 1), yint + (j - 1), b); pixelKernel[j][i] = sample; if (noDataRange.contains((short) sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > Short.MAX_VALUE) { result = Short.MAX_VALUE; } else if (result < Short.MIN_VALUE) { result = Short.MIN_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (short) (result); } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // BOTH ROI AND NODATA } else { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = iterSource.getSample(xint + (i - 1), yint + (j - 1), b); pixelKernel[j][i] = sample; if (noDataRange.contains((short) sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > Short.MAX_VALUE) { result = Short.MAX_VALUE; } else if (result < Short.MIN_VALUE) { result = Short.MIN_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (short) (result); } } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP } iterSource.done(); } protected void computeRectInt(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator initialization, taking into account the presence of the borderExtender RandomIter iterSource; final int minX, maxX, minY, maxY; if (extended) { // Creation of an iterator on the image extended by the padding factors iterSource = getRandomIterator(src, leftPad, rightPad, topPad, bottomPad, extender); // Definition of the image bounds minX = src.getMinX(); maxX = src.getMaxX(); minY = src.getMinY(); maxY = src.getMaxY(); } else { // Creation of an iterator on the image iterSource = getRandomIterator(src, null); // Definition of the image bounds minX = src.getMinX() + leftPad; // Left padding maxX = src.getMaxX() - rightPad; // Right padding minY = src.getMinY() + topPad; // Top padding maxY = src.getMaxY() - bottomPad; // Bottom padding } final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final int[][] data = dst.getIntDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // Creation of an iterator for the ROI Image if(hasROI && !roiContainsTile && roiIter == null){ throw new IllegalArgumentException("Error on creating the ROI iterator"); } // source does not have IndexColorModel // ONLY VALID DATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NO ROI // for (int b = 0; b < dstBands; b++) { // Interpolation long result = bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, null); // Clamp if (result > Integer.MAX_VALUE) { result = Integer.MAX_VALUE; } else if (result < Integer.MIN_VALUE) { result = Integer.MIN_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (int) (result); } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { for (int b = 0; b < dstBands; b++) { // Interpolation long result = bicubicCalculationInt(b, iterSource, xint, yint, offsetX, offsetY, null); // Clamp if (result > Integer.MAX_VALUE) { result = Integer.MAX_VALUE; } else if (result < Integer.MIN_VALUE) { result = Integer.MIN_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (int) (result); } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = iterSource.getSample(xint + (i - 1), yint + (j - 1), b); pixelKernel[j][i] = sample; if (noDataRange.contains(sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > Integer.MAX_VALUE) { result = Integer.MAX_VALUE; } else if (result < Integer.MIN_VALUE) { result = Integer.MIN_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (int) (result); } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // BOTH ROI AND NODATA } else { // Array used during calculations final long[][] pixelKernel = new long[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; long[] sumArray = new long[KERNEL_LINE_DIM]; long[] emptyArray = new long[KERNEL_LINE_DIM]; long[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization long tempSum = 0; long sum = 0; // final result initialization long result = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int sample = iterSource.getSample(xint + (i - 1), yint + (j - 1), b); pixelKernel[j][i] = sample; if (noDataRange.contains(sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpainting(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHi[offsetX] + tempData[1] * dataHi[offsetX + 1] + tempData[2] * dataHi[offsetX + 2] + tempData[3] * dataHi[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = ((tempSum + round) >> precisionBits); } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } else { tempData = bicubicInpainting(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVi[offsetY] + tempData[1] * dataVi[offsetY + 1] + tempData[2] * dataVi[offsetY + 2] + tempData[3] * dataVi[offsetY + 3]; // Interpolation result = ((sum + round) >> precisionBits); weight = 0; weightVert = 0; sum = 0; // Clamp if (result > Integer.MAX_VALUE) { result = Integer.MAX_VALUE; } else if (result < Integer.MIN_VALUE) { result = Integer.MIN_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (int) (result); } } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP } iterSource.done(); } protected void computeRectFloat(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator initialization, taking into account the presence of the borderExtender RandomIter iterSource; final int minX, maxX, minY, maxY; if (extended) { // Creation of an iterator on the image extended by the padding factors iterSource = getRandomIterator(src, leftPad, rightPad, topPad, bottomPad, extender); // Definition of the image bounds minX = src.getMinX(); maxX = src.getMaxX(); minY = src.getMinY(); maxY = src.getMaxY(); } else { // Creation of an iterator on the image iterSource = getRandomIterator(src, null); // Definition of the image bounds minX = src.getMinX() + leftPad; // Left padding maxX = src.getMaxX() - rightPad; // Right padding minY = src.getMinY() + topPad; // Top padding maxY = src.getMaxY() - bottomPad; // Bottom padding } final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final float[][] data = dst.getFloatDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // Creation of an iterator for the ROI Image if(hasROI && !roiContainsTile && roiIter == null){ throw new IllegalArgumentException("Error on creating the ROI iterator"); } // source does not have IndexColorModel // ONLY VALID DATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NO ROI // for (int b = 0; b < dstBands; b++) { // Interpolation double result = bicubicCalculationFloat(b, iterSource, xint, yint, offsetX, offsetY); // Clamp if (result > Float.MAX_VALUE) { result = Float.MAX_VALUE; } else if (result < -Float.MAX_VALUE) { result = -Float.MAX_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (float) (result); } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { for (int b = 0; b < dstBands; b++) { // Interpolation double result = bicubicCalculationFloat(b, iterSource, xint, yint, offsetX, offsetY); // Clamp if (result > Float.MAX_VALUE) { result = Float.MAX_VALUE; } else if (result < -Float.MAX_VALUE) { result = -Float.MAX_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (float) (result); } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { // Array used during calculations final double[][] pixelKernel = new double[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; double[] sumArray = new double[KERNEL_LINE_DIM]; double[] emptyArray = new double[KERNEL_LINE_DIM]; double[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization double tempSum = 0; double sum = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel float sample = iterSource.getSampleFloat(xint + (i - 1), yint + (j - 1), b); pixelKernel[j][i] = sample; if (noDataRange.contains(sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpaintingDouble(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHf[offsetX] + tempData[1] * dataHf[offsetX + 1] + tempData[2] * dataHf[offsetX + 2] + tempData[3] * dataHf[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = tempSum; } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } else { tempData = bicubicInpaintingDouble(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVf[offsetY] + tempData[1] * dataVf[offsetY + 1] + tempData[2] * dataVf[offsetY + 2] + tempData[3] * dataVf[offsetY + 3]; // Interpolation weight = 0; weightVert = 0; // Clamp if (sum > Float.MAX_VALUE) { sum = Float.MAX_VALUE; } else if (sum < -Float.MAX_VALUE) { sum = -Float.MAX_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (float) sum; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // BOTH ROI AND NODATA } else { // Array used during calculations final double[][] pixelKernel = new double[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; double[] sumArray = new double[KERNEL_LINE_DIM]; double[] emptyArray = new double[KERNEL_LINE_DIM]; double[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization double tempSum = 0; double sum = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel float sample = iterSource.getSampleFloat(xint + (i - 1), yint + (j - 1), b); pixelKernel[j][i] = sample; if (noDataRange.contains(sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpaintingDouble(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHf[offsetX] + tempData[1] * dataHf[offsetX + 1] + tempData[2] * dataHf[offsetX + 2] + tempData[3] * dataHf[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = tempSum; } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } else { tempData = bicubicInpaintingDouble(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVf[offsetY] + tempData[1] * dataVf[offsetY + 1] + tempData[2] * dataVf[offsetY + 2] + tempData[3] * dataVf[offsetY + 3]; // Interpolation weight = 0; weightVert = 0; // Clamp if (sum > Float.MAX_VALUE) { sum = Float.MAX_VALUE; } else if (sum < -Float.MAX_VALUE) { sum = -Float.MAX_VALUE; } data[b][pixelOffset + bandOffsets[b]] = (float) sum; } } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP } iterSource.done(); } protected void computeRectDouble(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator initialization, taking into account the presence of the borderExtender RandomIter iterSource; final int minX, maxX, minY, maxY; if (extended) { // Creation of an iterator on the image extended by the padding factors iterSource = getRandomIterator(src, leftPad, rightPad, topPad, bottomPad, extender); // Definition of the image bounds minX = src.getMinX(); maxX = src.getMaxX(); minY = src.getMinY(); maxY = src.getMaxY(); } else { // Creation of an iterator on the image iterSource = getRandomIterator(src, null); // Definition of the image bounds minX = src.getMinX() + leftPad; // Left padding maxX = src.getMaxX() - rightPad; // Right padding minY = src.getMinY() + topPad; // Top padding maxY = src.getMaxY() - bottomPad; // Bottom padding } final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final double[][] data = dst.getDoubleDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // Creation of an iterator for the ROI Image if(hasROI && !roiContainsTile && roiIter == null){ throw new IllegalArgumentException("Error on creating the ROI iterator"); } // source does not have IndexColorModel // ONLY VALID DATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NO ROI // for (int b = 0; b < dstBands; b++) { // Interpolation data[b][pixelOffset + bandOffsets[b]] = bicubicCalculationDouble(b, iterSource, xint, yint, offsetX, offsetY); } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { for (int b = 0; b < dstBands; b++) { // Interpolation data[b][pixelOffset + bandOffsets[b]] = bicubicCalculationDouble(b, iterSource, xint, yint, offsetX, offsetY); } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { // Array used during calculations final double[][] pixelKernel = new double[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; double[] sumArray = new double[KERNEL_LINE_DIM]; double[] emptyArray = new double[KERNEL_LINE_DIM]; double[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization double tempSum = 0; double sum = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel double sample = iterSource.getSampleDouble(xint + (i - 1), yint + (j - 1), b); pixelKernel[j][i] = sample; if (noDataRange.contains(sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpaintingDouble(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHd[offsetX] + tempData[1] * dataHd[offsetX + 1] + tempData[2] * dataHd[offsetX + 2] + tempData[3] * dataHd[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = tempSum; } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } else { tempData = bicubicInpaintingDouble(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVd[offsetY] + tempData[1] * dataVd[offsetY + 1] + tempData[2] * dataVd[offsetY + 2] + tempData[3] * dataVd[offsetY + 3]; // Interpolation weight = 0; weightVert = 0; data[b][pixelOffset + bandOffsets[b]] = (float) sum; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP // BOTH ROI AND NODATA } else { // Array used during calculations final double[][] pixelKernel = new double[KERNEL_LINE_DIM][KERNEL_LINE_DIM]; double[] sumArray = new double[KERNEL_LINE_DIM]; double[] emptyArray = new double[KERNEL_LINE_DIM]; double[] tempData; // Value used in calculations short weight = 0; byte weightVert = 0; byte temp = 0; // Row temporary sum initialization double tempSum = 0; double sum = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { final float sx = warpData[count++]; final float sy = warpData[count++]; final int xint = floor(sx); final int yint = floor(sy); final float xfrac = sx - xint; final float yfrac = sy - yint; if (xint < minX || xint >= maxX || yint < minY || yint >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // X and Y offset initialization final int offsetX = KERNEL_LINE_DIM * (int) (shift * xfrac); final int offsetY = KERNEL_LINE_DIM * (int) (shift * yfrac); // // ROI // // checks with roi // Initialization of the flag indicating that at least one kernel pixels is inside the ROI boolean inRoi = false; for (int j = 0; j < KERNEL_LINE_DIM && !inRoi; j++) { for (int i = 0; i < KERNEL_LINE_DIM && !inRoi; i++) { int x = xint + (i - 1); int y = yint + (j - 1); if (roiBounds.contains(x, y)) { inRoi |= roiIter.getSample(x, y, 0) > 0; } } } if (inRoi) { // // NODATA // // checks with nodata for (int b = 0; b < dstBands; b++) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value // and check if every kernel pixel is a No Data for (int j = 0; j < KERNEL_LINE_DIM; j++) { for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel double sample = iterSource.getSampleDouble(xint + (i - 1), yint + (j - 1), b); pixelKernel[j][i] = sample; if (noDataRange.contains(sample)) { weight &= (0xffff - (1 << KERNEL_LINE_DIM * j + i)); // weigjtArray[j][z] = 0; } else { // weigjtArray[j][z] = 1; weight |= (1 << (KERNEL_LINE_DIM * j + i)); } } // Data elaboration for each line temp = (byte) ((weight >> KERNEL_LINE_DIM * j) & 0x0F); tempData = bicubicInpaintingDouble(pixelKernel[j], temp, emptyArray); tempSum = tempData[0] * dataHd[offsetX] + tempData[1] * dataHd[offsetX + 1] + tempData[2] * dataHd[offsetX + 2] + tempData[3] * dataHd[offsetX + 3]; if (temp > 0) { weightVert |= (1 << j); // weigjtArrayVertical[j] = 1; } else { weightVert &= (0x0F - (1 << j)); // weigjtArrayVertical[j] = 0; } sumArray[j] = tempSum; } // Control if the 16 pixel are all No Data if (weight == 0) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } else { tempData = bicubicInpaintingDouble(sumArray, weightVert, emptyArray); // Vertical sum update sum = tempData[0] * dataVd[offsetY] + tempData[1] * dataVd[offsetY + 1] + tempData[2] * dataVd[offsetY + 2] + tempData[3] * dataVd[offsetY + 3]; // Interpolation weight = 0; weightVert = 0; data[b][pixelOffset + bandOffsets[b]] = sum; } } } else { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } // next desination pixel pixelOffset += pixelStride; } // COLS LOOP } // ROWS LOOP } iterSource.done(); } /** * Bicubic calculation for integer data * * @param b band * @param iterSource source image iterator * @param xint source pixel X position * @param yint source pixel Y position * @param offsetX X fractional offset * @param offsetY Y fractional offset * @param t optional color table * @return */ private long bicubicCalculationInt(int b, RandomIter iterSource, int xint, int yint, int offsetX, int offsetY, byte[] t) { // Temporary sum initialization long sum = 0; if (t == null) { // Cycle through all the 16 kernel pixel and calculation of the interpolated value for (int j = 0; j < KERNEL_LINE_DIM; j++) { // Row temporary sum initialization long temp = 0; for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int pixelValue = iterSource.getSample(xint + (i - 1), yint + (j - 1), b); // Update of the temporary sum temp += (pixelValue * dataHi[offsetX + i]); } // Vertical sum update sum += ((temp + round) >> precisionBits) * dataVi[offsetY + j]; } } else { // Cycle through all the 16 kernel pixel and calculation of the interpolated value for (int j = 0; j < KERNEL_LINE_DIM; j++) { // Row temporary sum initialization long temp = 0; for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel int pixelValue = t[iterSource.getSample(xint + (i - 1), yint + (j - 1), 0) & 0xFF] & 0xFF; // Update of the temporary sum temp += (pixelValue * dataHi[offsetX + i]); } // Vertical sum update sum += ((temp + round) >> precisionBits) * dataVi[offsetY + j]; } } // Interpolation return ((sum + round) >> precisionBits); } /** * Bicubic calculation for Float data * * @param b band * @param iterSource source image iterator * @param xint source pixel X position * @param yint source pixel Y position * @param offsetX X fractional offset * @param offsetY Y fractional offset * @return */ private double bicubicCalculationFloat(int b, RandomIter iterSource, int xint, int yint, int offsetX, int offsetY) { // Temporary sum initialization double sum = 0; // Cycle through all the 16 kernel pixel and calculation of the interpolated value for (int j = 0; j < KERNEL_LINE_DIM; j++) { // Row temporary sum initialization double temp = 0; for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel float pixelValue = iterSource.getSampleFloat(xint + (i - 1), yint + (j - 1), b); // Update of the temporary sum temp += (pixelValue * dataHf[offsetX + i]); } // Vertical sum update sum += temp * dataVf[offsetY + j]; } // Interpolation return sum; } /** * Bicubic calculation for Double data * * @param b band * @param iterSource source image iterator * @param xint source pixel X position * @param yint source pixel Y position * @param offsetX X fractional offset * @param offsetY Y fractional offset * @return */ private double bicubicCalculationDouble(int b, RandomIter iterSource, int xint, int yint, int offsetX, int offsetY) { // Temporary sum initialization double sum = 0; // Cycle through all the 16 kernel pixel and calculation of the interpolated value for (int j = 0; j < KERNEL_LINE_DIM; j++) { // Row temporary sum initialization double temp = 0; for (int i = 0; i < KERNEL_LINE_DIM; i++) { // Selection of one pixel double pixelValue = iterSource.getSampleDouble(xint + (i - 1), yint + (j - 1), b); // Update of the temporary sum temp += (pixelValue * dataHd[offsetX + i]); } // Vertical sum update sum += temp * dataVd[offsetY + j]; } // Interpolation return sum; } /** * Private method for extracting valid values from the input pixel no data values on a 4-pixel line This method is used for filling the no data * values inside the interpolation kernel with the values of the adjacent pixels * * @param array pixel array * @param weightSum value indicating how and where no data pixels are * @param emptyArray empty array to return in output * @return */ private static long[] bicubicInpainting(long[] array, short weightSum, long[] emptyArray) { // Absence of No Data, the pixels are returned. if (weightSum == 15) { return array; } long s_ = array[0]; long s0 = array[1]; long s1 = array[2]; long s2 = array[3]; emptyArray[0] = 0; emptyArray[1] = 0; emptyArray[2] = 0; emptyArray[3] = 0; // s2 s1 s0 s_ // 0/x 0/x 0/x 0/x switch (weightSum) { case 0: // 0 0 0 0 break; case 1: // 0 0 0 x emptyArray[0] = s_; emptyArray[1] = s_; emptyArray[2] = s_; emptyArray[3] = s_; break; case 2: // 0 0 x 0 emptyArray[0] = s0; emptyArray[1] = s0; emptyArray[2] = s0; emptyArray[3] = s0; break; case 3: // 0 0 x x emptyArray[0] = s_; emptyArray[1] = s0; emptyArray[2] = s0; emptyArray[3] = s0; break; case 4: // 0 x 0 0 emptyArray[0] = s1; emptyArray[1] = s1; emptyArray[2] = s1; emptyArray[3] = s1; break; case 5: // 0 x 0 x emptyArray[0] = s_; emptyArray[1] = (s_ + s1) / 2; emptyArray[2] = s1; emptyArray[3] = s1; break; case 6: // 0 x x 0 emptyArray[0] = s0; emptyArray[1] = s0; emptyArray[2] = s1; emptyArray[3] = s1; break; case 7: // 0 x x x emptyArray[0] = s_; emptyArray[1] = s0; emptyArray[2] = s1; emptyArray[3] = s1; break; case 8: // x 0 0 0 emptyArray[0] = s2; emptyArray[1] = s2; emptyArray[2] = s2; emptyArray[3] = s2; break; case 9: // x 0 0 x emptyArray[0] = s_; emptyArray[1] = (s_ + s2) / 2; emptyArray[2] = (s_ + s2) / 2; emptyArray[3] = s2; break; case 10: // x 0 x 0 emptyArray[0] = s0; emptyArray[1] = s0; emptyArray[2] = (s0 + s2) / 2; emptyArray[3] = s2; break; case 11: // x 0 x x emptyArray[0] = s_; emptyArray[1] = s0; emptyArray[2] = (s0 + s2) / 2; emptyArray[3] = s2; break; case 12: // x x 0 0 emptyArray[0] = s1; emptyArray[1] = s1; emptyArray[2] = s1; emptyArray[3] = s2; break; case 13: // x x 0 x emptyArray[0] = s_; emptyArray[1] = (s_ + s1) / 2; emptyArray[2] = s1; emptyArray[3] = s2; break; case 14: // x x x 0 emptyArray[0] = s0; emptyArray[1] = s0; emptyArray[2] = s1; emptyArray[3] = s2; break; default: throw new IllegalArgumentException("Array cannot be composed from more than 4 elements"); } return emptyArray; } /** * Private method for extracting valid values from the input pixel no data values on a 4-pixel line This method is used for filling the no data * values inside the interpolation kernel with the values of the adjacent pixels * * @param array pixel array * @param weightSum value indicating how and where no data pixels are * @param emptyArray empty array to return in output * @return */ private static double[] bicubicInpaintingDouble(double[] array, short weightSum, double[] emptyArray) { // Absence of No Data, the pixels are returned. if (weightSum == 15) { return array; } double s_ = array[0]; double s0 = array[1]; double s1 = array[2]; double s2 = array[3]; emptyArray[0] = 0; emptyArray[1] = 0; emptyArray[2] = 0; emptyArray[3] = 0; switch (weightSum) { case 0: // 0 0 0 0 break; case 1: // 0 0 0 x emptyArray[0] = s_; emptyArray[1] = s_; emptyArray[2] = s_; emptyArray[3] = s_; break; case 2: // 0 0 x 0 emptyArray[0] = s0; emptyArray[1] = s0; emptyArray[2] = s0; emptyArray[3] = s0; break; case 3: // 0 0 x x emptyArray[0] = s_; emptyArray[1] = s0; emptyArray[2] = s0; emptyArray[3] = s0; break; case 4: // 0 x 0 0 emptyArray[0] = s1; emptyArray[1] = s1; emptyArray[2] = s1; emptyArray[3] = s1; break; case 5: // 0 x 0 x emptyArray[0] = s_; emptyArray[1] = (s_ + s1) / 2; emptyArray[2] = s1; emptyArray[3] = s1; break; case 6: // 0 x x 0 emptyArray[0] = s0; emptyArray[1] = s0; emptyArray[2] = s1; emptyArray[3] = s1; break; case 7: // 0 x x x emptyArray[0] = s_; emptyArray[1] = s0; emptyArray[2] = s1; emptyArray[3] = s1; break; case 8: // x 0 0 0 emptyArray[0] = s2; emptyArray[1] = s2; emptyArray[2] = s2; emptyArray[3] = s2; break; case 9: // x 0 0 x emptyArray[0] = s_; emptyArray[1] = (s_ + s2) / 2; emptyArray[2] = (s_ + s2) / 2; emptyArray[3] = s2; break; case 10: // x 0 x 0 emptyArray[0] = s0; emptyArray[1] = s0; emptyArray[2] = (s0 + s2) / 2; emptyArray[3] = s2; break; case 11: // x 0 x x emptyArray[0] = s_; emptyArray[1] = s0; emptyArray[2] = (s0 + s2) / 2; emptyArray[3] = s2; break; case 12: // x x 0 0 emptyArray[0] = s1; emptyArray[1] = s1; emptyArray[2] = s1; emptyArray[3] = s2; break; case 13: // x x 0 x emptyArray[0] = s_; emptyArray[1] = (s_ + s1) / 2; emptyArray[2] = s1; emptyArray[3] = s2; break; case 14: // x x x 0 emptyArray[0] = s0; emptyArray[1] = s0; emptyArray[2] = s1; emptyArray[3] = s2; break; default: throw new IllegalArgumentException("Array cannot be composed from more than 4 elements"); } return emptyArray; } }