zoukankan      html  css  js  c++  java
  • OpenCV---Canny边缘提取

    一:Canny算法介绍

    Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:
    好的检测- 算法能够尽可能多地标识出图像中的实际边缘。
    好的定位- 标识出的边缘要尽可能与实际图像中的实际边缘尽可能接近。
    最小响应- 图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。

    推文:Canny边缘检测算法原理及其VC实现详解(一)

    1.高斯模糊--GaussianBlur  消除噪声。 一般情况下,使用高斯平滑滤波器卷积降噪。,因为canny是对噪声敏感的算法,所以先降噪,但是降噪不要太过,以免丢失
    2.灰度转换--cvtColor  
    3.计算梯度--Sobel/Scharr
    4.非最大信号抑制
    5.高低阈值输出二值图像

    补充:

    非最大信号抑制

    在Canny算法中,非极大值抑制是进行边缘检测的重要步骤,通俗意义上是指寻找像素点局部最大值,将非极大值点所对应的灰度值置为0
    sobel算子中有一个x,y
    根据x,y可以求出一个θ角度
    1.要进行非极大值抑制,就首先要确定像素点C的灰度值在其8值邻域内是否为最大。是最大则下一步
    2.图中蓝色的线条方向为C点的梯度方向,这样就可以确定其局部的最大值肯定分布在这条线上,也即出了C点外,梯度方向的交点dTmp1和dTmp2这两个点的值也可能会是局部最大值。
    因此,判断C点灰度与这两个点灰度大小即可判断C点是否为其邻域内的局部最大灰度点
    3.如果经过判断,C点灰度值小于这两个点中的任一个,那就说明C点不是局部极大值,那么则可以排除C点为边缘。
    完成非极大值抑制后,会得到一个二值图像,非边缘的点灰度值均为0,可能为边缘的局部灰度极大值点可设置其灰度为128
    根据下文的具体测试图像可以看出,这样一个检测结果还是包含了很多由噪声及其他原因造成的假边缘。因此还需要进一步的处理。

    高低阈值输出二值图像

     二:Canny边缘提取实现

    def edge_demo(image):
        #1.高斯模糊
        blurred = cv.GaussianBlur(image,(3,3),0)
        #2.灰度转换
        gray = cv.cvtColor(blurred,cv.COLOR_RGB2GRAY)
        #3.计算梯度
        xgrad = cv.Sobel(gray,cv.CV_16SC1,1,0)  #canny方法API要求不允许使用浮点数
        ygrad = cv.Sobel(gray,cv.CV_16SC1,0,1)
        #4.Canny方法中包含非最大信号抑制和双阈值输出
        edge_output = cv.Canny(xgrad,ygrad,50,150)  #50是低阈值,150是高阈值
        cv.imshow("Canny Edge",edge_output)
    
        dst = cv.bitwise_and(image,image,mask=edge_output)  #相与,获取颜色
        cv.imshow("Color Edge",dst)

    src = cv.imread("./g.png")  #读取图片
    cv.namedWindow("input image",cv.WINDOW_AUTOSIZE) #创建GUI窗口,形式为自适应
    cv.imshow("input image",src) #通过名字将图像和窗口联系

    edge_demo(src)

    cv.waitKey(0) #等待用户操作,里面等待参数是毫秒,我们填写0,代表是永远,等待用户操作
    cv.destroyAllWindows() #销毁所有窗口

     使用Canny计算梯度

    def edge_demo(image):
        #1.高斯模糊
        blurred = cv.GaussianBlur(image,(3,3),0)
        #2.灰度转换
        gray = cv.cvtColor(blurred,cv.COLOR_RGB2GRAY)
        #3.直接传入灰度图像,Canny方法中包含计算梯度,非最大信号抑制和双阈值输出
        edge_output = cv.Canny(gray,50,150)  #50是低阈值,150是高阈值
        cv.imshow("Canny Edge",edge_output)
    
        dst = cv.bitwise_and(image,image,mask=edge_output)
        cv.imshow("Color Edge",dst)

     相关知识补充

    (一)Canny方法

    (1)需要我们求出梯度

    Canny(dx, dy, threshold1, threshold2[, edges[, L2gradient]]) -> edges
    使用带自定义图像渐变的Canny算法在图像中查找边缘,
    
    其函数原型为:Canny(dx, dy, threshold1, threshold2[, edges[, L2gradient]]) -> edges
    
    dx参数表示输入图像的x导数(x导数满足16位,选择CV_16SC1或CV_16SC3)
    
    dy参数表示输入图像的y导数(y导数满足16位,选择CV_16SC1或CV_16SC3)。
    
    threshold1参数表示设置的低阈值。
    
    threshold2参数表示设置的高阈值,一般设定为低阈值的3倍 (根据Canny算法的推荐)。
    
    edges参数表示输出边缘图像,单通道8位图像。
    
    L2gradient参数表示L2gradient参数表示一个布尔值,如果为真,则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开方),否则使用L1范数(直接将两个方向导数的绝对值相加)。

    (2)直接调用Canny算法在单通道灰度图像中查找边缘,

    def Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None): # real signature unknown; restored from __doc__
    image参数表示8位输入图像。
    
    threshold1参数表示设置的低阈值。
    
    threshold2参数表示设置的高阈值,一般设定为低阈值的3倍 (根据Canny算法的推荐)。
    
    edges参数表示输出边缘图像,单通道8位图像。
    
    apertureSize参数表示Sobel算子的大小。
    
    L2gradient参数表示一个布尔值,如果为真,则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开方),否则使用L1范数(直接将两个方向导数的绝对值相加)。
  • 相关阅读:
    cf1100 F. Ivan and Burgers
    cf 1033 D. Divisors
    LeetCode 17. 电话号码的字母组合
    LeetCode 491. 递增的子序列
    LeetCode 459.重复的子字符串
    LeetCode 504. 七进制数
    LeetCode 3.无重复字符的最长子串
    LeetCode 16.06. 最小差
    LeetCode 77. 组合
    LeetCode 611. 有效三角形个数
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9275058.html
Copyright © 2011-2022 走看看