七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny

目录

一、Sobel

1、理论基础

2、Sobel算子函数及使用

(1)Sobel算子

(2)代码实例

二、Scharr

三、Sobel和Scharr比较

四、Laphlacian

五、Canny边缘检测

1、原理

2、代码实例


一、Sobel

1、理论基础

p5点处的水平方向梯度计算

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第1张图片

p5点处竖直方向的梯度

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第2张图片

图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第3张图片

但是有时候,计算sqrt(Gx2+Gy2)不太好算,故我们做一个简化:

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第4张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第5张图片

2、Sobel算子函数及使用

(1)Sobel算子

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第6张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第7张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第8张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第9张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第10张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第11张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第12张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第13张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第14张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第15张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第16张图片

(2)代码实例

# 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)

二、Scharr

sobel算子不怎么用,一般scharr算子运用的比较多

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第17张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第18张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第19张图片

# 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)

三、Sobel和Scharr比较

  • kernel大小一样,故计算量一样。

  • scharr算子临近像素的权重更大,故精确度更高。

  • 对比两种算子的处理效果。发现scharr算子能计算出更小的梯度变化

四、Laphlacian

拉普拉斯算子可以使用二阶导数的形式定义,可假设其离散实现类似于二阶Sobel导数,事实上,OpenCV在计算拉普拉斯算子时直接调用Sobel 算子。

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第20张图片

Laplacian算子:图像中的边缘区域,像素值会发生“跳跃”,对这些像素求导,在其一阶导数在边缘位置为极值,这就是Sobel算子使用的原理——极值处就是边缘。

每个求导数的方法都是使用Sobel求导方法,如果 ksize=1,那么会使用下面核函数进行滤波.

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第21张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第22张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第23张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第24张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第25张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第26张图片

这里只是处理单通道的灰度图像,彩色的三通道的图像同理。

# 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边缘检测

1、原理

参考: Canny算子原理

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第27张图片

Canny边缘检测算法可以分为以下5个步骤:

1)        使用高斯滤波器,以平滑图像,滤除噪声。

2)        计算图像中每个像素点的梯度强度和方向。

3)        应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。

4)        应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。

5)        通过抑制孤立的弱边缘最终完成边缘检测。

(1)图像平滑、去燥

原理可以参看: https://mp.csdn.net/postedit/103102498

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第28张图片

(2)梯度

对图像平滑后的图像使用 Sobel 算子计算图像梯度和方向

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第29张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第30张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第31张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第32张图片

(3)非极大抑制

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第33张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第34张图片

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第35张图片

(4)双阈值检测

七、图像边缘检测之 Sobel、Scharr、拉普拉斯算子、Canny_第36张图片

2、代码实例

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)

 

你可能感兴趣的:(#,OpenCV图像处理)