背景简述
Canny提出一种新的边缘检测方法[1][2],它对受白噪声影响的阶跃型边缘是最优的。Canny检测子的最优性与三个标准有关:第一、检测标准:不失去重要的边缘,不应有虚假的边缘;第二、定位标准:实际边缘与检测到的边缘位置之间的偏差最小;第三、单位应标准:将多个响应降低为单个边缘响应。这一点被第一个标准部分地覆盖了。因为当有两个响应对应于单个边缘时,其中之一应该被是虚假的。这第三个标准解决受噪声影响的边缘问题,起亦制非平滑边缘检测算子的作用。
基本理论
首先,Canny算子是针对1D信号和前两个最优标准表达的。用微积分方法可以得到完整的解。如果我们加上第三个标准,需要通达数值优化的办法得到最优解。其最优滤波器可有有效地为标准差的高斯平滑滤波器的一阶微分,其误差小于20%。然后,将边缘检测算子映射到2D情况。阶跃边缘由位置、方向和可能的幅度(强度)来确定。
由于噪声引起的对单个边缘的虚假响应通常造成的所谓“纹状”问题。一般而言,该问题在边缘检测中是非常普遍。边缘检测算子的输出通常要做阈值化处理,以确定哪些边缘是突出的。纹状是指边缘轮廓断开的情形,是由算子输出超出或阈值的波动引起。我可以通过来Thresholding with hysteresis消除。在一般情况下,我选择具有最小尺度的算子,因为它定位最准确。
Canny提出了特征综合方法。首先标记出所有由最小尺度算子得到的突出边缘。而整个Canny边缘检测器算法分成如下四步:
噪声去除。因为这个检测器用到了微分算子,所以对于局部的不连续是敏感的,某区域的噪声点很容易造成边缘的模糊。在我做的这个应用里,因为要检测的是文本的边缘,而文本的背景是比较规则的变形后的正方形方格,所以如果用wiki里建议的高斯滤波器,会造成整个图像都变成一种颜色,即全黑或者全白。因此如果换一种观点,把这些变形后的方格也看成图的一部分,因为字体的纹理和方格的纹理不同,所以可以看作是两种区域组合成的图像。由此我改用一般的镜子,增强图像边缘。
计算图像的边缘梯度。这个是常规运算,用了Sobel算子,分别计算图像的x和y方向的梯度值,最后计算出图像各点的梯度值以及梯度角。计算得到梯度角需要进行近似,近似四个值{-45(或135), 0, 45,90}。
非最大梯度值点抑制第2步计算后得到两组值,第一组是各点的梯度值,第二组是各点梯度角的近似值。这一个非最大梯度值点抑制是比较不好理解的一步。遍历各点,做如下操作。(1)如果该点(x, y)的梯度角是0,如果其梯度值比北(x - 1, y)和南(x + 1, y)的梯度值大,则认为(x,y)点是一个边缘点,否则抑制其值,该其梯度值为设定的背景值(0或255);(2)如果该点(x, y)的梯度角是90,如果其梯度值比西(x, y - 1)和东(x, y +1)的梯度值大,则认为(x, y)点是一个边缘点,否则抑制其值,该其梯度值为设定的背景值(0或255);(3)如果该点(x,y)的梯度角是135(或-45),如果其梯度值比东北(x - 1, y + 1)和西南(x + 1, y -1)的梯度值大,则认为(x, y)点是一个边缘点,否则抑制其值,该其梯度值为设定的背景值(0或255);(4)如果该点(x,y)的梯度角是45,如果其梯度值比西北(x - 1, y - 1)和东南(x + 1, y + 1)的梯度值大,则认为(x,y)点是一个边缘点,否则抑制其值,该其梯度值为设定的背景值(0或255)。
产生边缘.在第3步里直接用边缘值和背景值对两种图像区域进行了划分。这么做对于图像不同区域像素值区别较大的场合比较方便,计算也快,但是对于图像不同区域像素。
参考代码
Opencv版Canny函数
[cpp] view plaincopyprint?
- void canny (float s, IMAGE im, IMAGE mag, IMAGE ori){
- int width;
- float **smx,**smy;
- float **dx,**dy;
- int i,j,n;
- float gau[MAX_MASK_SIZE], dgau[MAX_MASK_SIZE], z;
-
-
- for(i=0; i<MAX_MASK_SIZE; i++){
- gau[i] = meanGauss ((float)i, s);
- if (gau[i] < 0.005){
- width = i;
- break;
- }
- dgau[i] = dGauss ((float)i, s);
- }
-
- n = width+width + 1;
- WIDTH = width/2;
- printf ("Smoothing with a Gaussian (width = %d) ...\n", n);
-
- smx = f2d (im->info->nr, im->info->nc);
- smy = f2d (im->info->nr, im->info->nc);
-
-
- seperable_convolution (im, gau, width, smx, smy);
-
-
- printf ("Convolution with the derivative of a Gaussian...\n");
- dx = f2d (im->info->nr, im->info->nc);
- dxy_seperable_convolution (smx, im->info->nr, im->info->nc,dgau, width, dx, 1);
- free(smx[0]); free(smx);
-
- dy = f2d (im->info->nr, im->info->nc);
- dxy_seperable_convolution (smy, im->info->nr, im->info->nc,
- dgau, width, dy, 0);
- free(smy[0]); free(smy);
-
-
- for (i=0; i<im->info->nr; i++)
- for (j=0; j<im->info->nc; j++)
- {
- z = norm (dx[i][j], dy[i][j]);
- mag->data[i][j] = (unsigned char)(z*MAG_SCALE);
- }
-
-
- nonmax_suppress (dx, dy, (int)im->info->nr, (int)im->info->nc, mag, ori);
-
- free(dx[0]); free(dx);
- free(dy[0]); free(dy);
- }
Opencv-Python版Canny
[cpp] view plaincopyprint?
- #coding=utf-8
- import cv2
- import numpy as np
-
- img = cv2.imread("test.jpg", 0)
- img = cv2.GaussianBlur(img,(3,3),0)
- canny = cv2.Canny(img, 50, 150)
-
- cv2.imshow('Canny', canny)
- cv2.imwrite("Canny.jpg",canny)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
Opencv-Python版Canny带阈值
[cpp] view plaincopyprint?
- import cv2
- import numpy as np
-
- def CannyThreshold(lowThreshold):
- detected_edges = cv2.GaussianBlur(gray,(3,3),0)
- detected_edges = cv2.Canny(detected_edges,lowThreshold,
- lowThreshold*ratio,apertureSize = kernel_size)
- dst = cv2.bitwise_and(img,img,mask = detected_edges)
- cv2.imshow('canny demo',dst)
- cv2.imwrite("CannyThreshold.jpg",dst)
-
- lowThreshold = 0
- max_lowThreshold = 100
- ratio = 3
- kernel_size = 3
-
- img = cv2.imread('test.jpg')
- gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
-
- cv2.namedWindow('canny demo')
-
- cv2.createTrackbar('Min threshold','Canny demo',
- lowThreshold, max_lowThreshold, CannyThreshold)
-
- CannyThreshold(0) # initialization
- if cv2.waitKey(0) == 27:
- cv2.destroyAllWindows()
测试输出结果
经Canny算子处理图像如下图所示:
经Canny算子并带阈值为100的处理图像如下图所示:
参考文献
[1] Canny J. F. "Finding edges and lines in images" Technical Report AI-TR-720,MIT,Artifical Inteligence Labortay,Cambridg,MA,1983.
[2] Canny J. F. "a Computational Approach to Edge Detection", IEEE Trancsctions on Pattern Analysis and Machine Intelligence, 8(6):679-698,1996.
原文地址:http://blog.csdn.net/songzitea/article/details/8827781