《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法

本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的、不同方法的处理,以达到对图像进行去噪、锐化等一系列的操作。同时,希望观看本专栏的小伙伴可以理解到OpenCv进行图像处理的强大哦,如有转载,请注明出处(原文链接和作者署名),感谢各位小伙伴啦!

前文参考:
《OpenCv视觉之眼》Python图像处理一 :Opencv-python的简介及Python环境搭建
《OpenCv视觉之眼》Python图像处理二 :Opencv图像读取、显示、保存基本函数原型及使用
《OpenCv视觉之眼》Python图像处理三 :Opencv图像属性、ROI区域获取及通道处理
《OpenCv视觉之眼》Python图像处理四 :Opencv图像灰度处理的四种方法及原理
《OpenCv视觉之眼》Python图像处理五 :Opencv图像去噪处理之均值滤波、方框滤波、中值滤波和高斯滤波
《OpenCv视觉之眼》Python图像处理六 :Opencv图像傅里叶变换和傅里叶逆变换原理及实现
《OpenCv视觉之眼》Python图像处理七 :Opencv图像处理之高通滤波和低通滤波原理及构造
《OpenCv视觉之眼》Python图像处理八 :Opencv图像处理之图像阈值化处理原理及函数
《OpenCv视觉之眼》Python图像处理九 :Opencv图像形态学处理之图像腐蚀与膨胀原理及方法
《OpenCv视觉之眼》Python图像处理十 :Opencv图像形态学处理之开运算、闭运算和梯度运算原理及方法
《OpenCv视觉之眼》Python图像处理十一 :Opencv图像形态学处理之顶帽运算与黑帽运算

上次博客,我们介绍了图像形态学处理的最后一个章节,图像形态学黑帽与顶帽运算,到这里,图像形态学处理我们就暂告一个段落,而对于形态学的黑帽与顶帽运算,大家作为一个科普了解一下,因为针对一般图像而言,我们不会用到。

本次博客,我们将进行图像处理的下一个阶段的学习——图像轮廓提取;对于图像轮廓提取,是图像处理中的一个重要阶段,而对于图像轮廓提取也有很多的算法,本次博客主要讲解图像轮廓提取的Roberts算法、Prewitt算法、以及常用的Sobel算法,分析各种算法的优势和缺点,通过原理,自己编写对应的函数实现对该种算法的功能函数编写,一起来看吧!

[Python图像处理十二 ]:Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法

  • 一、Roberts算法
    • 1、Roberts算法原理
    • 2、Roberts算法构造
    • 3、OpenCV中Roberts算法库函数使用
  • 二、Prewitt算法
    • 1、Prewitt算法原理
    • 2、Prewitt算法构造
    • 3、OpenCV中Prewitt算法库函数使用
  • 三、Sobel算法
    • 1、Sobel算法原理
    • 2、Sobel算法构造
    • 3、OpenCV中Sobel算法库函数使用

图像轮廓提取(边缘提取)技术可以消除图像中的噪声,提取图像信息中用来表征图像的一些变量,为图像识别提供基础。通常使用灰度差分法对图像的边缘、轮廓进行处理,将其凸显。本次博客分别采用Robert算子、Prewitt算子和Sobel算子进行图像锐化边缘处理,了解原理是关键哦!

一、Roberts算法

1、Roberts算法原理

1)、Roberts算法简介
Roberts算法又称为交叉微分算法,它是基于交叉差分的梯度算法,通过局部差分计算检测边缘线条。常用来处理具有陡峭的低噪声图像,当图像边缘接近于正45度或负45度时,该算法处理效果更理想。
Roberts算子的模板分为水平方向和垂直方向,如下所示:
d x = [ − 1 0 0 1 ] , d y = [ 0 − 1 1 0 ] dx=\begin{bmatrix} -1 & 0 \\ 0 & 1 \\ \end{bmatrix} , dy=\begin{bmatrix} 0 & -1 \\ 1 & 0 \\ \end{bmatrix} dx=[1001],dy=[0110]
从其模板可以看出,Roberts算子能较好的增强正负45度的图像边缘。

