OpenCV-Python快速入门(七):边缘检测

前言

  • 本文是个人快速入门OpenCV-Python的电子笔记,由于水平有限,难免出现错漏,敬请批评改正。
  • 更多精彩内容,可点击进入
    OpenCV-Python快速入门
    专栏或我的个人主页查看

前提条件

实验环境

  • Python 3.x (面向对象的高级语言)
  • OpenCV 4.0(python第三方库)pip3 install opencv-python

边缘检测

图像梯度

  • 图像梯度计算的是图像变化的速度。对于图像的边缘部分,其灰度值变化较大,梯度值也较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小。一般情况下,图像梯度计算的是图像的边缘信息。
  • 严格来讲,图像梯度计算需要求导数,但是图像梯度一般通过计算像素值的差来得到梯度的近似值(近似导数值)。
  • 在图像处理中,我们经常使用用 Sobel 算子、Scharr算子、 Laplacian 算子来计算图像的边缘信息。
  • 由于本文撰写的目的是快速入门,上述知识点,在入门阶段,了解并且会应用即可。

Sobel 算子

  • Sobel 算子是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。
  • Sobel 算子,一般定义为 [ − 1 0 1 − 2 0 2 − 1 0 1 ] \left[ \begin{matrix} -1 & 0 & 1\\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{matrix} \right] 121000121 [ − 1 − 2 − 1 0 0 0 − 1 2 1 ] \left[ \begin{matrix} -1 & -2 & -1\\ 0 & 0 & 0 \\ -1 & 2 & 1 \end{matrix} \right] 101202101
  • 计算水平方向偏导数的近似值,将 Sobel 算子与原始图像 img 进行卷积计算 Sobel 算子与原始图像 img 进行卷积计算。 G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] ∗ i m g G_x=\left[ \begin{matrix} -1 & 0 & 1\\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{matrix} \right]*img Gx= 121000121 img其中, G x G_x Gx表示水平方向偏导数。
  • 计算垂直方向偏导数的近似值,将 Sobel 算子与原始图像 img 进行卷积计算 Sobel 算子与原始图像 img 进行卷积计算。 G y = [ − 1 − 2 − 1 0 0 0 − 1 2 1 ] ∗ i m g G_y=\left[ \begin{matrix} -1 & -2 & -1\\ 0 & 0 & 0 \\ -1 & 2 & 1 \end{matrix} \right]*img Gy= 101202101 img其中, G y G_y Gy表示垂直方向偏导数。
  • 注:需要了解卷积运算的,可查阅OpenCV-Python快速入门(六):图像平滑
import cv2
import numpy as np

img1=cv2.imread("1.jpg",0)
img1_resize=cv2.resize(img1,(400,400))
'''
dst = cv2.Sobel( src, ddepth, dx, dy[,ksize[, scale[, delta[, borderType]]]] )
参数说明:
    dst 代表目标图像。
    src 代表原始图像。
    ddepth 代表输出图像的深度。
    dx 代表 x 方向上的求导阶数。
    dy 代表 y 方向上的求导阶数。
    ksize 代表 Sobel 核的大小。该值为-1 时,则会使用 Scharr 算子进行运算。
    scale 代表计算导数值时所采用的缩放因子,默认情况下该值是 1,是没有缩放的。
    delta 代表加在目标图像 dst 上的值,该值是可选的,默认为 0。
    borderType 代表边界样式。
'''
# 计算水平方向边缘(梯度):dx=1,dy=0
Sobelx = cv2.Sobel(img1_resize,cv2.CV_64F,1,0)
# 计算垂直方向边缘(梯度):dx=0,dy=1
Sobely = cv2.Sobel(img1_resize,cv2.CV_64F,0,1)
# 计算两个方向边缘(梯度):dx=1,dy=1
Sobelxy = cv2.Sobel(img1_resize,cv2.CV_64F,1,1)
# 计算x方向和y方向的边缘叠加
Sobelx_add_Sobely=cv2.addWeighted(Sobelx,0.5,Sobely,0.5,0)
# 取计算结果绝对值
SobelAbs=cv2.convertScaleAbs(Sobelxy)
cv2.imshow("origin",img1_resize)
cv2.imshow("Sobelx",Sobelx)
cv2.imshow("Sobely",Sobely)
cv2.imshow("Sobelxy",Sobelxy)
cv2.imshow("Sobelx_add_Sobely",Sobelx_add_Sobely)
cv2.imshow("SobelAbs",SobelAbs)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

