本文共享自华为云社区《[Python图画处理] 十七.图画锐化与边际检测之Roberts算子、Prewitt算子、Sobel算子和Laplacian算》,作者: eastmount 。
因为搜集图画数据的器材或传输数图画的通道的存在一些质量缺陷,文物图画时刻久远,或者受一些其他外界因素、动态不稳定抓取图画的影响,使得图画存在含糊和有噪声的状况,然后影响到图画识别作业的开展。这时需求开展图画锐化和边际检测处理,加强原图画的高频部分,锐化杰出图画的边际细节,改善图画的对比度,使含糊的图画变得更明晰。
图画锐化和边际提取技能能够消除图画中的噪声,提取图画信息中用来表征图画的一些变量,为图画识别供给根底。一般运用灰度差分法对图画的边际、概括进行处理,将其凸显。本文分别选用Laplacian算子、Robert算子、Prewitt算子和Sobel算子进行图画锐化边际处理实验。本文首要讲解灰度线性改换,根底性知识期望对您有所协助。
- 一.Roberts算子
- 二.Prewitt算子
- 三.Sobel算子
- 四.Laplacian算子
- 五.总结代码
该系列在github一切源代码:
- github.com/eastmountyx…
一.Roberts算子
Roberts算子又称为穿插微分算法,它是根据穿插差分的梯度算法,经过局部差分核算检测边际线条。常用来处理具有峻峭的低噪声图画,当图画边际接近于正45度或负45度时,该算法处理作用更理想。其缺陷是对边际的定位不太准确,提取的边际线条较粗。
Roberts算子的模板分为水平方向和笔直方向,如公式(11.7)所示,从其模板能够看出,Roberts算子能较好的增强正负45度的图画边际。
详细核算公式如下所示:(PS-下图参阅自己的书和论文)
在Python中,Roberts算子首要经过Numpy界说模板,再调用OpenCV的filter2D()函数完成边际提取。该函数首要是使用内核完成对图画的卷积运算,其函数原型如下所示:
dst = filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
- src表明输入图画
- dst表明输出的边际图,其巨细和通道数与输入图画相同
- ddepth表明方针图画所需的深度
- kernel表明卷积核,一个单通道浮点型矩阵
- anchor表明内核的基准点,其默许值为(-1,-1),坐落中心方位
- delta表明在贮存方针图画前可选的添加到像素的值,默许值为0
- borderType表明边框形式
Python完成代码如下所示:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图画
img = cv2.imread('lena.png')
lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#灰度化处理图画
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Roberts算子
kernelx = np.array([[-1,0],[0,1]], dtype=int)
kernely = np.array([[0,-1],[1,0]], dtype=int)
x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
#转uint8
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Roberts = cv2.addWeighted(absX,0.5,absY,0.5,0)
#用来正常显现中文标签
plt.rcParams['font.sans-serif']=['SimHei']
#显现图形
titles = [u'原始图画', u'Roberts算子']
images = [lenna_img, Roberts]
for i in xrange(2):
plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
运转成果如下图所示:
二.Prewitt算子
Prewitt是一种图画边际检测的微分算子,其原理是使用特定区域内像素灰度值产生的差分完成边际检测。因为Prewitt算子选用33模板对区域内的像素值进行核算,而Robert算子的模板为22,故Prewitt算子的边际检测成果在水平方向和笔直方向均比Robert算子愈加显着。Prewitt算子合适用来识别噪声较多、灰度突变的图画,其核算公式如下所示。
在Python中,Prewitt算子的完成进程与Roberts算子比较类似。经过Numpy界说模板,再调用OpenCV的filter2D()函数完成对图画的卷积运算,终究经过convertScaleAbs()和addWeighted()函数完成边际提取,代码如下所示:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图画
img = cv2.imread('lena.png')
lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#灰度化处理图画
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Prewitt算子
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(grayImage, cv2.CV_16S, kernelx)
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
#转uint8
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Prewitt = cv2.addWeighted(absX,0.5,absY,0.5,0)
#用来正常显现中文标签
plt.rcParams['font.sans-serif']=['SimHei']
#显现图形
titles = [u'原始图画', u'Prewitt算子']
images = [lenna_img, Prewitt]
for i in xrange(2):
plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
输出成果如下图所示,左边为原始图画,右边为Prewitt算子图画锐化提取的边际概括,其作用图的边际检测成果在水平方向和笔直方向均比Robert算子愈加显着。
三.Sobel算子
Sobel算子是一种用于边际检测的离散微分算子,它结合了高斯滑润和微分求导。该算子用于核算图画明暗程度近似值,依据图画边际周围明暗程度把该区域内超过某个数的特定点记为边际。Sobel算子在Prewitt算子的根底上增加了权重的概念,以为相邻点的距离远近对当时像素点的影响是不同的,距离越近的像素点对应当时像素的影响越大,然后完成图画锐化并杰出边际概括。
Sobel算子的边际定位更准确,常用于噪声较多、灰度突变的图画。其算法模板如公式所示,其间dx表明水平方向,dy表明笔直方向。
Sobel算子依据像素点上下、左右邻点灰度加权差,在边际处到达极值这一现象检测边际。对噪声具有滑润作用,供给较为准确的边际方向信息。因为Sobel算子结合了高斯滑润和微分求导(分化),因此成果会具有更多的抗噪性,当对精度要求不是很高时,Sobel算子是一种较为常用的边际检测方法。
dst = Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
- src表明输入图画
- dst表明输出的边际图,其巨细和通道数与输入图画相同
- ddepth表明方针图画所需的深度,针对不同的输入图画,输出方针图画有不同的深度
- dx表明x方向上的差分阶数,取值1或 0
- dy表明y方向上的差分阶数,取值1或0
- ksize表明Sobel算子的巨细,其值有必要是正数和奇数
- scale表明缩放导数的比例常数,默许状况下没有伸缩系数
- delta表明将成果存入方针图画之前,添加到成果中的可选增量值
- borderType表明边框形式,更多详细信息查阅BorderTypes
留意,在进行Sobel算子处理之后,还需求调用convertScaleAbs()函数核算绝对值,并将图画转换为8位图进行显现。其算法原型如下:
dst = convertScaleAbs(src[, dst[, alpha[, beta]]])
- src表明原数组
- dst表明输出数组,深度为8位
- alpha表明比例因子
- beta表明原数组元素按比例缩放后添加的值
Sobel算子的完成代码如下所示:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图画
img = cv2.imread('lena.png')
lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#灰度化处理图画
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#Sobel算子
x = cv2.Sobel(grayImage, cv2.CV_16S, 1, 0) #对x求一阶导
y = cv2.Sobel(grayImage, cv2.CV_16S, 0, 1) #对y求一阶导
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
#用来正常显现中文标签
plt.rcParams['font.sans-serif']=['SimHei']
#显现图形
titles = [u'原始图画', u'Sobel算子']
images = [lenna_img, Sobel]
for i in xrange(2):
plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
终究输出成果如下图所示:
四.Laplacian算子
拉普拉斯(Laplacian)算子是n维欧几里德空间中的一个二阶微分算子,常用于图画增强范畴和边际提取。它经过灰度差分核算邻域内的像素,基本流程是:判别图画中心像素灰度值与它周围其他像素的灰度值,假如中心像素的灰度更高,则提高中心像素的灰度;反之降低中心像素的灰度,然后完成图画锐化操作。在算法完成进程中,Laplacian算子经过对邻域中心像素的四方向或八方向求梯度,再将梯度相加起来判别中心像素灰度与邻域内其他像素灰度的关系,最终经过梯度运算的成果对像素灰度进行调整。
Laplacian算子分为四邻域和八邻域,四邻域是对邻域中心像素的四方向求梯度,八邻域是对八方向求梯度。其间,四邻域模板如公式所示:
经过模板能够发现,当邻域内像素灰度相一起,模板的卷积运算成果为0;当中心像素灰度高于邻域内其他像素的均匀灰度时,模板的卷积运算成果为正数;当中心像素的灰度低于邻域内其他像素的均匀灰度时,模板的卷积为负数。对卷积运算的成果用恰当的虚弱因子处理并加在原中心像素上,就能够完成图画的锐化处理。
Laplacian算子的八邻域模板如下:
Python和OpenCV将Laplacian算子封装在Laplacian()函数中,其函数原型如下所示:
dst = Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
- src表明输入图画
- dst表明输出的边际图,其巨细和通道数与输入图画相同
- ddepth表明方针图画所需的深度
- ksize表明用于核算二阶导数的滤波器的孔径巨细,其值有必要是正数和奇数,且默许值为1,更多详细信息查阅getDerivKernels
- scale表明核算拉普拉斯算子值的可选比例因子。默许值为1,更多详细信息查阅getDerivKernels
- delta表明将成果存入方针图画之前,添加到成果中的可选增量值,默许值为0
- borderType表明边框形式,更多详细信息查阅BorderTypes
留意,Laplacian算子其实首要是使用Sobel算子的运算,经过加上Sobel算子运算出的图画x方向和y方向上的导数,得到输入图画的图画锐化成果。一起,在进行Laplacian算子处理之后,还需求调用convertScaleAbs()函数核算绝对值,并将图画转换为8位图进行显现。
当ksize=1时,Laplacian()函数选用33的孔径(四邻域模板)进行改换处理。下面的代码是选用ksize=3的Laplacian算子进行图画锐化处理,其代码如下:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图画
img = cv2.imread('lena.png')
lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#灰度化处理图画
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#拉普拉斯算法
dst = cv2.Laplacian(grayImage, cv2.CV_16S, ksize = 3)
Laplacian = cv2.convertScaleAbs(dst)
#用来正常显现中文标签
plt.rcParams['font.sans-serif']=['SimHei']
#显现图形
titles = [u'原始图画', u'Laplacian算子']
images = [lenna_img, Laplacian]
for i in xrange(2):
plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
终究输出成果如下图所示:
五.总结代码
边际检测算法首要是根据图画强度的一阶和二阶导数,但导数一般对噪声很灵敏,因此需求选用滤波器来过滤噪声,并调用图画增强或阈值化算法进行处理,最终再进行边际检测。下面是选用高斯滤波去噪和阈值化处理之后,再进行边际检测的进程,并对比了四种常见的边际提取算法。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图画
img = cv2.imread('lena.png')
lenna_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#灰度化处理图画
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#高斯滤波
gaussianBlur = cv2.GaussianBlur(grayImage, (3,3), 0)
#阈值处理
ret, binary = cv2.threshold(gaussianBlur, 127, 255, cv2.THRESH_BINARY)
#Roberts算子
kernelx = np.array([[-1,0],[0,1]], dtype=int)
kernely = np.array([[0,-1],[1,0]], dtype=int)
x = cv2.filter2D(binary, cv2.CV_16S, kernelx)
y = cv2.filter2D(binary, cv2.CV_16S, kernely)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
#Prewitt算子
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(binary, cv2.CV_16S, kernelx)
y = cv2.filter2D(binary, cv2.CV_16S, kernely)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Prewitt = cv2.addWeighted(absX,0.5,absY,0.5,0)
#Sobel算子
x = cv2.Sobel(binary, cv2.CV_16S, 1, 0)
y = cv2.Sobel(binary, cv2.CV_16S, 0, 1)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
#拉普拉斯算法
dst = cv2.Laplacian(binary, cv2.CV_16S, ksize = 3)
Laplacian = cv2.convertScaleAbs(dst)
#作用图
titles = ['Source Image', 'Binary Image', 'Roberts Image',
'Prewitt Image','Sobel Image', 'Laplacian Image']
images = [lenna_img, binary, Roberts, Prewitt, Sobel, Laplacian]
for i in np.arange(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
输出成果如图所示。其间,Laplacian算子对噪声比较灵敏,因为其算法可能会出现双像素边界,常用来判别边际像素坐落图画的明区或暗区,很少用于边际检测;Robert算子对峻峭的低噪声图画作用较好,尤其是边际正负45度较多的图画,但定位准确率较差;Prewitt算子对灰度突变的图画边际提取作用较好,而没有考虑相邻点的距离远近对当时像素点的影响;Sobel算子考虑了综合因素,对噪声较多的图画处理作用更好。
参阅文献:
- 杨秀璋等. 根据苗族服饰的图画锐化和边际提取技能研究[J]. 现代核算机,2018(10).
- 《数字图画处理》(第3版),冈萨雷斯著,阮秋琦译,电子工业出版社,2013年.
- 《数字图画处理学》(第3版),阮秋琦,电子工业出版社,2008年,北京.
- 《OpenCV3编程入门》,毛星云,冷雪飞,电子工业出版社,2015.
- [数字图画处理] 七.MFC图画增强之图画普通滑润、高斯滑润、Laplacian、Sobel、Prewitt锐化详解
点击关注,第一时刻了解华为云新鲜技能~