2)、Roberts算法优缺点

  • 优点:Roberts算子能较好的增强正负45度的图像边缘
  • 缺点:对边缘的定位不太准确,提取的边缘线条较粗。

3)、Roberts算法计算原理
d x = f ( i + 1 , j + 1 ) − f ( i , j ) d y = f ( i , j + 1 ) − f ( i + 1 , j ) S = d x 2 + d y 2 d_x=f(i+1,j+1)-f(i,j)\\\\ d_y=f(i,j+1)-f(i+1,j)\\\\ S=\sqrt{d_x^2+d_y^2} dx=f(i+1,j+1)f(i,j)dy=f(i,j+1)f(i+1,j)S=dx2+dy2
以上计算原理就是我们自己构造Roberts算法原理功能函数的基础,通过以上计算原理,那么如何将计算公式与图像结合呢?如下所示:
d x = i m g [ i + 1 , j + 1 ] − i m g [ i , j ] d y = i m g [ i , j + 1 ] − i m g [ i + 1 , j ] d x 、 d y 分 别 表 示 图 像 水 平 方 向 和 竖 直 方 向 的 计 算 出 的 像 素 值 图 像 轮 廓 S [ i , j ] = d x 2 + d y 2 d_x=img[i+1,j+1]-img[i,j]\\\\ d_y=img[i,j+1]-img[i+1,j]\\\\ d_x、d_y分别表示图像水平方向和竖直方向的计算出的像素值\\\\ 图像轮廓S[i,j]=\sqrt{d_x^2+d_y^2} dx=img[i+1,j+1]img[i,j]dy=img[i,j+1]img[i+1,j]dxdyS[i,j]=dx2+dy2
在对公式转换为图像处理的公式之后,我们就可以构造Roberts算法的功能函数了

2、Roberts算法构造

1)、Roberts算法功能构造

'''
Roberts轮廓提取算法
'''
#通过原理,编写对应的Roberts图像轮廓提取算法
def Roberts(thresh1):
    #获取图像属性
    h,w=thresh1.shape[0:2]
    #定义空白图像,用于存放Roberts算法提取出来的轮廓图
    Roberts=np.zeros((h,w),dtype=thresh1.dtype)
    #对阈值化图像进行遍历,进行Roberts算法
    for i in range(h-1):
        for j in range(w-1):
            dx=int(thresh1[i+1,j+1])-int(thresh1[i,j])#水平方向计算公式
            dy=int(thresh1[i,j+1])-int(thresh1[i+1,j])#竖直方向计算公式
            Roberts[i,j]=np.sqrt(dx**2+dy**2)#水平方向与竖直方向结合和最终像素
    return Roberts

以上就是对Roberts算法函数的编写,通过传递阈值化后的图像进行轮廓提取,为什么要阈值化,因为这是图像轮廓提取的一般步骤

一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取

2)、读取图像进行对于处理,然后调用Roberts算法功能函数进行轮廓提取

import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Roberts算法函数进行图像轮廓提取
result=Roberts(thresh1)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
result=cv2.cvtColor(result,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'Roberts算法']  #标题
images = [img, result]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法_第1张图片

从上面可以看出,Roberts算法提取出来的轮廓图像轮廓边缘的线条是比较粗的,但大致轮廓却完美提取出来,但对于细节处理,由于边缘线较粗,会遮盖细节处,这个通过后面几种算法的对比可以看出来的!

3、OpenCV中Roberts算法库函数使用

在OpenCV官方的库中,也提供了Roberts算法库函数,调用OpenCV的filter2D()函数实现边缘提取。该函数主要是利用内核实现对图像的卷积运算,然后通过addWeighted()函数来进行x方向与y方向上的结合
1)、filter2D()函数原型:result=cv2.filter2D(thresh1, cv2.CV_16S, kernel)

  • thresh1:需要进行轮廓提取的图像
  • cv2.CV_16S:目标图深度
  • kernelx:卷积核,一个单通道浮点型矩阵