Scharr 算子

  • 在离散的空间上,有很多方法可以用来计算近似导数,在使用 3×3 的 Sobel 算子时,可能计算结果并不太精准。OpenCV 提供了 Scharr 算子,该算子具有和 Sobel 算子同样的速度,且精度更高。
  • Scharr 算子,一般定义为 [ − 3 0 3 − 10 0 10 − 3 0 3 ] \left[ \begin{matrix} -3 & 0 & 3\\ -10 & 0 & 10 \\ -3 & 0 & 3 \end{matrix} \right] 31030003103 [ − 3 − 10 − 3 0 0 0 − 3 10 3 ] \left[ \begin{matrix} -3 & -10 & -3\\ 0 & 0 & 0 \\ -3 & 10 & 3 \end{matrix} \right] 30310010303
  • Scharr 算子的计算方式与Sobel 算子的一样,只是算子不一样。
import cv2
import numpy as np

img1=cv2.imread("1.jpg",0)
img1_resize=cv2.resize(img1,(400,400))
'''
dst = cv2.Scharr( src, ddepth, dx, dy[, scale[, delta[, borderType]]] )
参数说明:
    dst 代表输出图像。
    src 代表原始图像。
    ddepth 代表输出图像深度。该值与函数 cv2.Sobel()中的参数 ddepth 的含义相同
    dx 代表 x 方向上的导数阶数。
    dy 代表 y 方向上的导数阶数。
    scale 代表计算导数值时的缩放因子,该项是可选项,默认值是 1,表示没有缩放。
    delta 代表加到目标图像上的亮度值,该项是可选项,默认值为 0。
    borderType 代表边界样式。
'''
# 计算水平方向边缘(梯度):dx=1,dy=0
Scharrx = cv2.Scharr(img1_resize,cv2.CV_64F,1,0)
# 取计算结果绝对值
ScharrxAbs=cv2.convertScaleAbs(Scharrx)
# 计算垂直方向边缘(梯度):dx=0,dy=1
Scharry = cv2.Scharr(img1_resize,cv2.CV_64F,0,1)
# 取计算结果绝对值
ScharryAbs=cv2.convertScaleAbs(Scharry)
# 计算x方向和y方向的边缘叠加
Scharrx_add_Scharry=cv2.addWeighted(Scharrx,0.5,Scharry,0.5,0)

cv2.imshow("origin",img1_resize)
cv2.imshow("Scharrx",Scharrx)
cv2.imshow("ScharrxAbs",ScharrxAbs)
cv2.imshow("Scharry",Scharry)
cv2.imshow("SobelyAbs",ScharryAbs)
cv2.imshow("Scharrx_add_Scharry",Scharrx_add_Scharry)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

Laplacian 算子

  • Laplacian(拉普拉斯)算子是一种二阶导数算子,其具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求。通常情况下,其算子的系数之和需要为零。
  • 一个 3×3 大小的 Laplacian 算子为 [ 0 1 0 1 − 4 1 0 1 0 ] \left[ \begin{matrix} 0 & 1 & 0\\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{matrix} \right] 010141010
  • Laplacian 算子的计算方式与Sobel 算子、Scharr 算子的一样,只是算子不一样。
import cv2
import numpy as np

img1=cv2.imread("1.jpg",0)
img1_resize=cv2.resize(img1,(400,400))
'''
dst = cv2.Laplacian( src, ddepth[, ksize[, scale[, delta[, borderType]]]] )
参数说明:
    dst 代表目标图像。
    src 代表原始图像。
    ddepth 代表目标图像的深度。
    ksize 代表用于计算二阶导数的核尺寸大小。该值必须是正的奇数。
    scale 代表计算 Laplacian 值的缩放比例因子,该参数是可选的。默认情况下,该值为 1,
    表示不进行缩放。
    delta 代表加到目标图像上的可选值,默认为 0。
    borderType 代表边界样式。
'''
# 计算两个方向的梯度值
Laplacianxy = cv2.Laplacian(img1_resize,cv2.CV_64F)
# 取计算结果绝对值
LaplacianAbs = cv2.convertScaleAbs(Laplacianxy)
cv2.imshow("origin",img1_resize)
cv2.imshow("Laplacianxy",Laplacianxy)
cv2.imshow("LaplacianAbs",LaplacianAbs)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

