Opencv-Python学习笔记(七):边缘检测

本片文章记录学习边缘检测的运用。

  • 了解坎尼边缘检测的概念
  • 学习函数:cv2.Canny()。

Canny 边缘检测

  • 使用高斯滤波器,以平滑图像,滤除噪声。

       由于边缘检测很容易受到噪声影响,所以第一步是使用 5x5 的高斯滤波器去除噪声。

  • 计算图像中每个像素点的梯度强度和方向

       对平滑后的图像使用 Sobel 算子计算水平方向和竖直方向的一阶导数(图像梯度)( Gx 和 Gy)。根据得到的这两幅梯度图( Gx 和 Gy)找到边界的梯度和方向,公式如下:

                                                                 Edge Gradient (G)=\sqrt{G_{X}^{2}+G_{Y}^{2}}    

                                                                  Angle(\theta )=tan^{-1}(\frac{G_{X}}{G_{Y}})

      梯度的方向一般总是与边界垂直。梯度方向被归为四类:垂直,水平,和两个对角线。

  • 应用非极大值抑制,以消除边缘检测带来的杂散影响。

       在获得梯度的方向和大小之后,应该对整幅图像做一个扫描,去除那些非边界上的点。对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的。如下图所示:

    点A在边缘(垂直方向)上。渐变方向垂直于边缘。点B和C在梯度方向上。因此,将A点与B点和C点进行检查,看是否形成局部最大值。如果是这样,则考虑将其用于下一阶段,否则将其抑制(置为零)。即得到的是一个包含“窄边界”的二值图像。

  • 应用双阈值检测来确定真实和潜在的边缘。

      现在要确定那些边界才是真正的边界。这时我们需要设置两个阈值:minVal 和 maxVal。当图像的灰度梯度高于 maxVal 时被认为是真的边界,那些低于 minVal 的边界会被抛弃。如果介于两者之间的话,就要看这个点是否与某个被确定为真正的边界点相连,如果是就认为它也是边界点,如果不是就抛弃。如下图:

 

       A 高于阈值 maxVal 所以是真正的边界点, C 虽然低于 maxVal 但高于minVal 并且与 A 相连,所以也被认为是真正的边界点。而 B 就会被抛弃,因为他不仅低于 maxVal 而且不与真正的边界点相连。所以选择合适的 maxVal和 minVal 对于能否得到好的结果非常重要。在这一步一些小的噪声点也会被除去,因为我们假设边界都是一些长的线段。

  • 通过抑制孤立的弱边缘最终完成边缘检测。

​​​​​​​接下来我们看一下效果:

# -*- coding: utf-8 -*-
# @Time    : 2019/10/19 17:11
# @Author  : MMagicLoren
# @Email   : 993983320@qq.com
# @File    : 边缘检测.py
# @Software: PyCharm
import cv2 as cv
import numpy as np


def canny_demo(image):
    edges1 = cv.Canny(image, 80, 150)
    edges2 = cv.Canny(image, 30, 100)
    res = np.hstack((edges1, edges2))
    cv.imshow('res', res)


if __name__ == '__main__':
    src = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu1.jpg")  # 读入图片放进src中
    # cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)  # 创建窗口, 窗口尺寸自动调整
    # cv.imshow("input image", src)
    canny_demo(src)
    cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    cv.destroyAllWindows()

可见,设置的阈值越小,检测出来的边缘越多。

我们知道了Canny边缘检测的原理之后,我们可以用之前学过的知识,自己写个demo看看效果。

# -*- coding: utf-8 -*-
# @Time    : 2019/10/19 17:11
# @Author  : MMagicLoren
# @Email   : 993983320@qq.com
# @File    : 边缘检测.py
# @Software: PyCharm
import cv2 as cv
import numpy as np


def edges_demo(image):
    blurred = cv.GaussianBlur(image, (3, 3), 0)
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
    xgray = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
    ygray = cv.Sobel(gray, cv.CV_16SC1, 0, 1)

    edges_output = cv.Canny(xgray, ygray, 50, 150)  # edges_output = cv.Canny(gray, 50, 150)
    cv.imshow("Canny Edges", edges_output)
    dst = cv.bitwise_and(image, image, mask=edges_output)  # 彩色边缘输出
    cv.imshow("Color Edges", dst)


if __name__ == '__main__':
    src = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu1.jpg")  # 读入图片放进src中
    # cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)  # 创建窗口, 窗口尺寸自动调整
    # cv.imshow("input image", src)
    canny_demo(src)
    # edges_demo(src)
    cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    cv.destroyAllWindows()

完整工程代码:

# -*- coding: utf-8 -*-
# @Time    : 2019/10/19 17:11
# @Author  : MMagicLoren
# @Email   : 993983320@qq.com
# @File    : 边缘检测.py
# @Software: PyCharm
import cv2 as cv
import numpy as np


def canny_demo(image):
    edges1 = cv.Canny(image, 80, 150)
    edges2 = cv.Canny(image, 30, 100)
    res = np.hstack((edges1, edges2))
    cv.imshow('res', res)


def edges_demo(image):
    blurred = cv.GaussianBlur(image, (3, 3), 0)
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
    xgray = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
    ygray = cv.Sobel(gray, cv.CV_16SC1, 0, 1)

    edges_output = cv.Canny(xgray, ygray, 50, 150)  # edges_output = cv.Canny(gray, 50, 150)
    cv.imshow("Canny Edges", edges_output)
    dst = cv.bitwise_and(image, image, mask=edges_output)  # 彩色边缘输出
    cv.imshow("Color Edges", dst)


if __name__ == '__main__':
    src = cv.imread("F:/Pycharm/opencv_exercises-master/images/CrystalLiu1.jpg")  # 读入图片放进src中
    # cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)  # 创建窗口, 窗口尺寸自动调整
    # cv.imshow("input image", src)
    # canny_demo(src)
    edges_demo(src)
    cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    cv.destroyAllWindows()

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MMagicLoren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值