我正在编写 Canny 算法,我似乎遇到了滞后问题。阈值似乎正在处理,但是我的滞后似乎根本不起作用。以及由于某些奇怪的原因而删除弱的方法。请帮忙!
Low @ 10 High @ 75 滞后后,对于问题 A,边缘没有通过方法 performHysteresis 加强;使用方法 removeWeak 不会删除 B 个弱非边缘。
该方法的源代码如下:
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;
}
}