Canny边缘检测器

由John F. Canny在1986年开发。Canny算法也被称为最佳检测器(optimal detector),旨在满足三个主要标准:

原理

  1. 使用高斯滤波图像
  2. 找到图像的强度梯度。为此,我们遵循类似于Sobel的过程:

    索贝尔 (Sobel) 算法理论

    图像中所有像素其实也就是个二维的离散函数,那么我们将它求导会得到什么?
    假设我们要检测图像中存在的边缘。例如:
    lena
    可以轻松地注意到,在边缘处,像素强度以急速的方式变化。表达变化的好方法是使用导数。

    假设我们有一个1D图像。像素值的迅速变化部分就是图像中的边缘。
    function
    求一阶导数:
    derivative
    假设要操作的图像是I
    计算两个导数:
    1. 横向变化:
      通过将I与奇数大小的内核𝐺𝑥卷积来计算。例如,内核大小3,𝐺𝑥计算为:
      g_x
    2. 纵向变化:
      通过将I与奇数大小的内核𝐺𝑦卷积来计算。例如,内核大小3,𝐺𝑦计算为:
      g_y
    在图像的每个点上,我们通过结合以上两个结果来计算该点的梯度近似值:
    g
  3. 方向舍入为四个可能的角度之一(即0、45、90或135)。
  4. 应用非最大抑制。这将删除不视为边缘一部分的像素。因此,将仅保留细线(候选边缘)。
  5. 最后一步:迟滞。Canny使用两个阈值(Upper和Lower):
    					
    • 如果像素梯度高于上限阈值,则该像素被接受为边缘。

    • 如果像素梯度值低于下阈值,则将其拒绝。

    • 如果像素梯度在两个阈值之间,则仅当它连接到高于上限阈值的像素时才被接受。

    • Canny建议使用2:1到3:1的上/下比例。



例子

#include <opencv2/opencv.hpp> using namespace cv; int th1 = 50, th2 = 50; int main() { // 从默认相机获取图像 VideoCapture capture(0); namedWindow("paras",0); createTrackbar("th1", "paras", &th1, 500); createTrackbar("th2", "paras", &th2, 500); Mat frame, cannyImg; while(1) { capture >> frame; cvtColor(frame, frame, CV_BGR2GRAY); Canny(frame, cannyImg, th1, th2); imshow("frame", frame); imshow("cannyImg", cannyImg); if(waitKey(1) == 'q') break; } return 0; }
canny