2)、addWeighted()函数原型:result=cv2.addWeighted(absX,alphax,absY, alphay,num)

  • absX:方向的处理结果
  • alphax:X方向上的权重
  • absY:Y方向的处理结果
  • alphay:Y方向上的权重
  • num:X与Y方向上求和后添加的偏移量,不能设置太大,否则容易溢出(总和超过255就算溢出)

3)、Roberts算法库函数的使用方法

'''
Roberts轮廓提取算法-OpenCV库函数的使用方法
'''
import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Roberts算法的OpenCV库函数进行图像轮廓提取
kernelx = np.array([[-1,0],[0,1]], dtype=int)
kernely = np.array([[0,-1],[1,0]], dtype=int)
x = cv2.filter2D(thresh1, cv2.CV_16S, kernelx)
y = cv2.filter2D(thresh1, cv2.CV_16S, kernely)
#转uint8 
absX = cv2.convertScaleAbs(x)      
absY = cv2.convertScaleAbs(y)    
Roberts = cv2.addWeighted(absX,0.5,absY,0.5,0)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
Roberts=cv2.cvtColor(Roberts,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'Roberts算法']  #标题
images = [img, Roberts]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法_第2张图片

二、Prewitt算法

1、Prewitt算法原理

1)、Prewitt算法简介
Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。Prewitt算法适合用来识别噪声较多、灰度渐变的图像;水平和竖直方向上的卷积模板如下所示:
d x = [ 1 0 − 1 1 0 − 1 1 0 − 1 ] , d y = [ − 1 − 1 − 1 0 0 0 1 1 1 ] dx=\begin{bmatrix} 1 & 0 & -1 \\ 1 & 0 & -1 \\1 & 0 & -1 \end{bmatrix} , dy=\begin{bmatrix} -1 & -1 & -1 \\ 0 & 0 & 0 \\1 & 1 & 1 \end{bmatrix} dx=111000111,dy=101101101
2)、Prewitt算法优缺点

  • 优点:Prewitt算子的边缘检测结果在水平方向和垂直方向均比Robert算子更加明显
  • 缺点:凡灰度新值大于或等于阈值的像素点都是边缘点。即选择适当的阈值T,若P(i,j)≥T,则(i,j)为边缘点,P(i,j)为边缘图像。这种判定是欠合理的,会造成边缘点的误判,因为许多噪声点的灰度值也很大,而且对于幅值较小的边缘点,其边缘反而丢失了。

