Opencv--边缘检测

边缘检测

一、简介

  • 边缘:边缘是图像强度函数快速变化的地方
  • 检测边缘的方法:为了检测边缘,我们需要检测图像中的不连续性,可以使用导数来检测不连续性。
  • 问题:导数也会受到噪声的影响,因此建议在求导数之前先对图像进行平滑处理。 然后我们可以使用遮罩使用卷积来检测边缘。

二、算法理论介绍

Sobel算子

推荐:https://blog.csdn.net/qq_29540745/article/details/51918004?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1

Canny边缘检测

Canny边缘检测于1986年由JOHN CANNY首次在论文《A Computational Approach to Edge Detection》中提出,就此拉开了Canny边缘检测算法的序幕。

Canny边缘检测是从不同视觉对象中提取有用的结构信息并大大减少要处理的数据量的一种技术,目前已广泛应用于各种计算机视觉系统。Canny发现,在不同视觉系统上对边缘检测的要求较为类似,因此,可以实现一种具有广泛应用意义的边缘检测技术。边缘检测的一般标准包括:

以低的错误率检测边缘,也即意味着需要尽可能准确的捕获图像中尽可能多的边缘。
检测到的边缘应精确定位在真实边缘的中心。
图像中给定的边缘应只被标记一次,并且在可能的情况下,图像的噪声不应产生假的边缘。
为了满足这些要求,Canny使用了变分法。Canny检测器中的最优函数使用四个指数项的和来描述,它可以由高斯函数的一阶导数来近似。

在目前常用的边缘检测方法中,Canny边缘检测算法是具有严格定义的,可以提供良好可靠检测的方法之一。由于它具有满足边缘检测的三个标准和实现过程简单的优势,成为边缘检测最流行的算法之一。

完成一个Canny边缘检测算法可以分为以下四步:

高斯滤波目的
1.高斯滤波去噪声降低错误率
2.计算梯度幅值和方向估计每一点处的边缘强度与方向
3.非极大值抑制(NMS)对Sobel、Prewitt等算子的结果进一步细化
4应用双阈值(Double-Threshold)检测确定真实的和可能的边缘
  1. 高斯滤波
    边缘检测结果容易受到图像噪声的影响,图片中一些噪声会大大影像边缘检测。因此为了使图像平滑,可以用高斯滤波器内核与图像进行卷积。 此步骤将使图像稍微平滑,以减少边缘检测器上明显噪声的影响。
    大小为 ( 2 k + 1 ) × ( 2 k + 1 ) (2k + 1)×(2k + 1) 2k+1×2k+1的高斯滤波器核的方程式为:

H i j = 1 2 π σ 2 exp ⁡ ( − ( i − ( k + 1 ) ) 2 + ( j − ( k + 1 ) ) 2 2 σ 2 ) ; 1 ≤ i , j ≤ ( 2 k + 1 ) {\displaystyle H_{ij}={\frac {1}{2\pi \sigma ^{2}}}\exp \left(-{\frac {(i-(k+1))^{2}+(j-(k+1))^{2}}{2\sigma ^{2}}}\right);1\leq i,j\leq (2k+1)} Hij=2πσ21exp(2σ2(i(k+1))2+(j(k+1))2);1i,j(2k+1)

  1. 计算梯度强度和方向
    进行高斯滤波后,图像中的边缘可以指向各个方向,接下来使用四个算子来检测图像中的水平、垂直和对角边缘。边缘检测的算子(如Roberts,Prewitt,Sobel等)返回水平 G x G_x Gx和垂直 G y G_y Gy方向的一阶导数值,由此便可以确定像素点的梯度 G G G和方向 θ \theta θ G = G x 2 + G y 2 (1) \mathbf {G} ={\sqrt {{\mathbf {G} _{x}}^{2}+{\mathbf {G} _{y}}^{2}}} \tag{1} G=Gx2+Gy2 (1)

θ = arctan ⁡ ( G y / G x ) (2) \mathbf {\theta } =\operatorname {arctan} \left(\mathbf {G} _{y}/\mathbf {G} _{x}\right) \tag{2} θ=arctan(Gy/Gx)(2)

