opencv中canny算法理解

来源:互联网 发布:一楼土木人 知乎 编辑:程序博客网 时间:2024/05/03 04:00

opencv canny的应用详解参见:

http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.html


canny算法的基本步骤:


1. 获取x,y的梯度

2. 非最大值抑制

3. 边缘跟踪

第一个步骤很好理解,获取x方向、y方向的梯度。opencv中应用sobel算子来获取dx,dy。

第二个步骤有点绕口费解,说白了就是在梯度方向上求最大值,来判断此点是不是边缘点。梯度方向上是灰度变换最大的方向,只要在这条线上,比较梯度图像的中心点的邻域即可。如果梯度图像中,中心点大于两个邻域的值,则可能为边缘点,如果小于邻域的值,则为非边缘点。


有的实现采用插值的方式来获取梯度方向上中心点邻域的值,然后进行比较。而opencv,将图像中心点梯度方向近似为4个方向 0, 45, 90 及135,直接可以利用8邻域进行比较计算,不用插值的方法。。


这四个方向正好对应8邻域的横向、纵向及斜向4个方向。例如 角度 < 22.5度(PI/8) 时,横向; 角度 > 67.5度时,纵向...

        1   2   3
         *  *  *
          * * *  
        0*******0
          * * *  
         *  *  *
        3   2   1



其中
#define TG22  (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5)
是tan(PI/8)的快速算法, tg67是tan(67.5)的快速算法。


prev_flag的作用,为1代表前一个像素点为边缘点,为0代表前一个点为非边缘点。目的是将大于high阈值的、且其前面的仍然是边缘点的(其实就是连续几个点是边缘点)点设置为可能是边缘点,即标示此点_map[j] = (uchar)0;,不用入栈,后续采用跟踪的方式再确定为边缘点。


第三个步骤,采用双阈值边缘跟踪。
如果是梯度在邻域中是最大值,且大于high阈值,确定是边缘点,然后以此为中心需找邻域中满足低阈值的点。

如果邻域点满足其点梯度最大值,且大于low阈值,确定此邻域点为边缘点,并递归此步骤。

opencv中阈值判断放在第二步中了,而其第三步仅用来邻域跟踪,采用栈循环非递归的方式实现。将扩展已经是边缘点的8邻域,将可能是边缘点的邻域(_map中为0的点),确定为边缘点。


其他:

获取一个区域内的梯度最大值,能很好的细化边缘。

本质是获取多个梯度

比较大小

梯度最大值与 阈值比较,而且可能是被蹂躏两次,确立边缘点。



reference:
http://cpansearch.perl.org/src/CORION/Image-CCV-0.02/ccv-src/lib/ccv_basic.c
http://comments.gmane.org/gmane.comp.lib.opencv/42781


原创粉丝点击