图像梯度处理
1. Sobel算子
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
ddepth:输出图像的深度,-1 表示采用的是与原图像相同的深度。
dx:代表 x 方向上的求导阶数,0 表示这个方向上没有求导,一般为 0、1、2。
dy:代表 y 方向上的求导阶数,0 表示这个方向上没有求导,一般为 0、1、2。
ksize:代表 Sobel 算子的大小,必须为 1、3、5、7。该值为 -1 时,则会使用 Scharr 算子进行运算。
复习一下前面学习过的函数
图像混合/叠加:cv2.addWeighted(src1, 权重1, src2, 权重2, gamma=0)
公式:
d
s
t
=
s
r
c
1
∗
权重
1
+
s
r
c
2
∗
权重
2
+
偏移量
g
a
m
m
a
dst = src1 * 权重1 + src2 * 权重2 + 偏移量 gamma
dst=src1∗权重1+src2∗权重2+偏移量gamma
square.png原图:
import cv2
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread("square.png",cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx) #函数cv2.convertScaleAbs()对一个随机数组取绝对值
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) #x、y求和
#sobelxy = cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
#直接设置dx=dy=1,得到的sobelxy效果一般般,没有上面的方法好(可自行尝试)
result = np.hstack((sobelx,sobely,sobelxy))
cv_show("sobelx-sobely",result)
# 实例
#import、函数cv_show与前面一样,省略,仅修改下面
img = cv2.imread("lena.jpg",cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
result = np.hstack((img,sobelxy))
cv_show("img-sobelxy",result)
plt.imshow(result)
2. Scharr算子
cv2.Scharr(src,ddepth, dx, dy)
和 sobel 算子相比,scharr 算子临近像素的权重更大,scharr 算子能计算出更小的梯度变化,故精确度更高。
3. Laplacian算子
cv2.Laplacian(src,ddepth)
Laplacian 算子对噪声比较敏感,所以图像一般先经过平滑处理
4. 不同算子的比较
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3) #Sobel算子
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
sobelxy = cv2.convertScaleAbs(sobelxy)
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0) #Scharr算子
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
scharrxy = cv2.convertScaleAbs(scharrxy)
laplacian = cv2.Laplacian(img,cv2.CV_64F) #Laplacian算子
laplacian = cv2.convertScaleAbs(laplacian)
result = np.hstack((sobelxy,scharrxy,laplacian))
cv_show("sobel-scharr-laplacian",result)
使用 sobel 算子的轮廓要更清晰,scharr 算子的轮廓的细节更多,laplacian 获得的结果边缘信息较浅。
Canny边缘检测
Canny 边缘检测算子是 John F. Canny 于 1986 年开发出来的一个多级边缘检测算法。
Canny 边缘检测算法可以分为以下 5 个步骤 :
(1)应用高斯滤波来平滑图像,目的是去除噪声
(2)找寻图像的强度梯度
(3)应用非最大抑制技术来消除边误检(本来不是但检测出来是)
(4)应用双阈值的方法来决定可能的(潜在的)边界
(5)利用滞后技术来跟踪边界
双阈值检测:
梯度值 > maxVal:则处理为边界
minVal < 梯度值 < maxVal:连有边界则保留,否则舍弃
梯度值 < minVal:则舍弃
edge = cv2.Canny(image, minVal, maxVal)
必要参数:
image:需要处理的原图像,该图像必须为单通道的灰度图;
minVal:阈值 1,较小的阈值 1 用于将间断的边缘连接起来;
maxVal:阈值 2,较大的阈值 2 用于检测图像中明显的边缘,但一般情况下检测的效果不会那么完美,边缘检测出来是断断续续的。
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img=cv2.imread("lena.jpg",cv2.IMREAD_GRAYSCALE)
c1=cv2.Canny(img,80,150) #阈值不同,效果不同
c2=cv2.Canny(img,50,100)
result = np.hstack((c1,c2))
cv_show("result",result)
本笔记记录学习OpenCV,若有错误,欢迎批评指正,学习交流。