[算法说明]
Canny边缘检测算法可以分为4步:高斯滤波器平滑处理、梯度计算、非极大值抑制、双阈值边缘检
测和边缘连接。
1,高斯滤波器平滑处理。由于图像中经常包含一些高斯噪声,因此在边缘检测前我们要先用高斯
滤波器对其进行滤波,为了方便,通常是使用一些高斯模板,这里我们使用如下的高斯滤波器模板。
-
/// <summary> -
/// Canny edge detect process. -
/// </summary> -
/// <param name="src">The source image.</param> -
/// <param name="highThreshould">The high threshould value. </param> -
/// <param name="lowThreshould">The low threshould value. </param> -
/// <returns></returns> -
public static WriteableBitmap CannyedgedetectProcess(WriteableBitmap src,int highThreshould,int lowThreshould)////图像油画效果 -
{ -
if (src != null) -
{ -
int w = src.PixelWidth; -
int h = src.PixelHeight; -
WriteableBitmap srcImage = new WriteableBitmap(w, h); -
byte[] temp = src.PixelBuffer.ToArray(); -
byte[] tempMask = (byte[])temp.Clone(); -
int[,] srcBytes = new int[w, h]; -
for (int j = 0; j < h; j++) -
{ -
for (int i = 0; i < w; i++) -
{ -
srcBytes[i, j] = (int)(tempMask[i * 4 + j * w * 4] * 0.114 + tempMask[i * 4 + 1 + j * w * 4] * 0.587 + tempMask[i * 4 + 2 + j * w * 4] * 0.299); -
} -
} -
float gradientMax = 0; -
float[,] gradient = new float[w, h]; -
byte[,] degree = new byte[w, h]; -
GaussFilter(ref srcBytes, w, h); -
GetGradientDegree(srcBytes, ref gradient, ref degree, ref gradientMax, w, h); -
NonMaxMini(gradient, ref srcBytes, gradientMax, w, h, degree); -
TwoThreshouldJudge(highThreshould, lowThreshould, ref srcBytes, w, h); -
for (int j = 0; j < h; j++) -
{ -
for (int i = 0; i < w; i++) -
{ -
temp[i * 4 + j * w * 4] = temp[i * 4 + 1 + j * w * 4] = temp[i * 4 + 2 + j * w * 4] = (byte)srcBytes[i, j]; -
} -
} -
Stream sTemp = srcImage.PixelBuffer.AsStream(); -
sTemp.Seek(0, SeekOrigin.Begin); -
sTemp.Write(temp, 0, w * 4 * h); -
return srcImage; -
} -
else -
{ -
return null; -
} -
} -
//高斯滤波 -
private static void GaussFilter(ref int[,] src, int x, int y) -
{ -
for (int j = 1; j < y - 1; j++) -
{ -
for (int i = 1; i < x - 1; i++) -
{ -
src[i, j] = (4 * src[i, j] + src[i - 1, j - 1] + src[i + 1, j - 1] + src[i - 1, j + 1] + src[i + 1, j + 1] + 2 * src[i, j - 1] + 2 * src[i - 1, j] + 2 * src[i, j + 1] + 2 * src[i + 1, j]) / 16; -
} -
} -
} -
//梯度相位角获取 -
private static void GetGradientDegree(int[,] srcBytes, ref float[,] gradient, ref byte[,] degree, ref float GradientMax, int x, int y) -
{ -
gradient = new float[x, y]; -
degree = new byte[x, y]; -
int gx, gy; -
int temp; -
double div; -
for (int j = 1; j < y - 1; j++) -
{ -
for (int i = 1; i < x - 1; i++) -
{ -
gx = srcBytes[i + 1, j - 1] + 2 * srcBytes[i + 1, j] + srcBytes[i + 1, j + 1] - srcBytes[i - 1, j - 1] - 2 * srcBytes[i - 1, j] - srcBytes[i - 1, j + 1]; -
gy = srcBytes[i - 1, j - 1] + 2 * srcBytes[i, j - 1] + srcBytes[i + 1, j - 1] - srcBytes[i - 1, j + 1] - 2 * srcBytes[i, j + 1] - srcBytes[i + 1, j + 1]; -
gradient[i, j] = (float)Math.Sqrt((double)(gx * gx + gy * gy)); -
if (GradientMax < gradient[i, j]) -
{ -
GradientMax = gradient[i, j]; -
} -
if (gx == 0) -
{ -
temp = (gy == 0) ? 0 : 90; -
} -
else -
{ -
div = (double)gy / (double)gx; -
if (div < 0) -
{ -
temp = (int)(180 - Math.Atan(-div) * 180 / Math.PI); -
} -
else -
{ -
temp = (int)(Math.Atan(div) * 180 / Math.PI); -
} -
if (temp < 22.5) -
{ -
temp = 0; -
} -
else if (temp < 67.5) -
{ -
temp = 45; -
} -
else if (temp < 112.5) -
{ -
temp = 90; -
} -
else if (temp < 157.5) -
{ -
temp = 135; -
} -
else -
temp = 0; -
} -
degree[i, j] = (byte)temp; -
} -
} -
} -
//非极大值抑制 -
private static void NonMaxMini(float[,] gradient, ref int[,] srcBytes, float GradientMax, int x, int y, byte[,] degree) -
{ -
float leftPixel = 0, rightPixel = 0; -
for (int j = 1; j < y - 1; j++) -
{ -
for (int i = 1; i < x - 1; i++) -
{ -
switch (degree[i, j]) -
{ -
case 0: -
leftPixel = gradient[i - 1, j]; -
rightPixel = gradient[i + 1, j]; -
break; -
case 45: -
leftPixel = gradient[i - 1, j + 1]; -
rightPixel = gradient[i + 1, j - 1]; -
break; -
case 90: -
leftPixel = gradient[i, j + 1]; -
rightPixel = gradient[i, j - 1]; -
break; -
case 135: -
leftPixel = gradient[i + 1, j + 1]; -
rightPixel = gradient[i - 1, j - 1]; -
break; -
default: -
break; -
} -
if ((gradient[i, j] < leftPixel) || (gradient[i, j] < rightPixel)) -
{ -
srcBytes[i, j] = 0; -
} -
else -
{ -
srcBytes[i, j] = (int)(255 * gradient[i, j] / GradientMax); -
} -
} -
} -
} -
//双阈值边缘判断 -
private static void TwoThreshouldJudge(int highThreshold, int lowThreshould, ref int[,] srcBytes, int x, int y) -
{ -
for (int j = 1; j < y - 1; j++) -
{ -
for (int i = 1; i < x - 1; i++) -
{ -
if (srcBytes[i, j] > highThreshold) -
{ -
srcBytes[i, j] = 255; -
} -
else if (srcBytes[i, j] < lowThreshould) -
{ -
srcBytes[i, j] = 0; -
} -
else -
{ -
if (srcBytes[i - 1, j - 1] < highThreshold && srcBytes[i, j - 1] < highThreshold && srcBytes[i + 1, j - 1] < highThreshold && srcBytes[i - 1, j] < highThreshold -
&& srcBytes[i + 1, j] < highThreshold && srcBytes[i - 1, j + 1] < highThreshold && srcBytes[i, j + 1] < highThreshold && srcBytes[i + 1, j + 1] < highThreshold) -
{ -
srcBytes[i, j] = 0; -
} -
else -
srcBytes[i, j] = 255; -
} -
} -
} -
}