其中 G \mathbf {G} G为梯度强度, θ \theta θ表示梯度方向, arctan ⁡ \operatorname {arctan} arctan为反正切函数。通过上式我们可以得到一个梯度矩阵 G \mathbf {G} G和方向矩阵 θ \theta θ

  1. 非极大值抑制(NMS)
    在每一点上,邻域中心与沿着其对应的梯度方向的两个像素相比,若中心像素为最大值,则保留,否则中心置0,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。
    对图像进行梯度计算后,仅仅基于梯度值提取的边缘仍然很模糊。对边缘有且应当只有一个准确的响应。而非极大值抑制则可以帮助将局部最大值之外的所有梯度值抑制为0。非极大值抑制是一种边缘稀疏技术,非极大值抑制的作用在于“瘦”边。直观上地看,对第二步得到的图片,边缘由粗变细了。

  2. 用双阈值算法检测和连接边缘
    双阈值法非常简单,我们假设两类边缘:经过非极大值抑制之后的边缘点中,梯度值超过TH的称为强边缘,梯度值小于TH大于TL的称为弱边缘,梯度小于TL的不是边缘。
    可以肯定的是,强边缘必然是边缘点,因此必须将T1设置的足够高,以要求像素点的梯度值足够大(变化足够剧烈),而弱边缘可能是边缘,也可能是噪声,如何判断呢?当弱边缘的周围8邻域有强边缘点存在时,就将该弱边缘点变成强边缘点,以此来实现对强边缘的补充。实际中人们发现T1:T2=2:1的比例效果比较好,其中T1可以人为指定,也可以设计算法来自适应的指定,比如定义梯度直方图的前30%的分界线为T1。检查8邻域的方法叫边缘滞后跟踪,连接边缘的办法还有区域生长法等等。

三、基于OpenCV的实现

Sobel算子

opencv使用sobel 算子的方法是cv2.Sobel

# -*- coding: utf-8 -*-
"""
cv2.Sobel(src, #参数是需要处理的图像;
		ddepth, #图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度
		dx, #dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
		dy[,
		dst[, #输出图片
		ksize[,#Sobel算子的大小,必须为1、3、5、7。
		scale[, #缩放导数的比例常数,默认情况下没有伸缩系数;
		delta[, #可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
		borderType #判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
		]]]]])
"""
import cv2
import numpy as np
from matplotlib import pyplot as plt

# 读图
img = cv2.imread('1.jpg', 0)

sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)

# 画图
plt.subplot(1, 3, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])

plt.subplot(1, 3, 2), plt.imshow(sobelx, cmap='gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])

plt.subplot(1, 3, 3), plt.imshow(sobely, cmap='gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])

plt.show()

结果:
在这里插入图片描述

Canny算法

# -*- coding: utf-8 -*-

"""
cv2.Canny(image,            # 输入原图(必须为单通道图)
          threshold1,
          threshold2,       # 较大的阈值2用于检测图像中明显的边缘
          [, edges[,
          apertureSize[,    # apertureSize:Sobel算子的大小
          L2gradient ]]])   # 参数(布尔值):
                              true: 使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放),
                              false:使用L1范数(直接将两个方向导数的绝对值相加)。
"""

import cv2
import numpy as np
import matplotlib.pyplot as plt

original_img = cv2.imread("1.jpg", 0)

# canny边缘检测
img1 = cv2.GaussianBlur(original_img, (3, 3), 0)
canny = cv2.Canny(img1, 50, 150)

# 画图
plt.subplot(1, 2, 1), plt.imshow(original_img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])

plt.subplot(1, 2, 2), plt.imshow(canny, cmap='gray')
plt.title('Canny'), plt.xticks([]), plt.yticks([])
plt.show()

结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV-Python是一个用于计算机视觉和图像处理的开源库。边缘检测OpenCV-Python中一个重要的图像处理操作。根据引用的内容,边缘检测的方法包括Laplacian边缘检测、Sobel边缘检测和Canny边缘检测。其中,Laplacian边缘检测是一种基于二阶导数的方法,Sobel边缘检测是一种基于一阶导数的方法,而Canny边缘检测是一种综合了多种方法的优化算法。您可以根据引用中的文章目录了解更多关于这些方法的详细信息。 引用给出了一个使用OpenCV-Python进行自动确定阈值的边缘检测的示例代码。该代码首先读取一张名为'bee.jpg'的图像,并将其转换为灰度图像。然后,通过应用高斯模糊对图像进行预处理,使用自动确定阈值的方法计算合适的阈值,最后使用Canny边缘检测算法检测图像的边缘。您可以根据需要调整代码中的参数来适应不同的图像。 总而言之,OpenCV-Python提供了多种边缘检测方法,包括Laplacian边缘检测、Sobel边缘检测和Canny边缘检测。您可以根据具体需求选择适合的方法,并使用OpenCV-Python提供的函数进行图像处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【OpenCV-Python】14.OpenCV边缘检测](https://blog.csdn.net/weixin_43843069/article/details/121950301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值