3)、Prewitt算法计算原理
d x = ( f [ i − 1 , j − 1 ] + f [ i − 1 , j ] + f [ i − 1 , j + 1 ] ) − ( f [ i + 1 , j − 1 ] + f [ i + 1 , j ] + f [ i + 1 , j + 1 ] ) d y = ( [ ( i − 1 , j + 1 ] + f [ i , j + 1 ] + f [ i + 1 , j + 1 ] ) − ( f [ i − 1 , j − 1 ] + f [ i , j − 1 ] + f [ i + 1 , j − 1 ] ) d x 、 d y 分 别 表 示 图 像 水 平 方 向 和 竖 直 方 向 的 计 算 出 的 像 素 值 图 像 轮 廓 S [ i , j ] = d x 2 + d y 2 d_x=(f[i-1,j-1]+f[i-1,j]+f[i-1,j+1])-(f[i+1,j-1]+f[i+1,j]+f[i+1,j+1])\\\\ d_y=([(i-1,j+1]+f[i,j+1]+f[i+1,j+1])-(f[i-1,j-1]+f[i,j-1]+f[i+1,j-1])\\\\ d_x、d_y分别表示图像水平方向和竖直方向的计算出的像素值\\\\ 图像轮廓S[i,j]=\sqrt{d_x^2+d_y^2} dx=(f[i1,j1]+f[i1,j]+f[i1j+1])(f[i+1,j1]+f[i+1j]+f[i+1j+1])dy=([(i1,j+1]+f[i,j+1]+f[i+1j+1])(f[i1,j1]+f[i,j1]+f[i+1j1])dxdyS[i,j]=dx2+dy2
通过以上的计算公式,我们就可以进行Prewitt算法功能函数的构造了,继续往下看吧!

2、Prewitt算法构造

1)、Prewitt算法功能函数构造

'''
Prewitt轮廓提取算法
'''
#通过原理,编写对应的Roberts图像轮廓提取算法
def Prewitt(thresh1):
    #获取图像属性
    h,w=thresh1.shape[0:2]
    #定义空白图像,用于存放Prewitt算法提取出来的轮廓图
    Prewitt=np.zeros((h,w),dtype=thresh1.dtype)
    #对阈值化图像进行遍历,进行Roberts算法
    for i in range(h-1):
        for j in range(w-1):
            dx=(int(thresh1[i-1,j-1])+int(thresh1[i-1,j])+int(thresh1[i-1,j+1]))-(int(thresh1[i+1,j-1])+int(thresh1[i+1,j])+int(thresh1[i+1,j+1]))
            dy=(int(thresh1[i-1,j+1])+int(thresh1[i,j+1])+int(thresh1[i+1,j+1]))-(int(thresh1[i-1,j-1])+int(thresh1[i,j-1])+int(thresh1[i+1,j-1]))
            Prewitt[i,j]=np.sqrt(dx**2+dy**2)
    return Prewitt

2)、读取图像处理,然后调用Prewitt功能函数进行轮廓提取

import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Prewitt算法函数进行图像轮廓提取
result=Prewitt(thresh1)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
result=cv2.cvtColor(result,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'Prewitt算法']  #标题
images = [img, result]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法_第3张图片

通过这里可以看出,在对同一张图像进过相同处理之后,通过Prewitt算法提取的图像比通过Roberts算法算法提取的图像更加明显,但也将更多噪声误判为边缘点,这对图像轮廓提取是有一定影响的,这也是Prewitt算法的缺点

3、OpenCV中Prewitt算法库函数使用

同样的,OpenCV官方同样对Prewitt算法有对于的库函数,与Roberts算法算法的库函数一样,只是传递的卷积核不一样,有变化;通过Numpy定义模板,再调用OpenCV的filter2D()函数实现对图像的卷积运算,最终通过convertScaleAbs()和addWeighted()函数实现边缘提取,函数原型参考Roberts算法介绍的函数原型,是一样的!
1)、Prewitt算发库函数使用方法

'''
Prewitt轮廓提取算法-OpenCV库函数的使用方法
'''
import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Prewitt算法的OpenCV库函数进行图像轮廓提取
kernelx = np.array([[1,1,1],[0,0,0],[-1,-1,-1]],dtype=int)
kernely = np.array([[-1,0,1],[-1,0,1],[-1,0,1]],dtype=int)
x = cv2.filter2D(thresh1, cv2.CV_16S, kernelx)
y = cv2.filter2D(thresh1, cv2.CV_16S, kernely)
#转uint8 
absX = cv2.convertScaleAbs(x)      
absY = cv2.convertScaleAbs(y)    
Prewitt= cv2.addWeighted(absX,0.5,absY,0.5,0)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
Prewitt=cv2.cvtColor(Prewitt,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'Prewitt算法']  #标题
images = [img, Prewitt]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法_第4张图片

三、Sobel算法

1、Sobel算法原理

