目录
一、Sobel
1、理论基础
2、Sobel算子函数及使用
(1)Sobel算子
(2)代码实例
二、Scharr
三、Sobel和Scharr比较
四、Laphlacian
五、Canny边缘检测
1、原理
2、代码实例
p5点处的水平方向梯度计算
p5点处竖直方向的梯度
图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:
但是有时候,计算sqrt(Gx2+Gy2)不太好算,故我们做一个简化:
# encoding: utf-8
import cv2
import matplotlib.pyplot as plt
import math
import copy
import numpy as np
def show_img(name="test",img=None):
plt.figure()
plt.imshow(img)
plt.title(name)
plt.show()
path = r"lena.jpg"
img = cv2.imread(path)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 1
#计算 深度-1,x方向梯度 1,即目标图像和原始图像都是256色域的图像,y方向梯度同理
# 出现问题:会被截断,导致计算不出图像左侧的边界,
soble_x1 = cv2.Sobel(gray,-1,1,0)
# show_img(img=soble_x1)
# 2
# 解决1中问题,y方向梯度同理
soble_x2 = cv2.Sobel(gray,cv2.CV_64F,1,0)
soble_x2 = cv2.convertScaleAbs(soble_x2)
# show_img(img=soble_x2)
# 3
#同时计算x 和y 方向梯度(边界),若同时计算 两个方向梯度边界,这种方式比较好
soble_x3 = cv2.Sobel(gray,cv2.CV_64F,1,0)
soble_y3 = cv2.Sobel(gray,cv2.CV_64F,0,1)
soble_x3 = cv2.convertScaleAbs(soble_x3)
soble_y3 = cv2.convertScaleAbs(soble_y3)
soble_xy3 = cv2.addWeighted(soble_x3, 0.5, soble_y3, 0.5, 0)
# show_img(img=soble_xy)
# 4
#同时计算 x 和 y 方向梯度,但是这种方式计算出的结果不好
#出现问题:结果不好,最好使用 3 中的方式
soble_xy4 = cv2.Sobel(gray,cv2.CV_64F,1,1)
soble_xy4 = cv2.convertScaleAbs(soble_xy4)
show_img(img=soble_xy4)
sobel算子不怎么用,一般scharr算子运用的比较多
# encoding: utf-8
import cv2
import matplotlib.pyplot as plt
import math
import copy
import numpy as np
def show_img(name="test",img=None):
plt.figure()
plt.imshow(img)
plt.title(name)
plt.show()
path = r"lena.jpg"
img = cv2.imread(path)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 1
#计算 深度-1,x方向梯度 1,即目标图像和原始图像都是256色域的图像,y方向梯度同理
# 出现问题:会被截断,导致计算不出图像左侧的边界,
scharr_x1 = cv2.Scharr(gray,-1,1,0)
# show_img(img=scharr_x1)
# 2
# 解决1中问题,y方向梯度同理
scharr_x2 = cv2.Scharr(gray,cv2.CV_64F,1,0)
scharr_x2 = cv2.convertScaleAbs(scharr_x2)
# show_img(img=scharr_x2)
# 3
#同时计算x 和y 方向梯度(边界),若同时计算 两个方向梯度边界,这种方式比较好
scharr_x3 = cv2.Scharr(gray,cv2.CV_64F,1,0)
scharr_y3 = cv2.Scharr(gray,cv2.CV_64F,0,1)
scharr_x3 = cv2.convertScaleAbs(scharr_x3)
scharr_y3 = cv2.convertScaleAbs(scharr_y3)
scharr_xy3 = cv2.addWeighted(scharr_x3, 0.5, scharr_y3, 0.5, 0)
show_img(img=scharr_xy3)
# 4
#同时计算 x 和 y 方向梯度,但是这种方式计算出的结果不好
#出现问题:报错,无法执行,无法通过编译器编译
scharr_xy4 = cv2.Scharr(gray,cv2.CV_64F,1,1)#
scharr_xy4 = cv2.convertScaleAbs(scharr_xy4)
# show_img(img=scharr_xy4)
print("===========可以使用Sobel计算Scharr梯度,即通过调节Soble最后参数达到Scharr的效果=============")
# 调节最后一个参数,-1表示使用和Scharr算子相同的算法计算
scharr_x5 = cv2.Sobel(gray,cv2.CV_64F,1,0,-1)
scharr_y5 = cv2.Sobel(gray,cv2.CV_64F,0,1,-1)
scharr_x5 = cv2.convertScaleAbs(scharr_x5)
scharr_y5 = cv2.convertScaleAbs(scharr_y5)
kernel大小一样,故计算量一样。
scharr算子临近像素的权重更大,故精确度更高。
对比两种算子的处理效果。发现scharr算子能计算出更小的梯度变化
拉普拉斯算子可以使用二阶导数的形式定义,可假设其离散实现类似于二阶Sobel导数,事实上,OpenCV在计算拉普拉斯算子时直接调用Sobel 算子。
Laplacian算子:图像中的边缘区域,像素值会发生“跳跃”,对这些像素求导,在其一阶导数在边缘位置为极值,这就是Sobel算子使用的原理——极值处就是边缘。
每个求导数的方法都是使用Sobel求导方法,如果 ksize=1,那么会使用下面核函数进行滤波.
这里只是处理单通道的灰度图像,彩色的三通道的图像同理。
# encoding: utf-8
import cv2
import matplotlib.pyplot as plt
import math
import copy
import numpy as np
def show_img(name="test",img=None):
plt.figure()
plt.imshow(img)
plt.title(name)
plt.show()
path = r"lena.jpg"
img = cv2.imread(path)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 这里只是处理单通道的灰度图像,彩色的三通道的图像同理。
lablacian = cv2.Laplacian(img,cv2.CV_64F)
lablacian = cv2.convertScaleAbs(lablacian)
show_img(img=lablacian)
参考: Canny算子原理
Canny边缘检测算法可以分为以下5个步骤:
1) 使用高斯滤波器,以平滑图像,滤除噪声。
2) 计算图像中每个像素点的梯度强度和方向。
3) 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
4) 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
5) 通过抑制孤立的弱边缘最终完成边缘检测。
(1)图像平滑、去燥
原理可以参看: https://mp.csdn.net/postedit/103102498
(2)梯度
对图像平滑后的图像使用 Sobel 算子计算图像梯度和方向
(3)非极大抑制
(4)双阈值检测
cv2.Canny(image, # 输入原图(必须为单通道图)
threshold1,
threshold2, # 较大的阈值2用于检测图像中明显的边缘
[, edges[,
apertureSize[, # apertureSize:Sobel算子的大小
L2gradient ]]]) # 参数(布尔值):
true: 使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放),
false:使用L1范数(直接将两个方向导数的绝对值相加)。
# encoding: utf-8
import cv2
import matplotlib.pyplot as plt
import math
import copy
import numpy as np
def show_img(name="test",img=None):
plt.figure()
plt.imshow(img)
plt.title(name)
plt.show()
path = r"lena.jpg"
img = cv2.imread(path)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
canny_1 = cv2.Canny(gray,100,200)
canny_2 = cv2.Canny(gray,64,128)
show_img(img=canny_1)
show_img(img=canny_2)