赞
踩
- 本文是个人快速入门OpenCV-Python的电子笔记,由于水平有限,难免出现错漏,敬请批评改正。
- 更多精彩内容,可点击进入
OpenCV-Python快速入门专栏或我的个人主页查看
- 熟悉Python
- Python 3.x (面向对象的高级语言)
- OpenCV 4.0(python第三方库)
pip3 install opencv-python
- 图像梯度计算的是图像变化的速度。对于图像的边缘部分,其灰度值变化较大,梯度值也较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小。一般情况下,图像梯度计算的是图像的边缘信息。
- 严格来讲,图像梯度计算需要求导数,但是图像梯度一般通过计算像素值的差来得到梯度的近似值(近似导数值)。
- 在图像处理中,我们经常使用用 Sobel 算子、Scharr算子、 Laplacian 算子来计算图像的边缘信息。
- 由于本文撰写的目的是快速入门,上述知识点,在入门阶段,了解并且会应用即可。
- Sobel 算子是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。
- Sobel 算子,一般定义为 [ − 1 0 1 − 2 0 2 − 1 0 1 ] \left[
\right] ⎣ ⎡−1−2−1000121⎦ ⎤ [ − 1 − 2 − 1 0 0 0 − 1 2 1 ] \left[−1−2−1000121 \right] ⎣ ⎡−10−1−202−101⎦ ⎤−10−1−202−101 - 计算水平方向偏导数的近似值,将 Sobel 算子与原始图像 img 进行卷积计算 Sobel 算子与原始图像 img 进行卷积计算。 G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] ∗ i m g G_x=\left[
\right]*img Gx=⎣ ⎡−1−2−1000121⎦ ⎤∗img其中, G x G_x Gx表示水平方向偏导数。−1−2−1000121 - 计算垂直方向偏导数的近似值,将 Sobel 算子与原始图像 img 进行卷积计算 Sobel 算子与原始图像 img 进行卷积计算。 G y = [ − 1 − 2 − 1 0 0 0 − 1 2 1 ] ∗ i m g G_y=\left[
\right]*img Gy=⎣ ⎡−10−1−202−101⎦ ⎤∗img其中, G y G_y Gy表示垂直方向偏导数。−10−1−202−101 - 注:需要了解卷积运算的,可查阅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()
- 在离散的空间上,有很多方法可以用来计算近似导数,在使用 3×3 的 Sobel 算子时,可能计算结果并不太精准。OpenCV 提供了 Scharr 算子,该算子具有和 Sobel 算子同样的速度,且精度更高。
- Scharr 算子,一般定义为 [ − 3 0 3 − 10 0 10 − 3 0 3 ] \left[
\right] ⎣ ⎡−3−10−30003103⎦ ⎤ [ − 3 − 10 − 3 0 0 0 − 3 10 3 ] \left[−3−10−30003103 \right] ⎣ ⎡−30−3−10010−303⎦ ⎤−30−3−10010−303 - 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(拉普拉斯)算子是一种二阶导数算子,其具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求。通常情况下,其算子的系数之和需要为零。
- 一个 3×3 大小的 Laplacian 算子为 [ 0 1 0 1 − 4 1 0 1 0 ] \left[
\right] ⎣ ⎡0101−41010⎦ ⎤0101−41010 - 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 边缘检测分为如下几个步骤。
- 去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。(通常使用高斯滤波进行去噪,需要了解高斯滤波的,可查阅OpenCV-Python快速入门(六):图像平滑)
- 计算梯度的幅度与方向。
- 非极大值抑制,即适当地让边缘“变瘦”。
- 确定边缘。使用双阈值算法确定最终的边缘信息。
- 由于本文撰写的目的是快速入门,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=
norm={∣dxdl∣+∣dydl∣,L2gradient=False(dxdl)2+(dydl)2 ,L2gradient=True其中,L2gradient = False时,表达式是L1范数,L2gradient = True时,表达式是L2范数。⎧⎩⎨|dldx|+|dldy|,L2gradient=False(dldx)2+(dldy)2−−−−−−−−−−−√,L2gradient=True
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
- 更多精彩内容,可点击进入
OpenCV-Python快速入门专栏或我的个人主页查看
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。