1)、Sobel算法简介
Sobel算法(索贝尔算子)是一种用于边缘检测的离散微分算子,它结合了高斯平滑和微分求导。该算子用于计算图像明暗程度近似值,根据图像边缘旁边明暗程度把该区域内超过某个数的特定点记为边缘。Sobel算子在Prewitt算子的基础上增加了权重的概念,认为相邻点的距离远近对当前像素点的影响是不同的,距离越近的像素点对应当前像素的影响越大,从而实现图像锐化并突出边缘轮廓。当对精度要求不是很高时,Sobel算子是一种较为常用的边缘检测方法,其卷积模板如下所示:
d x = [ 1 0 − 1 2 0 − 2 1 0 − 1 ] , d y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] dx=\begin{bmatrix} 1 & 0 & -1 \\ 2 & 0 & -2 \\1 & 0 & -1 \end{bmatrix} , dy=\begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\1 & 2 & 1 \end{bmatrix} dx=121000121,dy=101202101
2)、Sobel算法优缺点

  • 优点:Sobel算子的边缘定位更准确,会具有更多的抗噪性,不但产生较好的检测效果,而且对噪声具有平滑抑制作用;方法简单、处理速度快,并且所得的边缘光滑、连续
  • 缺点:得到的边缘较粗,且可能出现伪边缘

3)、Sobel算法计算原理
d x = ( f [ i − 1 , j − 1 ] + 2 f [ i − 1 , j ] + f [ i − 1 , j + 1 ] ) − ( f [ i + 1 , j − 1 ] + 2 f [ i + 1 , j ] + f [ i + 1 , j + 1 ] ) d y = ( f [ i − 1 , j + 1 ] + 2 f [ i , j + 1 ] + f [ i + 1 , j + 1 ] ) − ( f [ i − 1 , j − 1 ] + 2 f [ i , j − 1 ] + f [ i + 1 , j − 1 ] ) d x 、 d y 分 别 表 示 图 像 水 平 方 向 和 竖 直 方 向 的 计 算 出 的 像 素 值 图 像 轮 廓 S [ i , j ] = d x 2 + d y 2 d_x=(f[i-1,j-1]+2f[i-1,j]+f[i-1,j+1])-(f[i+1,j-1]+2f[i+1,j]+f[i+1,j+1])\\\\ d_y=(f[i-1,j+1]+2f[i,j+1]+f[i+1,j+1])-(f[i-1,j-1]+2f[i,j-1]+f[i+1,j-1])\\\\ d_x、d_y分别表示图像水平方向和竖直方向的计算出的像素值\\\\ 图像轮廓S[i,j]=\sqrt{d_x^2+d_y^2} dx=(f[i1,j1]+2f[i1,j]+f[i1j+1])(f[i+1,j1]+2f[i+1j]+f[i+1j+1])dy=(f[i1,j+1]+2f[i,j+1]+f[i+1j+1])(f[i1,j1]+2f[i,j1]+f[i+1j1])dxdyS[i,j]=dx2+dy2

2、Sobel算法构造

1)、Sobel算法功能函数构造

'''
Sobel轮廓提取算法
'''
#通过原理,编写对应的Roberts图像轮廓提取算法
def Sobel(thresh1):
    #获取图像属性
    h,w=thresh1.shape[0:2]
    #定义空白图像,用于存放Roberts算法提取出来的轮廓图
    Sobel=np.zeros((h,w),dtype=thresh1.dtype)
    #对阈值化图像进行遍历,进行Roberts算法
    for i in range(h-1):
        for j in range(w-1):
            dx=(int(thresh1[i-1,j-1])+2*int(thresh1[i-1,j])+int(thresh1[i-1,j+1]))-(int(thresh1[i+1,j-1])+2*int(thresh1[i+1,j])+int(thresh1[i+1,j+1]))
            dy=(int(thresh1[i-1,j+1])+2*int(thresh1[i,j+1])+int(thresh1[i+1,j+1]))-(int(thresh1[i-1,j-1])+2*int(thresh1[i,j-1])+int(thresh1[i+1,j-1]))
            Sobel[i,j]=np.sqrt(dx**2+dy**2)
    return Sobel

2)、读取图像并处理,调用Sobel算法进行图像轮廓提取

