I am writing Canny's Algorithm, and I seem to have an issue with hysteresis. The Thresholds Appears to process, however my hysteresis does not seem to function at all. As well as method remove weak for some odd reason. Please help!
Low @ 10 High @ 75 After Hysteresis, with problem A, edges were not strengthen with method performHysteresis; B weak non-edges are not removed with method removeWeak.
Source code for the method as follows:
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
class CannyMethod {
private static final float[] sobelX = { 1.0f, 0.0f, -1.0f,
2.0f, 0.0f, -2.0f,
1.0f, 0.0f, -1.0f};
private static final float[] sobelY = { 1.0f, 2.0f, 1.0f,
0.0f, 0.0f, 0.0f,
-1.0f,-2.0f,-1.0f};
private static int low, high;
public CannyMethod() {}
private ConvolveOp getSobel(boolean xy) {
Kernel kernel;
if (xy) kernel = new Kernel(3, 3, sobelX);
else kernel = new Kernel(3, 3, sobelY);
return new ConvolveOp(kernel, ConvolveOp.EDGE_ZERO_FILL, null);
}
public BufferedImage getCannyFilter(BufferedImage img) {
return getCannyFilter(img, low, high);
}
public BufferedImage getCannyFilter(BufferedImage img, int l, int h) {
int width = img.getWidth();
int height = img.getHeight();
low = l;
high = h;
int size = width * height;
int[] x = new int[size];
int[] y = new int[size];
int[] pixelM = new int[size];
double[] pixelD = new double[size];
int[] pixelNew = new int[size];
BufferedImage sobelXImg = getSobel(true).filter(img, null);
BufferedImage sobelYImg = getSobel(false).filter(img, null);
// returns arrays for x and y direction after convultion with Sobel Operator
sobelXImg.getRaster().getPixels(0, 0, width, height, x);
sobelYImg.getRaster().getPixels(0, 0, width, height, y);
// Calculates Gradient and Magnitude
for(int i = 0; i < size; i++) {
pixelM[i] = (int) Math.hypot(x[i], y[i]);
pixelD[i] = Math.atan2((double) y[i], (double) x[i]);
}
//Operations for Canny Algorithm takes magnitude and gradient and input into new array fo WritableRaster
normalizeDirection(pixelD);
nonMaximaSupression(pixelM, pixelD, pixelNew, width, height);
performHysteresis(pixelNew, width);
removeWeak(pixelNew);
BufferedImage result =
new BufferedImage(width, height,
BufferedImage.TYPE_BYTE_GRAY);
result.getRaster().setPixels(0, 0, width, height, pixelNew);
return result;
}
private void normalizeDirection(double[] dArray) {
//Round degrees
double pi = Math.PI;
for(double i : dArray) {
if (i < pi/8d && i >= -pi/8d) i = 0;
else if (i < 3d*pi/8d && i >= pi/8d) i = 45;
else if (i < -3d*pi/8d || i >= 3d*pi/8d) i = 90;
else if (i < -pi/8d && i >= -3d*pi/8d) i = 135;
}
}
private void nonMaximaSupression(int[] pixelM, double[] pixelD,
int[] pixelNew, int width, int height) {
//non-Maxima Supression
//Since array is not in 2-D, positions are calulated with width - functions properly
for(int i = 0; i < pixelNew.length; i++) {
if (i % width == 0 || (i + 1) % width == 0 ||
i <= width || i >= width * height - 1) pixelNew[i] = 0;
else {
switch ((int) pixelD[i]) {
case 0: if (pixelM[i] > pixelM[i+1]
&& pixelM[i] > pixelM[i-1])
setPixel(i, pixelM[i], pixelNew);
else pixelNew[i] = 0;
break;
case 45: if (pixelM[i] > pixelM[i+(width-1)]
&& pixelM[i] > pixelM[i-(width-1)])
setPixel(i, pixelM[i], pixelNew);
else pixelNew[i] = 0;
break;
case 90: if (pixelM[i] > pixelM[i+width]
&& pixelM[i] > pixelM[i-width])
setPixel(i, pixelM[i], pixelNew);
else pixelNew[i] = 0;
break;
case 135:if (pixelM[i] > pixelM[i+width]
&& pixelM[i] > pixelM[i-width])
setPixel(i, pixelM[i], pixelNew);
else pixelNew[i] = 0;
break;
default: pixelNew[i] = 0;
}
}
}
}
private void performHysteresis(int[] array, int width) {
//performs hysteresis
int[] temp;
for(int i = width; i < array.length - width; i++) {
if (i % width == 0 || (i + 1) % width == 0) {}
else {
if (array[i] == 255) {
//found strong one, track surrounding weak ones
//temp is the positions of surrounding pixels
temp = new int[]
{i - (width + 1), i - width, i - (width - 1),
i - 1, i + 1,
i + (width - 1), i + width, i + (width + 1)};
trackWeak(array, temp, width);
}
}
}
}
private void trackWeak(int[] array, int[] pos, int width) {
int[] temp;
for (int i : pos) {
if (array[i] > 0 && array[i] < 255) {
array[i] = 255;
//set weak one to strong one
if (i % width == 0 || (i + 1) % width == 0) {}
else {
//temp is the positions of surrounding pixels
temp = new int[]
{i - (width + 1), i - width, i - (width - 1),
i - 1, i + 1,
i + (width - 1), i + width, i + (width + 1)};
trackWeak(array, temp, width);
}
}
}
}
private void removeWeak(int[] array) {
//remove remaining weak ones from lew Threshold
for(int i : array) {
if (i < 255) {i = 0;}
}
}
private void setPixel(int pos, int value, int[] pixelNew) {
if (value > high) pixelNew[pos] = 255;
else if (value > low) pixelNew[pos] = 128;
else pixelNew[pos] = 0;
}
public void setThreshold(int l, int h) {
low = l;
high = h;
}
}