OpenCV核心模块核心提炼(四) —— 边缘检测之Canny边缘检测器

一、引入

      Canny边缘检测器可以说是OpenCV中的一个重要工具,它可以自己通过调节阈值对图像边缘进行检测与滤波,具有低错误率与良好的定位。

二、原理

  1. 过滤掉任何噪音。高斯滤波器用于此目的。size = 5可能使用的高斯内核示例如下所示:

    K = \ dfrac {1} {159} \ begin {bmatrix} 2&4&5&4&2 \\ 4&9&12&9&4 \\ 5&12&15&12&5 \\ 4& 9&12&9&4 \\ 2&4&5&4&2 \ end {bmatrix}

  2. 找到图像的强度梯度。为此,我们遵循类似索贝尔的程序:

    1. 使用一对卷积面罩(在Xÿ方向:

      G_ {x} = \ begin {bmatrix} -1&0&+ 1 \\ -2&0&+ 2 \\ -1&0&+ 1 \ end {bmatrix} G_ {y} = \ begin {bmatrix} -1&-2&-1 \\ 0&0&0 \\ +1&+ 2&+ 1 \ end {bmatrix}

    2. 找到梯度强度和方向:

      \ begin {array} {l} G = \ sqrt {G_ {x} ^ {2} + G_ {y} ^ {2}} \\ \ theta = \ arctan(\ dfrac {G_ {y}} {G_ { x}})\ end {array}

      方向四舍五入为四个可能的角度之一(即0,45,90或135)

  3. 应用非最大抑制。这将删除不被视为边缘一部分的像素。因此,仅保留细线(候选边缘)。

  4. 迟滞:最后一步。Canny确实使用了两个阈值(上限和下限):

    1. 如果像素梯度高于阈值,则将像素接受为边缘
    2. 如果像素梯度值低于阈值,则拒绝它。
    3. 如果像素梯度在两个阈值之间,则仅当它连接到高于阈值的像素时才接受。

    Canny建议上限较低的比例在2:1和3:1之间。

三、代码

  1. 创建一些所需的变量:

      Mat src, src_gray;
      Mat dst, detected_edges;
    
      int edgeThresh = 1;
      int lowThreshold;
      int const max_lowThreshold = 100;
      int ratio = 3;
      int kernel_size = 3;
      char* window_name = "Edge Map";
    
    请注意以下事项:
    
    a.我们建立一个3:1的低:高阈值比率(可变*比率*)
    
    b.我们将内核大小设置为:math:`3`(对于canny函数内部执行的sobel操作)
    
    c.我们为以下阈值设置了一个最大值:math:`100`。
    
  2. 加载源图像:

    /// Load an image
    src = imread( argv[1] );
    
    if( !src.data )
      { return -1; }

     

  3. 创建一个src相同类型和大小的矩阵(将是dst

    dst.create( src.size(), src.type() );

     

  4. 将图像转换为灰度(使用函数cvtColor

    cvtColor( src, src_gray, CV_BGR2GRAY );

     

  5. 创建一个窗口以显示结果

    namedWindow( window_name, CV_WINDOW_AUTOSIZE );

     

  6. 创建一个跟踪栏,供用户输入Canny探测器的下限:

    createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );

    请注意以下事项:

    1. 由Trackbar控制的变量是lowThreshold,其限制为max_lowThreshold(我们之前设置为100)
    2. 每次Trackbar注册一个动作时,都会调用回调函数CannyThreshold
  7. 让我们一步一步检查CannyThreshold函数:

    1. 首先,我们使用内核大小为3的过滤器模糊图像:

      blur( src_gray, detected_edges, Size(3,3) );

       

    2. 其次,我们应用OpenCV函数Canny

      Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );

      参数在哪里:

      • detected_edges:源图像,灰度
      • detected_edges:探测器的输出(可以与输入相同)
      • lowThreshold:用户移动Trackbar输入的值
      • highThreshold:在程序中设置为下限阈值的三倍(遵循Canny的建议)
      • kernel_size:我们将它定义为3(内部使用的Sobel内核的大小)
  8. 我们用零填充dst图像(意味着图像是完全黑色的)。

    dst = Scalar::all(0);

     

  9. 最后,我们将使用函数copyTo仅映射图像中标识为边的区域(在黑色背景上)。

    src.copyTo( dst, detected_edges);

    CopyTo从复制的src图像到DST。但是,它只会复制具有非零值的位置的像素。由于Canny探测器的输出是黑色背景上的边缘轮廓,因此得到的dst在所有区域中都是黑色的,但是检测到的边缘。

  10. 我们显示结果:

    imshow( window_name, dst );

     

结果

  • 在编译上面的代码之后,我们可以运行它作为参数给出图像的路径。例如,使用以下图像作为输入:

    原始测试图像

  • 移动滑块,尝试不同的阈值,我们得到以下结果:

    运行Canny后的结果

  • 注意图像如何叠加到边缘区域的黑色背景上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值