package gdsc.smlm.filters;
/*-----------------------------------------------------------------------------
* GDSC SMLM Software
*
* Copyright (C) 2013 Alex Herbert
* Genome Damage and Stability Centre
* University of Sussex, UK
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*---------------------------------------------------------------------------*/
import org.apache.commons.math3.util.FastMath;
/**
* Computes the block sum for each point within the array.
*/
public class SumFilter implements Cloneable
{
private float[] floatDataBuffer = null;
private float[] floatRowBuffer = null;
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void rollingBlockSumInternal(float[] data, final int maxx, final int maxy, final int n)
{
// Note: Speed tests show that this method is only marginally faster than rollingBlockSumNxNInternal.
// Sometimes it is slower. The intricacies of the java optimiser escape me.
if (n == 1)
rollingBlockSum3x3Internal(data, maxx, maxy);
else
rollingBlockSumNxNInternal(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void rollingBlockSumNxNInternal(float[] data, final int maxx, final int maxy, final int n)
{
final int blockSize = 2 * n + 1;
if (maxx < blockSize || maxy < blockSize)
return;
float[] newData = floatBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
// Initialise the rolling sum
float sum = 0;
int endIndex = y * maxx;
int x = 0;
while (x < blockSize)
{
sum += data[endIndex];
endIndex++;
x++;
}
// Rolling sum over the X-direction
int startIndex = y * maxx;
int centreIndex = startIndex + n;
newData[centreIndex] = sum;
while (x < maxx)
{
centreIndex++;
sum += data[endIndex] - data[startIndex];
newData[centreIndex] = sum;
x++;
startIndex++;
endIndex++;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = n; x < maxx - n; x++)
{
// Initialise the rolling sum
float sum = 0;
int endIndex = x;
int y = 0;
while (y < blockSize)
{
sum += newData[endIndex];
endIndex += maxx;
y++;
}
// Rolling sum over the Y-direction
int startIndex = x;
int centreIndex = startIndex + n * maxx;
data[centreIndex] = sum;
while (y < maxy)
{
centreIndex += maxx;
sum += newData[endIndex] - newData[startIndex];
data[centreIndex] = sum;
y++;
startIndex += maxx;
endIndex += maxx;
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void rollingBlockSum3x3Internal(float[] data, final int maxx, final int maxy)
{
if (maxx < 3 || maxy < 3)
return;
float[] newData = floatBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
// Initialise the rolling sum
int startIndex = y * maxx;
int centreIndex = startIndex + 1;
int endIndex = centreIndex + 1;
float sum = data[startIndex] + data[centreIndex] + data[endIndex];
// Rolling sum over the X-direction
newData[centreIndex++] = sum;
for (int x = 0; x < maxx - 3; x++)
{
sum += data[++endIndex] - data[startIndex++];
newData[centreIndex++] = sum;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = 1; x < maxx - 1; x++)
{
// Initialise the rolling sum
int startIndex = x;
int centreIndex = startIndex + maxx;
int endIndex = centreIndex + maxx;
float sum = newData[startIndex] + newData[centreIndex] + newData[endIndex];
// Rolling sum over the Y-direction
data[centreIndex] = sum;
for (int y = 0; y < maxy - 3; y++)
{
centreIndex += maxx;
endIndex += maxx;
sum += newData[endIndex] - newData[startIndex];
data[centreIndex] = sum;
startIndex += maxx;
}
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
@Deprecated
public void rollingBlockSumNxNInternalTransposed(float[] data, final int maxx, final int maxy, final int n)
{
int blockSize = 2 * n + 1;
if (maxx < blockSize || maxy < blockSize)
return;
float[] newData = floatBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
// Initialise the rolling sum
float sum = 0;
int endIndex = y * maxx;
int x = 0;
while (x < blockSize)
{
sum += data[endIndex];
endIndex++;
x++;
}
// Rolling sum over the X-direction
int startIndex = y * maxx;
int newCentreIndex = y + n * maxy;
newData[newCentreIndex] = sum;
while (x < maxx)
{
newCentreIndex += maxy;
sum += data[endIndex] - data[startIndex];
newData[newCentreIndex] = sum;
x++;
startIndex++;
endIndex++;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = n; x < maxx - n; x++)
{
// Initialise the rolling sum
float sum = 0;
int endIndex = x * maxy;
int y = 0;
while (y < blockSize)
{
sum += newData[endIndex];
endIndex++;
y++;
}
// Rolling sum over the Y-direction
int startIndex = x * maxy;
int centreIndex = x + n * maxx;
data[centreIndex] = sum;
while (y < maxy)
{
centreIndex += maxx;
sum += newData[endIndex] - newData[startIndex];
data[centreIndex] = sum;
y++;
startIndex++;
endIndex++;
}
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void stripedBlockSumInternal(float[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
stripedBlockSum3x3Internal(data, maxx, maxy);
else
stripedBlockSumNxNInternal(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void stripedBlockSumNxNInternal(float[] data, final int maxx, final int maxy, final int n)
{
int blockSize = 2 * n + 1;
if (maxx < blockSize || maxy < blockSize)
return;
float[] newData = floatBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
int index = y * maxx;
for (int x = 0; x <= maxx - blockSize; x++, index++)
{
float sum = 0;
for (int x2 = 0; x2 < blockSize; x2++)
{
sum += data[index + x2];
}
newData[(x + n) * maxy + y] = sum;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = n; x < maxx - n; x++)
{
int index = x * maxy;
for (int y = 0; y <= maxy - blockSize; y++, index++)
{
float sum = 0;
for (int y2 = 0; y2 < blockSize; y2++)
{
sum += newData[index + y2];
}
data[x + (y + n) * maxx] = sum;
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void stripedBlockSum3x3Internal(float[] data, final int maxx, final int maxy)
{
if (maxx < 3 || maxy < 3)
return;
float[] newData = floatBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
int index = y * maxx;
int index2 = maxy + y;
for (int x = 0; x <= maxx - 3; x++, index++)
{
float sum = data[index] + data[index + 1] + data[index + 2];
newData[index2] = sum;
index2 += maxy;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = 1; x < maxx - 1; x++)
{
int index = x * maxy;
int index2 = x + maxx;
for (int y = 0; y <= maxy - 3; y++, index++)
{
float sum = newData[index] + newData[index + 1] + newData[index + 2];
data[index2] = sum;
index2 += maxx;
}
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void blockSumInternal(float[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
blockSum3x3Internal(data, maxx, maxy);
else
blockSumNxNInternal(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void blockSumNxNInternal(float[] data, final int maxx, final int maxy, final int n)
{
final int blockSize = 2 * n + 1;
if (maxx < blockSize || maxy < blockSize)
return;
float[] newData = floatBuffer(data.length);
int[] offset = new int[blockSize * blockSize - 1];
for (int y = -n, d = 0; y <= n; y++)
for (int x = -n; x <= n; x++)
if (x != 0 || y != 0)
{
offset[d] = maxx * y + x;
d++;
}
for (int y = n; y < maxy - n; y++)
{
int index = y * maxx + n;
for (int x = n; x < maxx - n; x++, index++)
{
float sum = data[index];
// Sweep neighbourhood -
// No check for boundaries as this should be an internal sweep.
for (int offset_d : offset)
{
sum += data[index + offset_d];
}
newData[index] = sum;
}
}
// Copy back
for (int y = n; y < maxy - n; y++)
{
int index = y * maxx + n;
for (int x = n; x < maxx - n; x++, index++)
{
data[index] = newData[index];
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void blockSum3x3Internal(float[] data, final int maxx, final int maxy)
{
float[] newData = floatBuffer(data.length);
for (int y = 1; y < maxy - 1; y++)
{
int index0 = (y - 1) * maxx + 1;
int index1 = y * maxx + 1;
int index2 = (y + 1) * maxx + 1;
for (int x = 1; x < maxx - 1; x++)
{
float sum = data[index0 - 1] + data[index0] + data[index0 + 1] + data[index1 - 1] + data[index1] +
data[index1 + 1] + data[index2 - 1] + data[index2] + data[index2 + 1];
newData[index1] = sum;
index0++;
index1++;
index2++;
}
}
// Copy back
for (int y = 1; y < maxy - 1; y++)
{
int index = y * maxx + 1;
for (int x = 1; x < maxx - 1; x++, index++)
{
data[index] = newData[index];
}
}
}
private float[] floatBuffer(int size)
{
if (floatDataBuffer == null || floatDataBuffer.length < size)
{
floatDataBuffer = new float[size];
}
return floatDataBuffer;
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void rollingBlockSum(float[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
rollingBlockSum3x3(data, maxx, maxy);
else
rollingBlockSumNxN(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void rollingBlockSumNxN(float[] data, final int maxx, final int maxy, final int n)
{
float[] newData = floatBuffer(data.length);
// X-direction
int width = maxx;
int height = maxy;
float[] inData = data;
float[] outData = newData;
float[] row = floatRowBuffer(width + 2 * n);
for (int y = 0; y < height; y++)
{
extractRow(inData, y, width, n, row);
// Initialise rolling sum
float sum = (n + 1) * row[0];
int endIndex = n + 1;
for (int i = 0; i < n; i++)
{
sum += row[endIndex++];
}
int centreIndex = y;
outData[centreIndex] = sum;
// Rolling sum over the X-direction
for (int x = 0; x < width - 1; x++)
{
sum += row[endIndex++] - row[x];
centreIndex += height;
outData[centreIndex] = sum;
}
}
// Y-direction.
width = maxy;
height = maxx;
inData = newData;
outData = data;
row = floatRowBuffer(width + 2 * n);
for (int y = 0; y < height; y++)
{
extractRow(inData, y, width, n, row);
// Initialise rolling sum
float sum = (n + 1) * row[0];
int endIndex = n + 1;
for (int i = 0; i < n; i++)
{
sum += row[endIndex++];
}
int centreIndex = y;
outData[centreIndex] = sum;
// Rolling sum over the X-direction
for (int x = 0; x < width - 1; x++)
{
sum += row[endIndex++] - row[x];
centreIndex += height;
outData[centreIndex] = sum;
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void rollingBlockSum3x3(float[] data, final int maxx, final int maxy)
{
float[] newData = floatBuffer(data.length);
// X-direction
int width = maxx;
int height = maxy;
float[] inData = data;
float[] outData = newData;
float[] row = floatRowBuffer(width + 2);
for (int y = 0; y < height; y++)
{
extractRow1(inData, y, width, row);
// Initialise rolling sum
float sum = 2 * row[0] + row[2];
int endIndex = 3;
int centreIndex = y;
outData[centreIndex] = sum;
// Rolling sum over the X-direction
for (int x = 0; x < width - 1; x++)
{
sum += row[endIndex++] - row[x];
centreIndex += height;
outData[centreIndex] = sum;
}
}
// Y-direction.
width = maxy;
height = maxx;
inData = newData;
outData = data;
row = floatRowBuffer(width + 2);
for (int y = 0; y < height; y++)
{
extractRow1(inData, y, width, row);
// Initialise rolling sum
float sum = 2 * row[0] + row[2];
int endIndex = 3;
int centreIndex = y;
outData[centreIndex] = sum;
// Rolling sum over the X-direction
for (int x = 0; x < width - 1; x++)
{
sum += row[endIndex++] - row[x];
centreIndex += height;
outData[centreIndex] = sum;
}
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void stripedBlockSum(float[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
stripedBlockSum3x3(data, maxx, maxy);
else
stripedBlockSumNxN(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void stripedBlockSumNxN(float[] data, final int maxx, final int maxy, final int n)
{
int blockSize = 2 * n + 1;
float[] newData = floatBuffer(data.length);
// X-direction
int width = maxx;
int height = maxy;
float[] inData = data;
float[] outData = newData;
float[] row = floatRowBuffer(width + 2 * n);
for (int y = 0; y < height; y++)
{
extractRow(inData, y, width, n, row);
int centreIndex = y;
for (int x = 0; x < width; x++)
{
// Sum strips
float sum = 0;
for (int j = 0; j < blockSize; j++)
{
sum += row[x + j];
}
// Store result in transpose
outData[centreIndex] = sum;
centreIndex += height;
}
}
// Y-direction.
width = maxy;
height = maxx;
inData = newData;
outData = data;
row = floatRowBuffer(width + 2 * n);
for (int y = 0; y < height; y++)
{
// Extract row (pad ends)
extractRow(inData, y, width, n, row);
int centreIndex = y;
for (int x = 0; x < width; x++)
{
// Sum strips
float sum = 0;
for (int j = 0; j < blockSize; j++)
{
sum += row[x + j];
}
// Store result in transpose
outData[centreIndex] = sum;
centreIndex += height;
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void stripedBlockSum3x3(float[] data, final int maxx, final int maxy)
{
float[] newData = floatBuffer(data.length);
// X-direction
int width = maxx;
int height = maxy;
float[] inData = data;
float[] outData = newData;
float[] row = floatRowBuffer(width + 2);
for (int y = 0; y < height; y++)
{
extractRow1(inData, y, width, row);
int centreIndex = y;
for (int x = 0; x < width; x++)
{
// Sum strips
float sum = row[x] + row[x + 1] + row[x + 2];
// Store result in transpose
outData[centreIndex] = sum;
centreIndex += height;
}
}
// Y-direction.
width = maxy;
height = maxx;
inData = newData;
outData = data;
row = floatRowBuffer(width + 2);
for (int y = 0; y < height; y++)
{
// Extract row (pad ends)
extractRow1(inData, y, width, row);
int centreIndex = y;
for (int x = 0; x < width; x++)
{
// Sum strips
float sum = row[x] + row[x + 1] + row[x + 2];
// Store result in transpose
outData[centreIndex] = sum;
centreIndex += height;
}
}
}
private float[] floatRowBuffer(int size)
{
if (floatRowBuffer == null || floatRowBuffer.length < size)
{
floatRowBuffer = new float[size];
}
return floatRowBuffer;
}
private void extractRow(float[] inData, int y, int width, final int n, float[] row)
{
int index = y * width;
// Pad ends
for (int i = 0; i < n; i++)
{
row[i] = inData[index];
row[i + n + width] = inData[index + width - 1];
}
// Fill in data
for (int x = 0, i = n; x < width; x++)
{
row[i++] = inData[index++];
}
}
private void extractRow1(float[] inData, int y, int width, float[] row)
{
int index = y * width;
// Pad ends
row[0] = inData[index];
row[1 + width] = inData[index + width - 1];
// Fill in data
for (int x = 0, i = 1; x < width; x++)
{
row[i++] = inData[index++];
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void blockSum(float[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
blockSum3x3(data, maxx, maxy);
else
blockSumNxN(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void blockSumNxN(float[] data, final int maxx, final int maxy, final int n)
{
float[] newData = floatBuffer(data.length);
// Boundary control
int xwidth = FastMath.min(n, maxx - 1);
int ywidth = FastMath.min(n, maxy - 1);
int xlimit = maxx - xwidth;
int ylimit = maxy - ywidth;
int[] offset = new int[(2 * xwidth + 1) * (2 * ywidth + 1) - 1];
int[] xoffset = new int[offset.length];
int[] yoffset = new int[offset.length];
int d = 0;
for (int y = -ywidth; y <= ywidth; y++)
for (int x = -xwidth; x <= xwidth; x++)
if (x != 0 || y != 0)
{
offset[d] = maxx * y + x;
xoffset[d] = x;
yoffset[d] = y;
d++;
}
int index = 0;
for (int y = 0; y < maxy; y++)
{
for (int x = 0; x < maxx; x++, index++)
{
float sum = data[index];
// Flag to indicate this pixels has a complete (2n+1) neighbourhood
boolean isInnerXY = (y >= ywidth && y < ylimit) && (x >= xwidth && x < xlimit);
// Sweep neighbourhood
if (isInnerXY)
{
for (d = offset.length; d-- > 0;)
{
sum += data[index + offset[d]];
}
}
else
{
for (d = offset.length; d-- > 0;)
{
// Get the pixel with boundary checking
int yy = y + yoffset[d];
int xx = x + xoffset[d];
if (xx <= 0)
xx = 0;
else if (xx >= maxx)
xx = maxx - 1;
if (yy <= 0)
yy = 0;
else if (yy >= maxy)
yy = maxy - 1;
sum += data[xx + yy * maxx];
}
}
newData[index] = sum;
}
}
// Copy back
for (index = data.length; index-- > 0;)
{
data[index] = newData[index];
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void blockSum3x3(float[] data, final int maxx, final int maxy)
{
final int n = 1;
float[] newData = floatBuffer(data.length);
// Boundary control
int xwidth = FastMath.min(n, maxx - 1);
int ywidth = FastMath.min(n, maxy - 1);
int xlimit = maxx - xwidth;
int ylimit = maxy - ywidth;
int[] offset = new int[(2 * xwidth + 1) * (2 * ywidth + 1) - 1];
int[] xoffset = new int[offset.length];
int[] yoffset = new int[offset.length];
int d = 0;
for (int y = -ywidth; y <= ywidth; y++)
for (int x = -xwidth; x <= xwidth; x++)
if (x != 0 || y != 0)
{
offset[d] = maxx * y + x;
xoffset[d] = x;
yoffset[d] = y;
d++;
}
for (int y = 0; y < maxy; y++)
{
int index0 = (y - 1) * maxx;
int index1 = y * maxx;
int index2 = (y + 1) * maxx;
for (int x = 0; x < maxx; x++)
{
// Flag to indicate this pixels has a complete (2n+1) neighbourhood
boolean isInnerXY = (y >= ywidth && y < ylimit) && (x >= xwidth && x < xlimit);
// Sweep neighbourhood
if (isInnerXY)
{
float sum = data[index0 - 1] + data[index0] + data[index0 + 1] + data[index1 - 1] + data[index1] +
data[index1 + 1] + data[index2 - 1] + data[index2] + data[index2 + 1];
newData[index1] = sum;
}
else
{
float sum = data[index1];
for (d = offset.length; d-- > 0;)
{
// Get the pixel with boundary checking
int yy = y + yoffset[d];
int xx = x + xoffset[d];
if (xx <= 0)
xx = 0;
else if (xx >= maxx)
xx = maxx - 1;
if (yy <= 0)
yy = 0;
else if (yy >= maxy)
yy = maxy - 1;
sum += data[xx + yy * maxx];
}
newData[index1] = sum;
}
index0++;
index1++;
index2++;
}
}
// Copy back
for (int index = data.length; index-- > 0;)
{
data[index] = newData[index];
}
}
// ----------------------------------------------------
// XXX
// NOTE:
// The following code is copied directly from above.
// All 'float' have been replaced with 'int'.
// ----------------------------------------------------
private int[] intDataBuffer = null;
private int[] intRowBuffer = null;
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void rollingBlockSumInternal(int[] data, final int maxx, final int maxy, final int n)
{
// Note: Speed tests show that this method is only marginally faster than rollingBlockSumNxNInternal.
// Sometimes it is slower. The intricacies of the java optimiser escape me.
if (n == 1)
rollingBlockSum3x3Internal(data, maxx, maxy);
else
rollingBlockSumNxNInternal(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void rollingBlockSumNxNInternal(int[] data, final int maxx, final int maxy, final int n)
{
final int blockSize = 2 * n + 1;
if (maxx < blockSize || maxy < blockSize)
return;
int[] newData = intBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
// Initialise the rolling sum
int sum = 0;
int endIndex = y * maxx;
int x = 0;
while (x < blockSize)
{
sum += data[endIndex];
endIndex++;
x++;
}
// Rolling sum over the X-direction
int startIndex = y * maxx;
int centreIndex = startIndex + n;
newData[centreIndex] = sum;
while (x < maxx)
{
centreIndex++;
sum += data[endIndex] - data[startIndex];
newData[centreIndex] = sum;
x++;
startIndex++;
endIndex++;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = n; x < maxx - n; x++)
{
// Initialise the rolling sum
int sum = 0;
int endIndex = x;
int y = 0;
while (y < blockSize)
{
sum += newData[endIndex];
endIndex += maxx;
y++;
}
// Rolling sum over the Y-direction
int startIndex = x;
int centreIndex = startIndex + n * maxx;
data[centreIndex] = sum;
while (y < maxy)
{
centreIndex += maxx;
sum += newData[endIndex] - newData[startIndex];
data[centreIndex] = sum;
y++;
startIndex += maxx;
endIndex += maxx;
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void rollingBlockSum3x3Internal(int[] data, final int maxx, final int maxy)
{
if (maxx < 3 || maxy < 3)
return;
int[] newData = intBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
// Initialise the rolling sum
int startIndex = y * maxx;
int centreIndex = startIndex + 1;
int endIndex = centreIndex + 1;
int sum = data[startIndex] + data[centreIndex] + data[endIndex];
// Rolling sum over the X-direction
newData[centreIndex++] = sum;
for (int x = 0; x < maxx - 3; x++)
{
sum += data[++endIndex] - data[startIndex++];
newData[centreIndex++] = sum;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = 1; x < maxx - 1; x++)
{
// Initialise the rolling sum
int startIndex = x;
int centreIndex = startIndex + maxx;
int endIndex = centreIndex + maxx;
int sum = newData[startIndex] + newData[centreIndex] + newData[endIndex];
// Rolling sum over the Y-direction
data[centreIndex] = sum;
for (int y = 0; y < maxy - 3; y++)
{
centreIndex += maxx;
endIndex += maxx;
sum += newData[endIndex] - newData[startIndex];
data[centreIndex] = sum;
startIndex += maxx;
}
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
@Deprecated
public void rollingBlockSumNxNInternalTransposed(int[] data, final int maxx, final int maxy, final int n)
{
int blockSize = 2 * n + 1;
if (maxx < blockSize || maxy < blockSize)
return;
int[] newData = intBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
// Initialise the rolling sum
int sum = 0;
int endIndex = y * maxx;
int x = 0;
while (x < blockSize)
{
sum += data[endIndex];
endIndex++;
x++;
}
// Rolling sum over the X-direction
int startIndex = y * maxx;
int newCentreIndex = y + n * maxy;
newData[newCentreIndex] = sum;
while (x < maxx)
{
newCentreIndex += maxy;
sum += data[endIndex] - data[startIndex];
newData[newCentreIndex] = sum;
x++;
startIndex++;
endIndex++;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = n; x < maxx - n; x++)
{
// Initialise the rolling sum
int sum = 0;
int endIndex = x * maxy;
int y = 0;
while (y < blockSize)
{
sum += newData[endIndex];
endIndex++;
y++;
}
// Rolling sum over the Y-direction
int startIndex = x * maxy;
int centreIndex = x + n * maxx;
data[centreIndex] = sum;
while (y < maxy)
{
centreIndex += maxx;
sum += newData[endIndex] - newData[startIndex];
data[centreIndex] = sum;
y++;
startIndex++;
endIndex++;
}
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void stripedBlockSumInternal(int[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
stripedBlockSum3x3Internal(data, maxx, maxy);
else
stripedBlockSumNxNInternal(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void stripedBlockSumNxNInternal(int[] data, final int maxx, final int maxy, final int n)
{
int blockSize = 2 * n + 1;
if (maxx < blockSize || maxy < blockSize)
return;
int[] newData = intBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
int index = y * maxx;
for (int x = 0; x <= maxx - blockSize; x++, index++)
{
int sum = 0;
for (int x2 = 0; x2 < blockSize; x2++)
{
sum += data[index + x2];
}
newData[(x + n) * maxy + y] = sum;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = n; x < maxx - n; x++)
{
int index = x * maxy;
for (int y = 0; y <= maxy - blockSize; y++, index++)
{
int sum = 0;
for (int y2 = 0; y2 < blockSize; y2++)
{
sum += newData[index + y2];
}
data[x + (y + n) * maxx] = sum;
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void stripedBlockSum3x3Internal(int[] data, final int maxx, final int maxy)
{
if (maxx < 3 || maxy < 3)
return;
int[] newData = intBuffer(data.length);
// X-direction
for (int y = 0; y < maxy; y++)
{
int index = y * maxx;
int index2 = maxy + y;
for (int x = 0; x <= maxx - 3; x++, index++)
{
int sum = data[index] + data[index + 1] + data[index + 2];
newData[index2] = sum;
index2 += maxy;
}
}
// Y-direction.
// Only sweep over the interior
for (int x = 1; x < maxx - 1; x++)
{
int index = x * maxy;
int index2 = x + maxx;
for (int y = 0; y <= maxy - 3; y++, index++)
{
int sum = newData[index] + newData[index + 1] + newData[index + 2];
data[index2] = sum;
index2 += maxx;
}
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void blockSumInternal(int[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
blockSum3x3Internal(data, maxx, maxy);
else
blockSumNxNInternal(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void blockSumNxNInternal(int[] data, final int maxx, final int maxy, final int n)
{
final int blockSize = 2 * n + 1;
if (maxx < blockSize || maxy < blockSize)
return;
int[] newData = intBuffer(data.length);
int[] offset = new int[blockSize * blockSize - 1];
for (int y = -n, d = 0; y <= n; y++)
for (int x = -n; x <= n; x++)
if (x != 0 || y != 0)
{
offset[d] = maxx * y + x;
d++;
}
for (int y = n; y < maxy - n; y++)
{
int index = y * maxx + n;
for (int x = n; x < maxx - n; x++, index++)
{
int sum = data[index];
// Sweep neighbourhood -
// No check for boundaries as this should be an internal sweep.
for (int offset_d : offset)
{
sum += data[index + offset_d];
}
newData[index] = sum;
}
}
// Copy back
for (int y = n; y < maxy - n; y++)
{
int index = y * maxx + n;
for (int x = n; x < maxx - n; x++, index++)
{
data[index] = newData[index];
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* Only pixels with a full block are processed. Pixels within border regions
* are unchanged.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void blockSum3x3Internal(int[] data, final int maxx, final int maxy)
{
int[] newData = intBuffer(data.length);
for (int y = 1; y < maxy - 1; y++)
{
int index0 = (y - 1) * maxx + 1;
int index1 = y * maxx + 1;
int index2 = (y + 1) * maxx + 1;
for (int x = 1; x < maxx - 1; x++)
{
int sum = data[index0 - 1] + data[index0] + data[index0 + 1] + data[index1 - 1] + data[index1] +
data[index1 + 1] + data[index2 - 1] + data[index2] + data[index2 + 1];
newData[index1] = sum;
index0++;
index1++;
index2++;
}
}
// Copy back
for (int y = 1; y < maxy - 1; y++)
{
int index = y * maxx + 1;
for (int x = 1; x < maxx - 1; x++, index++)
{
data[index] = newData[index];
}
}
}
private int[] intBuffer(int size)
{
if (intDataBuffer == null || intDataBuffer.length < size)
{
intDataBuffer = new int[size];
}
return intDataBuffer;
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void rollingBlockSum(int[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
rollingBlockSum3x3(data, maxx, maxy);
else
rollingBlockSumNxN(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void rollingBlockSumNxN(int[] data, final int maxx, final int maxy, final int n)
{
int[] newData = intBuffer(data.length);
// X-direction
int width = maxx;
int height = maxy;
int[] inData = data;
int[] outData = newData;
int[] row = intRowBuffer(width + 2 * n);
for (int y = 0; y < height; y++)
{
extractRow(inData, y, width, n, row);
// Initialise rolling sum
int sum = (n + 1) * row[0];
int endIndex = n + 1;
for (int i = 0; i < n; i++)
{
sum += row[endIndex++];
}
int centreIndex = y;
outData[centreIndex] = sum;
// Rolling sum over the X-direction
for (int x = 0; x < width - 1; x++)
{
sum += row[endIndex++] - row[x];
centreIndex += height;
outData[centreIndex] = sum;
}
}
// Y-direction.
width = maxy;
height = maxx;
inData = newData;
outData = data;
row = intRowBuffer(width + 2 * n);
for (int y = 0; y < height; y++)
{
extractRow(inData, y, width, n, row);
// Initialise rolling sum
int sum = (n + 1) * row[0];
int endIndex = n + 1;
for (int i = 0; i < n; i++)
{
sum += row[endIndex++];
}
int centreIndex = y;
outData[centreIndex] = sum;
// Rolling sum over the X-direction
for (int x = 0; x < width - 1; x++)
{
sum += row[endIndex++] - row[x];
centreIndex += height;
outData[centreIndex] = sum;
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void rollingBlockSum3x3(int[] data, final int maxx, final int maxy)
{
int[] newData = intBuffer(data.length);
// X-direction
int width = maxx;
int height = maxy;
int[] inData = data;
int[] outData = newData;
int[] row = intRowBuffer(width + 2);
for (int y = 0; y < height; y++)
{
extractRow1(inData, y, width, row);
// Initialise rolling sum
int sum = 2 * row[0] + row[2];
int endIndex = 3;
int centreIndex = y;
outData[centreIndex] = sum;
// Rolling sum over the X-direction
for (int x = 0; x < width - 1; x++)
{
sum += row[endIndex++] - row[x];
centreIndex += height;
outData[centreIndex] = sum;
}
}
// Y-direction.
width = maxy;
height = maxx;
inData = newData;
outData = data;
row = intRowBuffer(width + 2);
for (int y = 0; y < height; y++)
{
extractRow1(inData, y, width, row);
// Initialise rolling sum
int sum = 2 * row[0] + row[2];
int endIndex = 3;
int centreIndex = y;
outData[centreIndex] = sum;
// Rolling sum over the X-direction
for (int x = 0; x < width - 1; x++)
{
sum += row[endIndex++] - row[x];
centreIndex += height;
outData[centreIndex] = sum;
}
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void stripedBlockSum(int[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
stripedBlockSum3x3(data, maxx, maxy);
else
stripedBlockSumNxN(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void stripedBlockSumNxN(int[] data, final int maxx, final int maxy, final int n)
{
int blockSize = 2 * n + 1;
int[] newData = intBuffer(data.length);
// X-direction
int width = maxx;
int height = maxy;
int[] inData = data;
int[] outData = newData;
int[] row = intRowBuffer(width + 2 * n);
for (int y = 0; y < height; y++)
{
extractRow(inData, y, width, n, row);
int centreIndex = y;
for (int x = 0; x < width; x++)
{
// Sum strips
int sum = 0;
for (int j = 0; j < blockSize; j++)
{
sum += row[x + j];
}
// Store result in transpose
outData[centreIndex] = sum;
centreIndex += height;
}
}
// Y-direction.
width = maxy;
height = maxx;
inData = newData;
outData = data;
row = intRowBuffer(width + 2 * n);
for (int y = 0; y < height; y++)
{
// Extract row (pad ends)
extractRow(inData, y, width, n, row);
int centreIndex = y;
for (int x = 0; x < width; x++)
{
// Sum strips
int sum = 0;
for (int j = 0; j < blockSize; j++)
{
sum += row[x + j];
}
// Store result in transpose
outData[centreIndex] = sum;
centreIndex += height;
}
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void stripedBlockSum3x3(int[] data, final int maxx, final int maxy)
{
int[] newData = intBuffer(data.length);
// X-direction
int width = maxx;
int height = maxy;
int[] inData = data;
int[] outData = newData;
int[] row = intRowBuffer(width + 2);
for (int y = 0; y < height; y++)
{
extractRow1(inData, y, width, row);
int centreIndex = y;
for (int x = 0; x < width; x++)
{
// Sum strips
int sum = row[x] + row[x + 1] + row[x + 2];
// Store result in transpose
outData[centreIndex] = sum;
centreIndex += height;
}
}
// Y-direction.
width = maxy;
height = maxx;
inData = newData;
outData = data;
row = intRowBuffer(width + 2);
for (int y = 0; y < height; y++)
{
// Extract row (pad ends)
extractRow1(inData, y, width, row);
int centreIndex = y;
for (int x = 0; x < width; x++)
{
// Sum strips
int sum = row[x] + row[x + 1] + row[x + 2];
// Store result in transpose
outData[centreIndex] = sum;
centreIndex += height;
}
}
}
private int[] intRowBuffer(int size)
{
if (intRowBuffer == null || intRowBuffer.length < size)
{
intRowBuffer = new int[size];
}
return intRowBuffer;
}
private void extractRow(int[] inData, int y, int width, final int n, int[] row)
{
int index = y * width;
// Pad ends
for (int i = 0; i < n; i++)
{
row[i] = inData[index];
row[i + n + width] = inData[index + width - 1];
}
// Fill in data
for (int x = 0, i = n; x < width; x++)
{
row[i++] = inData[index++];
}
}
private void extractRow1(int[] inData, int y, int width, int[] row)
{
int index = y * width;
// Pad ends
row[0] = inData[index];
row[1 + width] = inData[index + width - 1];
// Fill in data
for (int x = 0, i = 1; x < width; x++)
{
row[i++] = inData[index++];
}
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void blockSum(int[] data, final int maxx, final int maxy, final int n)
{
if (n == 1)
blockSum3x3(data, maxx, maxy);
else
blockSumNxN(data, maxx, maxy, n);
}
/**
* Compute the block sum within a 2n+1 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
* @param n
* The block size
*/
public void blockSumNxN(int[] data, final int maxx, final int maxy, final int n)
{
int[] newData = intBuffer(data.length);
// Boundary control
int xwidth = FastMath.min(n, maxx - 1);
int ywidth = FastMath.min(n, maxy - 1);
int xlimit = maxx - xwidth;
int ylimit = maxy - ywidth;
int[] offset = new int[(2 * xwidth + 1) * (2 * ywidth + 1) - 1];
int[] xoffset = new int[offset.length];
int[] yoffset = new int[offset.length];
int d = 0;
for (int y = -ywidth; y <= ywidth; y++)
for (int x = -xwidth; x <= xwidth; x++)
if (x != 0 || y != 0)
{
offset[d] = maxx * y + x;
xoffset[d] = x;
yoffset[d] = y;
d++;
}
int index = 0;
for (int y = 0; y < maxy; y++)
{
for (int x = 0; x < maxx; x++, index++)
{
int sum = data[index];
// Flag to indicate this pixels has a complete (2n+1) neighbourhood
boolean isInnerXY = (y >= ywidth && y < ylimit) && (x >= xwidth && x < xlimit);
// Sweep neighbourhood
if (isInnerXY)
{
for (d = offset.length; d-- > 0;)
{
sum += data[index + offset[d]];
}
}
else
{
for (d = offset.length; d-- > 0;)
{
// Get the pixel with boundary checking
int yy = y + yoffset[d];
int xx = x + xoffset[d];
if (xx <= 0)
xx = 0;
else if (xx >= maxx)
xx = maxx - 1;
if (yy <= 0)
yy = 0;
else if (yy >= maxy)
yy = maxy - 1;
sum += data[xx + yy * maxx];
}
}
newData[index] = sum;
}
}
// Copy back
for (index = data.length; index-- > 0;)
{
data[index] = newData[index];
}
}
/**
* Compute the block sum within a 3x3 size block around each point.
* <p>
* Note: the input data is destructively modified
*
* @param data
* The input/output data (packed in YX order)
* @param maxx
* The width of the data
* @param maxy
* The height of the data
*/
public void blockSum3x3(int[] data, final int maxx, final int maxy)
{
final int n = 1;
int[] newData = intBuffer(data.length);
// Boundary control
int xwidth = FastMath.min(n, maxx - 1);
int ywidth = FastMath.min(n, maxy - 1);
int xlimit = maxx - xwidth;
int ylimit = maxy - ywidth;
int[] offset = new int[(2 * xwidth + 1) * (2 * ywidth + 1) - 1];
int[] xoffset = new int[offset.length];
int[] yoffset = new int[offset.length];
int d = 0;
for (int y = -ywidth; y <= ywidth; y++)
for (int x = -xwidth; x <= xwidth; x++)
if (x != 0 || y != 0)
{
offset[d] = maxx * y + x;
xoffset[d] = x;
yoffset[d] = y;
d++;
}
for (int y = 0; y < maxy; y++)
{
int index0 = (y - 1) * maxx;
int index1 = y * maxx;
int index2 = (y + 1) * maxx;
for (int x = 0; x < maxx; x++)
{
// Flag to indicate this pixels has a complete (2n+1) neighbourhood
boolean isInnerXY = (y >= ywidth && y < ylimit) && (x >= xwidth && x < xlimit);
// Sweep neighbourhood
if (isInnerXY)
{
int sum = data[index0 - 1] + data[index0] + data[index0 + 1] + data[index1 - 1] + data[index1] +
data[index1 + 1] + data[index2 - 1] + data[index2] + data[index2 + 1];
newData[index1] = sum;
}
else
{
int sum = data[index1];
for (d = offset.length; d-- > 0;)
{
// Get the pixel with boundary checking
int yy = y + yoffset[d];
int xx = x + xoffset[d];
if (xx <= 0)
xx = 0;
else if (xx >= maxx)
xx = maxx - 1;
if (yy <= 0)
yy = 0;
else if (yy >= maxy)
yy = maxy - 1;
sum += data[xx + yy * maxx];
}
newData[index1] = sum;
}
index0++;
index1++;
index2++;
}
}
// Copy back
for (int index = data.length; index-- > 0;)
{
data[index] = newData[index];
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
public SumFilter clone()
{
try
{
SumFilter o = (SumFilter) super.clone();
o.floatDataBuffer = null;
o.floatRowBuffer = null;
return o;
}
catch (CloneNotSupportedException e)
{
// Ignore
}
return null;
}
}