Canny 边缘检测

  • Canny 边缘检测是一种使用多级边缘检测算法检测边缘的方法。
  • Canny 边缘检测分为如下几个步骤。
    1. 去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。(通常使用高斯滤波进行去噪,需要了解高斯滤波的,可查阅OpenCV-Python快速入门(六):图像平滑
    2. 计算梯度的幅度与方向。
    3. 非极大值抑制,即适当地让边缘“变瘦”。
    4. 确定边缘。使用双阈值算法确定最终的边缘信息。
  • 由于本文撰写的目的是快速入门,Canny 边缘检测步骤,在入门阶段,了解并且会应用即可。
  • 扩展知识: n o r m = { ∣ d l d x ∣ + ∣ d l d y ∣ , L 2 g r a d i e n t = F a l s e ( d l d x ) 2 + ( d l d y ) 2 , L 2 g r a d i e n t = T r u e norm= \begin{cases} |\frac{dl}{dx}|+|\frac{dl}{dy}|,\quad L2gradient = False\\ \sqrt{(\frac{dl}{dx})^2 + (\frac{dl}{dy})^2},\quad L2gradient = True \end{cases} norm={dxdl+dydlL2gradient=False(dxdl)2+(dydl)2 L2gradient=True其中,L2gradient = False时,表达式是L1范数,L2gradient = True时,表达式是L2范数。
import cv2
import numpy as np

img1=cv2.imread("1.jpg",0)
img1_resize=cv2.resize(img1,(400,400))
'''
edges = cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])
参数说明:
    edges 为计算得到的边缘图像。
    image 为 8 位输入图像。
    threshold1 表示处理过程中的第一个阈值。
    threshold2 表示处理过程中的第二个阈值。
    apertureSize 表示 Sobel 算子的孔径大小。
    L2gradient 为计算图像梯度幅度(gradient magnitude)的标识。
        其默认值为 False。如果为 True,则使用更精确的 L2 范数进行计算
        (即两个方向的导数的平方和再开方),否则使用 L1 范数
        (直接将两个方向导数的绝对值相加)。
'''
edges1 = cv2.Canny(img1_resize,128,200)
edges2 = cv2.Canny(img1_resize,32,128)
cv2.imshow("origin",img1_resize)
cv2.imshow("edges1",edges1)
cv2.imshow("edges2",edges2)
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

从输出结果上看,当函数 cv2.Canny()的参数 threshold1 和 threshold2 的值较小时,能够捕获更多的边缘信息。

参考文献

[1] https://opencv.org/
[2] 李立宗. OpenCV轻松入门:面向Python. 北京: 电子工业出版社,2019

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
很好,下面我来为你介绍一下 OpenCV-Python 实现目标检测的过程。 OpenCV-Python 是一款基于 Python计算机视觉库,它可以帮助我们完成各种图像处理任务,包括图像的读取、处理、显示等。在使用它进行目标检测时,我们可以使用传统方法 HOG+SVM 实现。 HOG(Histogram of Oriented Gradient)特征是一种常用的图像特征,它可以描述图像中的边缘、角点等信息,其中梯度方向直方图是 HOG 特征的核心部分。在目标检测中,我们需要先提取出图像中的 HOG 特征,然后再使用 SVM(Support Vector Machine)进行分类,从而实现目标检测。 下面是一个简单的 OpenCV-Python 实现目标检测的示例代码: ```python import cv2 # 加载 SVM 分类器 svm = cv2.ml.SVM_load('svm.xml') # 加载测试图片 img = cv2.imread('test.jpg') # 创建 HOG 描述符 hog = cv2.HOGDescriptor() # 设置 SVM 分类器 hog.setSVMDetector(svm) # 检测目标并绘制矩形框 rects, weights = hog.detectMultiScale(img, winStride=(8, 8), padding=(32, 32), scale=1.05) for (x, y, w, h) in rects: cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # 显示结果 cv2.imshow('result', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在代码中,我们首先加载了训练好的 SVM 分类器,并加载了测试图片。然后创建了 HOG 描述符,并设置 SVM 分类器。最后使用 detectMultiScale 函数检测目标,并绘制矩形框,最终在窗口中显示检测结果。 当然,这仅仅是一个简单的示例,实际的目标检测过程还需要根据具体的应用场景进行调整和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FriendshipT

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

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

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

打赏作者

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

抵扣说明:

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

余额充值