背景简述
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 函数
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
#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带阈值
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