opencv+python入门之七(边缘提取之sobel、scharr、laplacian、canny算子等)

1.sobel算子

sobel算子的原理便是求出x,y方向的梯度。梯度的计算方法如下:

G{x}=\begin{bmatrix} -1\ 0\1 \\ -2\ 0 \2\\ -1\0\ 1 \end{bmatrix}*\begin{bmatrix} P1 \ P2 \ P3 \\ P4\ P5\ P6 \\ P7\ P8\ P9 \end{bmatrix}可以得到元素P5在x方向的梯度为P3-P1+2*(P6-P4)+P9-P7。

G{y}=\begin{bmatrix} -1 \ -2 \ -1 \\ 0 \ 0 \ 0\\ 1 \ 2 \ 1 \end{bmatrix}*\begin{bmatrix} P1 \ P2 \ P3 \\ P4\ P5\ P6 \\ P7\ P8\ P9 \end{bmatrix}可以得到元素P5在y方向的梯度为P3-P1+2*(P6-P4)+P9-P7。

然后将Gx和Gy取绝对值相加,根据差值的大小来判断是否为边界。(注意这里要取绝对值,不然可能会丢失一些信息)

sobel算子检测边缘通过cv2.sobel(src,ddepth,dx.dy[,ksize])函数来实现。其中ddepth指的是处理图象的深度,等于1时表示与原图像相同的深度,但是要注意的是如果原图像为uint8类型的,需要转换成有符号的,例如cv2.CV_16S和cv2.CV_64F保留负数部分。当dx =0,dy=1时,求得是y方向的梯度。 ksize一般设置为-1。

求得梯度之后,通过cv2.convertScaleAbs(y)  函数来将求得的梯度转化为uint8类型的数,最后通过前面博文介绍的图像融合函数cv2.addWeighted(absX,0.5,absY,0.5,0) 将x和y方向的梯度合成便是最终的边缘信息。代码如下:

import cv2
import numpy as np

img = cv2.imread('F:\python\work\cv_learn\lena.jpg',1)#读取图像
x = cv2.Sobel(img,cv2.CV_16S,1,0)  #求x方向梯度
y = cv2.Sobel(img,cv2.CV_16S,0,1)  
  
absX = cv2.convertScaleAbs(x)   # 转回uint8  
absY = cv2.convertScaleAbs(y)  
  
dst = cv2.addWeighted(absX,0.5,absY,0.5,0) #合成
cv2.imshow('sobel',dst) 
cv2.waitKey(0)#保持图像

运行效果如下:

                                                 opencv+python入门之七(边缘提取之sobel、scharr、laplacian、canny算子等)_第1张图片

2.scharr算子

scharr算子只是一个加强版的sobel算子,他的核函数定义为    

                                                                            \begin{bmatrix} -3\0\3 \\ -10\0\10 \\ -3\0\3 \end{bmatrix}

其余的操作步骤与sobel完全相同,只是求梯度时调用的是cv2.Scharr(src,ddepth,dx,dy)函数。

3.拉普拉斯算子

拉普拉斯算子进行边缘检测的原理是查看中间值与周围像素值的差别,如果相差大则判断为边界。

G{x}=\begin{bmatrix} 0\ 1\0 \\ 1\ -4 \1\\ 0\1\ 0 \end{bmatrix}*\begin{bmatrix} P1 \ P2 \ P3 \\ P4\ P5\ P6 \\ P7\ P8\ P9 \end{bmatrix}可以得到元素P5的值为(P2+P4+P6+P8)-4*P5。

通过调用cv2.Laplacian(src,cv2.CV_64F)直接得到边缘图像。

result = cv2.Laplacian(img,cv2.CV_64F)

4.Canny边缘提取

canny边缘提取是非常经典的一种算法,它包括以下4个步骤:

  1. 高斯去噪
  2. 求sobel梯度,获得角度图
  3. 利用求出的梯度角度图,把各个梯度分别划分到水平,垂直,45°,-45°,四个方向上。然后把赋值图按所划分的四个方向,分别同邻近的两个点比较,若为最大值则保留,若不是,则变为0;这样就得到非最大值抑制图。
  4. 设置滞后阈值。有两个阈值,我们指定一个为maxval,一个为minval,如果像素值大于maxval则判断为边界,小于minval则判断为非边界点,在两者之间则判断周围是否有边界点,如果有,则也判断为边界点。

在opencv中我们通过简单的cv2.canny(img,threshold1,threshold2)来实现。

效果如下:

                            opencv+python入门之七(边缘提取之sobel、scharr、laplacian、canny算子等)_第2张图片

PS:跟前面介绍的方法混合使用效果更佳

 

 

你可能感兴趣的:(opencv+python)