package fr.unistra.pelican.algorithms.edge;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.AlgorithmException;
import fr.unistra.pelican.BooleanImage;
import fr.unistra.pelican.DoubleImage;
import fr.unistra.pelican.Image;
/**
* This class represents the Sobel edge detector scheme applied in 2-D or 3-D as norm,
* dimensional and orientation gradient.
*
* @author Aptoula, Lefèvre
*/
public class Sobel extends Algorithm {
/**
* Input image
*/
public Image input;
/**
* Type of operation (NORM = 0,GRADX = 1,GRADY = 2,ORIEN = 3)
*/
public int operation;
/**
* Gradient norm
*/
public static final int NORM = 0;
/**
* X gradient
*/
public static final int GRADX = 1;
/**
* Y gradient
*/
public static final int GRADY = 2;
/**
* Orientation gradient
*/
public static final int ORIEN = 3;
/**
* Z gradient
*/
public static final int GRADZ = 4;
/**
* T gradient
*/
public static final int GRADT = 5;
/**
* Dimensions used to compute the Sobel operator
*/
public int dimensions = XY;
/**
* Processing 2-D images
*/
public static final int XY = 0;
/**
* Processing 3-D images
*/
public static final int XYZ = 1;
/**
* Processing 2-D+t image sequences
*/
public static final int XYT = 2;
/**
* Output image
*/
public Image output;
private int bdim, tdim, zdim, ydim, xdim;
/**
* Constructor
*
*/
public Sobel() {
super.inputs = "input,operation";
super.options = "dimensions";
super.outputs = "output";
}
/*
* (non-Javadoc)
*
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() throws AlgorithmException {
bdim = input.getBDim();
tdim = input.getTDim();
zdim = input.getZDim();
ydim = input.getYDim();
xdim = input.getXDim();
int size = input.size();
Image gradx, grady, gradz, gradt;
if (input instanceof BooleanImage)
throw new AlgorithmException("BooleanImages are not supported");
switch (dimensions) {
case XYZ:
switch (operation) {
case GRADZ:
output = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, -3, -1 }, { -3, -6, -3 }, { -1, -3, -1 } },
{ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } },
{ { 1, 3, 1 }, { 3, 6, 3 }, { 1, 3, 1 } } });
break;
case GRADY:
output = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, -3, -1 }, { 0, 0, 0 }, { 1, 3, 1 } },
{ { -3, -6, -3 }, { 0, 0, 0 }, { 3, 6, 3 } },
{ { -1, -3, -1 }, { 0, 0, 0 }, { 1, 3, 1 } } });
break;
case GRADX:
output = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, 0, 1 }, { -3, 0, 3 }, { -1, 0, 1 } },
{ { -3, 0, 3 }, { -6, 0, 6 }, { 3, 0, 3 } },
{ { -1, 0, 1 }, { -3, 0, 3 }, { -1, 0, 1 } } });
break;
case ORIEN:
gradx = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, 0, 1 }, { -3, 0, 3 }, { -1, 0, 1 } },
{ { -3, 0, 3 }, { -6, 0, 6 }, { 3, 0, 3 } },
{ { -1, 0, 1 }, { -3, 0, 3 }, { -1, 0, 1 } } });
grady = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, -3, -1 }, { 0, 0, 0 }, { 1, 3, 1 } },
{ { -3, -6, -3 }, { 0, 0, 0 }, { 3, 6, 3 } },
{ { -1, -3, -1 }, { 0, 0, 0 }, { 1, 3, 1 } } });
gradz = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, -3, -1 }, { -3, -6, -3 }, { -1, -3, -1 } },
{ { 0, 0, 3 }, { 0, 0, 0 }, { 0, 0, 0 } },
{ { 1, 3, 1 }, { 3, 6, 3 }, { 1, 3, 1 } } });
System.err
.println("cas non traité pour l'instant : orientation XYZ Sobel");
break;
default:
case NORM:
gradx = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, 0, 1 }, { -3, 0, 3 }, { -1, 0, 1 } },
{ { -3, 0, 3 }, { -6, 0, 6 }, { 3, 0, 3 } },
{ { -1, 0, 1 }, { -3, 0, 3 }, { -1, 0, 1 } } });
grady = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, -3, -1 }, { 0, 0, 0 }, { 1, 3, 1 } },
{ { -3, -6, -3 }, { 0, 0, 0 }, { 3, 6, 3 } },
{ { -1, -3, -1 }, { 0, 0, 0 }, { 1, 3, 1 } } });
gradz = convolve3DXYZ(1, 1, 1, 0, 0, new int[][][] {
{ { -1, -3, -1 }, { -3, -6, -3 }, { -1, -3, -1 } },
{ { 0, 0, 3 }, { 0, 0, 0 }, { 0, 0, 0 } },
{ { 1, 3, 1 }, { 3, 6, 3 }, { 1, 3, 1 } } });
output = new DoubleImage(xdim, ydim, zdim, tdim, bdim);
output.copyAttributes(input);
for (int p = 0; p < size; p++)
output.setPixelDouble(p, Math.sqrt(gradx.getPixelDouble(p)
* gradx.getPixelDouble(p) + grady.getPixelDouble(p)
* grady.getPixelDouble(p) + gradz.getPixelDouble(p)
* gradz.getPixelDouble(p)));
}
break;
case XYT:
break;
case XY:
default:
switch (operation) {
case GRADX:
output = convolve2D(1, 1, 0, 0, 0, new int[][] { { -1, 0, 1 },
{ -2, 0, 2 }, { -1, 0, 1 } });
break;
case GRADY:
output = convolve2D(1, 1, 0, 0, 0, new int[][] {
{ -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } });
break;
case ORIEN:
gradx = convolve2D(1, 1, 0, 0, 0, new int[][] { { -1, 0, 1 },
{ -2, 0, 2 }, { -1, 0, 1 } });
grady = convolve2D(1, 1, 0, 0, 0, new int[][] { { -1, -2, -1 },
{ 0, 0, 0 }, { 1, 2, 1 } });
output = new DoubleImage(xdim, ydim, zdim, tdim, bdim);
output.copyAttributes(input);
for (int p = 0; p < size; p++)
output.setPixelDouble(p, Math.atan(grady.getPixelDouble(p)
/ gradx.getPixelDouble(p))
- 3 * Math.PI / 4);
break;
default:
case NORM:
gradx = convolve2D(1, 1, 0, 0, 0, new int[][] { { -1, 0, 1 },
{ -2, 0, 2 }, { -1, 0, 1 } });
grady = convolve2D(1, 1, 0, 0, 0, new int[][] { { -1, -2, -1 },
{ 0, 0, 0 }, { 1, 2, 1 } });
output = new DoubleImage(xdim, ydim, zdim, tdim, bdim);
output.copyAttributes(input);
for (int p = 0; p < size; p++)
output.setPixelDouble(p, Math.sqrt(gradx.getPixelDouble(p)
* gradx.getPixelDouble(p) + grady.getPixelDouble(p)
* grady.getPixelDouble(p)));
}
}
}
Image convolve2D(int dx, int dy, int dz, int dt, int db, int tab[][]) {
Image result = new DoubleImage(xdim, ydim, zdim, tdim, bdim);
result.copyAttributes(input);
for (int b = db; b < bdim - db; b++)
for (int t = dt; t < tdim - dt; t++)
for (int z = dz; z < zdim - dz; z++)
for (int y = dy; y < ydim - dy; y++)
for (int x = dx; x < xdim - dx; x++) {
double sum = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
sum += tab[j][i]
* input.getPixelXYZTBDouble(x + i
- 1, y + j - 1, z, t, b);
result.setPixelXYZTBDouble(x, y, z, t, b, sum);
}
return result;
}
Image convolve3DXYZ(int dx, int dy, int dz, int dt, int db, int tab[][][]) {
Image result = new DoubleImage(xdim, ydim, zdim, tdim, bdim);
result.copyAttributes(input);
for (int b = db; b < bdim - db; b++)
for (int t = dt; t < tdim - dt; t++)
for (int z = dz; z < zdim - dz; z++)
for (int y = dy; y < ydim - dy; y++)
for (int x = dx; x < xdim - dx; x++) {
double sum = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++)
sum += tab[k][j][i]
* input.getPixelXYZTBDouble(x
+ i - 1, y + j - 1, z
+ k - 1, t, b);
result.setPixelXYZTBDouble(x, y, z, t, b, sum);
}
return result;
}
Image convolve3DXYT(int dx, int dy, int dz, int dt, int db, int tab[][][]) {
Image result = new DoubleImage(xdim, ydim, zdim, tdim, bdim);
result.copyAttributes(input);
for (int b = db; b < bdim - db; b++)
for (int t = dt; t < tdim - dt; t++)
for (int z = dz; z < zdim - dz; z++)
for (int y = dy; y < ydim - dy; y++)
for (int x = dx; x < xdim - dx; x++) {
double sum = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++)
sum += tab[k][j][i]
* input.getPixelXYZTBDouble(x
+ i - 1, y + j - 1, z,
t + k - 1, b);
result.setPixelXYZTBDouble(x, y, z, t, b, sum);
}
return result;
}
public static DoubleImage exec(Image image, int operation, int dimensions) {
return (DoubleImage) new Sobel().process(image, operation, dimensions);
}
/**
* Apply the Sobel edge detector scheme
*
* @param image
* the input image
* @param operation
* type of operation (NORM,GRADX,GRADY,ORIEN)
* @return the output image
*/
public static DoubleImage exec(Image image, int operation) {
return (DoubleImage) new Sobel().process(image, operation);
}
/**
* Apply the Sobel edge detector scheme with the NORM operation
*
* @param the
* input image
* @return the output image
*/
public static DoubleImage exec(Image image) {
return (DoubleImage) new Sobel().process(image, Sobel.NORM);
}
}