import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Sobel算法函数进行图像轮廓提取
result=Sobel(thresh1)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
result=cv2.cvtColor(result,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'Sobel算法']  #标题
images = [img, result]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法_第5张图片
Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息。因为Sobel算子结合了高斯平滑和微分求导(分化),因此结果会具有更多的抗噪性,当对精度要求不是很高时,Sobel算子是一种较为常用的边缘检测方法。

3、OpenCV中Sobel算法库函数使用

OpenCV中提供了专门的Soble算法的库函数,如下介绍
1)、函数原型:result=cv2.Sobel(img, ddepth, dx,dy,ksize)

  • img:需要轮廓提取的图像
  • ddepth:目标图像深度
  • dx:x方向上的差分阶数,取值1或 0
  • dy:y方向上的差分阶数,取值1或0
  • ksize:Sobel算子的大小,其值必须是正数和奇数

在进行Sobel算子处理之后,还需要调用convertScaleAbs()函数计算绝对值
2)、convertScaleAbs()函数原型:x=cv2.convertScaleAbs(x)

  • x:x或者y方向上的Sobel算法值

3)、OpenCV中Sobel算法库函数使用

'''
Sobel轮廓提取算法-OpenCV库函数的使用方法
'''
import cv2
import numpy as np
#np.set_printoptions(threshold=np.inf)  #打印数组中的全部内容
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
'''
一般来说,对图像轮廓提取都会经过如下步骤,灰度-滤波去噪-阈值化处理-(形态学处理,前面如果达标,这步骤可以省略)-轮廓提取
'''
#读取图像
img=cv2.imread("my.jpg")
#图像灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#图像高斯滤波去噪
blur=cv2.GaussianBlur(gray,(7,7),1,1)#核尺寸通过对图像的调节自行定义
#图像阈值化处理
ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY)  #二进制阈值化
#调用Sobel算法的OpenCV库函数进行图像轮廓提取
x = cv2.Sobel(thresh1, cv2.CV_16S, 1, 0) #对x求一阶导
y = cv2.Sobel(thresh1, cv2.CV_16S, 0, 1) #对y求一阶导
absX = cv2.convertScaleAbs(x)  #对x取绝对值,并将图像转换为8位图   
absY = cv2.convertScaleAbs(y)   #对y取绝对值,并将图像转换为8位图
Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
#对原图进行格式转换,方便matplotlib图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#对结果图进行格式转换,方便matplotlib图像显示
Sobel=cv2.cvtColor(Sobel,cv2.COLOR_BGR2RGB)
#图像显示
titles = ['原图', 'Sobel算法']  #标题
images = [img, Sobel]   #图像对比显示
for i in range(2):
    plt.subplot(1,2,i+1), plt.imshow(images[i])  
    plt.title(titles[i])    
    plt.axis('off')#关闭坐标轴  设置为on则表示开启坐标轴
plt.show()#显示图像

《OpenCv视觉之眼》Python图像处理十二 :Opencv图像轮廓提取之基于一阶导数的Roberts算法、Prewitt算法及Sobel算法_第6张图片
可以看出,Sobel算法的边缘定位更准确,相比于之前的Roberts算法和Prewitt算法,Sobel算法对边缘更加明显,抗噪能力强!

边缘检测算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此需要采用滤波器来过滤噪声,并调用图像增强或阈值化算法进行处理,最后再进行边缘检测。

以上就是本次博客的全部内容,遇到问题的小伙伴记得留言评论,学长看到会为大家进行解答的,这个学长不太冷!

十二星座的光芒从不停歇,它们穿梭过你的生命,你永远在它们的共同辉映下,原本你以为你属于其中之一,其实这一生,你都在缓缓经历着所有星辰的痕迹,有深有浅,却不偏不倚。只是它们出现在你生命的不同阶段而已——十二星座的爱情

陈一月的又一天编程岁月^ _ ^

你可能感兴趣的:(Opencv视觉之眼)