图像基本变换---Canny边缘检测算法

本文将详细介绍经典Canny边缘检测的算法实现。

  Canny边缘检测算法可以分为4步:高斯滤波器平滑处理、梯度计算、非极大值抑制、双阈值边缘检测和边缘连接。

      1,高斯滤波器平滑处理。由于图像中经常包含一些高斯噪声,因此在边缘检测前我们要先用高斯滤波器对其进行滤波,为了方便,通常是使用一些高斯模板,这里我们使用如下的高斯滤波器模板。

      2,梯度计算。使用一阶导数算子(一般用sobel模板)计算灰度图像每个像素点在水平和竖直方向上的导数Gx、Gy,得出梯度向量 (Gx,Gy),最后得到该像素点的梯度G和相位角D,Sobel模板及梯度公式如下所示。

图像基本变换---Canny边缘检测算法_第1张图片

                              Fig.1 Sobel模板算子

      3,非极大值抑制。对于2中得到的梯度,它其实是一个粗边缘信息,我们通过非极大值抑制来去掉一些非边缘信息。这里将当前像素的梯度与其在梯度方向上的邻域像素的梯度对比,如果当前像素的梯度为最大值,则保留该点梯度信息,否则将该点删除或置为0。

      4 ,双阈值边缘检测和边缘连接。由 3 得到的边缘信息中包含较多伪边缘信息,我们通过设置高低双阈值的方法去除它们。首先,设定两个阈值,一个高阈值,一个低阈值,阈值大小根据实际情况设置,一般低阈值为高阈值的 0.4 倍;然后我们判断:梯度值大于高阈值的像素点一定是边缘,该点像素值置为 255 ;梯度值小于低阈值的像素点一定不是边缘点,该点像素之置为 0 ;介于高低阈值之间的像素点为准边缘点,对于这些点,如果其像素点周围 8 邻域的梯度值都小于高阈值,则认为其不是边缘点,该点像素值置为 0 ,否则置为 255
  下面给出一份Win8C#的代码,另附一份C#代码在文章 末尾链接。
  1. ///   
  2. /// Canny edge detect process.  
  3. ///   
  4. /// The source image.  
  5. /// The high threshould value.   
  6. /// The low threshould value.   
  7. ///   
  8. public static WriteableBitmap CannyedgedetectProcess(WriteableBitmap src,int highThreshould,int lowThreshould)////图像油画效果  
  9. {  
  10.     if (src != null)  
  11.     {  
  12.         int w = src.PixelWidth;  
  13.         int h = src.PixelHeight;  
  14.         WriteableBitmap srcImage = new WriteableBitmap(w, h);  
  15.         byte[] temp = src.PixelBuffer.ToArray();  
  16.         byte[] tempMask = (byte[])temp.Clone();  
  17.         int[,] srcBytes = new int[w, h];  
  18.         for (int j = 0; j < h; j++)  
  19.         {  
  20.             for (int i = 0; i < w; i++)  
  21.             {  
  22.                 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);  
  23.             }  
  24.         }  
  25.         float gradientMax = 0;  
  26.         float[,] gradient = new float[w, h];  
  27.         byte[,] degree = new byte[w, h];  
  28.         GaussFilter(ref srcBytes, w, h);  
  29.         GetGradientDegree(srcBytes, ref gradient, ref degree, ref gradientMax, w, h);  
  30.         NonMaxMini(gradient, ref srcBytes, gradientMax, w, h, degree);  
  31.         TwoThreshouldJudge(highThreshould, lowThreshould, ref srcBytes, w, h);  
  32.         for (int j = 0; j < h; j++)  
  33.         {  
  34.             for (int i = 0; i < w; i++)  
  35.             {  
  36.                 temp[i * 4 + j * w * 4] = temp[i * 4 + 1 + j * w * 4] = temp[i * 4 + 2 + j * w * 4] = (byte)srcBytes[i, j];  
  37.             }  
  38.         }  
  39.         Stream sTemp = srcImage.PixelBuffer.AsStream();  
  40.         sTemp.Seek(0, SeekOrigin.Begin);  
  41.         sTemp.Write(temp, 0, w * 4 * h);  
  42.         return srcImage;  
  43.     }  
  44.     else  
  45.     {  
  46.         return null;  
  47.     }  
  48. }  
  49. //高斯滤波  
  50. private static void GaussFilter(ref int[,] src, int x, int y)  
  51. {  
  52.     for (int j = 1; j < y - 1; j++)  
  53.     {  
  54.         for (int i = 1; i < x - 1; i++)  
  55.         {  
  56.             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;  
  57.         }  
  58.     }  
  59. }  
  60. //梯度相位角获取  
  61. private static void GetGradientDegree(int[,] srcBytes, ref float[,] gradient, ref byte[,] degree, ref float GradientMax, int x, int y)  
  62. {  
  63.     gradient = new float[x, y];  
  64.     degree = new byte[x, y];  
  65.     int gx, gy;  
  66.     int temp;  
  67.     double div;  
  68.     for (int j = 1; j < y - 1; j++)  
  69.     {  
  70.         for (int i = 1; i < x - 1; i++)  
  71.         {  
  72.             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];  
  73.             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];  
  74.             gradient[i, j] = (float)Math.Sqrt((double)(gx * gx + gy * gy));  
  75.             if (GradientMax < gradient[i, j])  
  76.             {  
  77.                 GradientMax = gradient[i, j];  
  78.             }  
  79.             if (gx == 0)  
  80.             {  
  81.                 temp = (gy == 0) ? 0 : 90;  
  82.             }  
  83.             else  
  84.             {  
  85.                 div = (double)gy / (double)gx;  
  86.                 if (div < 0)  
  87.                 {  
  88.                     temp = (int)(180 - Math.Atan(-div) * 180 / Math.PI);  
  89.                 }  
  90.                 else  
  91.                 {  
  92.                     temp = (int)(Math.Atan(div) * 180 / Math.PI);  
  93.                 }  
  94.                 if (temp < 22.5)  
  95.                 {  
  96.                     temp = 0;  
  97.                 }  
  98.                 else if (temp < 67.5)  
  99.                 {  
  100.                     temp = 45;  
  101.                 }  
  102.                 else if (temp < 112.5)  
  103.                 {  
  104.                     temp = 90;  
  105.                 }  
  106.                 else if (temp < 157.5)  
  107.                 {  
  108.                     temp = 135;  
  109.                 }  
  110.                 else  
  111.                     temp = 0;  
  112.             }  
  113.             degree[i, j] = (byte)temp;  
  114.         }  
  115.     }  
  116. }  
  117. //非极大值抑制  
  118. private static void NonMaxMini(float[,] gradient, ref int[,] srcBytes, float GradientMax, int x, int y, byte[,] degree)  
  119. {  
  120.     float leftPixel = 0, rightPixel = 0;  
  121.     for (int j = 1; j < y - 1; j++)  
  122.     {  
  123.         for (int i = 1; i < x - 1; i++)  
  124.         {  
  125.             switch (degree[i, j])  
  126.             {  
  127.                 case 0:  
  128.                     leftPixel = gradient[i - 1, j];  
  129.                     rightPixel = gradient[i + 1, j];  
  130.                     break;  
  131.                 case 45:  
  132.                     leftPixel = gradient[i - 1, j + 1];  
  133.                     rightPixel = gradient[i + 1, j - 1];  
  134.                     break;  
  135.                 case 90:  
  136.                     leftPixel = gradient[i, j + 1];  
  137.                     rightPixel = gradient[i, j - 1];  
  138.                     break;  
  139.                 case 135:  
  140.                     leftPixel = gradient[i + 1, j + 1];  
  141.                     rightPixel = gradient[i - 1, j - 1];  
  142.                     break;  
  143.                 default:  
  144.                     break;  
  145.             }  
  146.             if ((gradient[i, j] < leftPixel) || (gradient[i, j] < rightPixel))  
  147.             {  
  148.                 srcBytes[i, j] = 0;  
  149.             }  
  150.             else  
  151.             {  
  152.                 srcBytes[i, j] = (int)(255 * gradient[i, j] / GradientMax);  
  153.             }  
  154.         }  
  155.     }  
  156. }  
  157. //双阈值边缘判断  
  158. private static void TwoThreshouldJudge(int highThreshold, int lowThreshould, ref int[,] srcBytes, int x, int y)  
  159. {  
  160.     for (int j = 1; j < y - 1; j++)  
  161.     {  
  162.         for (int i = 1; i < x - 1; i++)  
  163.         {  
  164.             if (srcBytes[i, j] > highThreshold)  
  165.             {  
  166.                 srcBytes[i, j] = 255;  
  167.             }  
  168.             else if (srcBytes[i, j] < lowThreshould)  
  169.             {  
  170.                 srcBytes[i, j] = 0;  
  171.             }  
  172.             else  
  173.             {  
  174.                 if (srcBytes[i - 1, j - 1] < highThreshold && srcBytes[i, j - 1] < highThreshold && srcBytes[i + 1, j - 1] < highThreshold && srcBytes[i - 1, j] < highThreshold  
  175.                     && srcBytes[i + 1, j] < highThreshold && srcBytes[i - 1, j + 1] < highThreshold && srcBytes[i, j + 1] < highThreshold && srcBytes[i + 1, j + 1] < highThreshold)  
  176.                 {  
  177.                     srcBytes[i, j] = 0;  
  178.                 }  
  179.                 else  
  180.                     srcBytes[i, j] = 255;  
  181.             }  
  182.         }  
  183.     }  
  184. }  
图像基本变换---Canny边缘检测算法_第2张图片
  
demo download: http://www.zealfilter.com/forum.php?mod=viewthread&tid=28&extra=page%3D1

你可能感兴趣的:(图像基本变换)