边缘检测的目的:标识出数字图像中亮度变化明显的点。
边缘检测可以按照原理被分为两类,第一类是基于查找的一类(通过寻找图像一阶导数中的最大最小值来检测边界)第二类是基于零穿越的一类(寻找图像二阶导数的零点)。经常有人将锐化和边缘检测弄混,找到有差异的相邻像素是边缘检测,增加有差异的像素的对比度是图像锐化。
一阶导数为基础的边缘检测有sobel算子,prewitt算子,robert算子
二阶导数为基础的边缘检测有LOG算子;
下面先介绍robel算子,robel算子是用卷积的方法以差分的形式近似计算梯度。算子公式如下:
对于中的P5来说,要求其x方向上的梯度秩序与dx卷积即可,即同理可得。
具体处理的过程是:1.对图像灰度化处理2.使用filter2D函数对图像求梯度,3.将x方向上的梯度和y方向上的梯度求绝对值(convertscaleAbs函数)后将两个方向上的绝对值按照加权值进行相加(addweighted函数)4.最后显示图像。
prewitt算子和robel算子原理差不多,但又区别的是卷积核不同。prewitt算子的卷积核是:
,
sobel算子是利用像素上下左右邻域的灰度加权算法,根据在边缘点处到达极值这一原理进行边缘检测。其大致步骤为1.提取x方向的边缘,x方向上的边缘检测算子为
2.提取y方向上的边缘,y方向上的边缘检测算子为
3.综合两个方向的边缘信息(求两个方向上像素的绝对值平方和)。
LOG算子 也就是高斯拉普拉斯函数(laplace of gaussian function)
log算子边缘检测的过程如下:1.首先对图像做高斯滤波2.求其拉普拉斯二阶导,即图像与laplacian of the gaussian function进行滤波运算3.最后通过检测滤波的零交叉可以获得图像的边缘。
常用的5*5版本的高斯拉普拉斯算子(其实就是差分系数)如图所示。
import cv2 as cv
import sys
import numpy as np
np.set_printoptions(threshold=sys.maxsize)
import matplotlib.pyplot as plt
doc=open('out.txt','w')
#读取图像
img=cv.imread("C:/Users/wangyiyuan/Desktop/20200201172603_hocyy.jpg")
rgb_img=cv.cvtColor(img,cv.COLOR_BGR2RGB)
#灰度化图像
grayImage=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
##################################################robert算子
print("原图像矩阵")
#######robert算子
kernelx=np.array([[-1,0],[0,1]], dtype=int)
kernely=np.array([[0,-1],[1,0]],dtype=int)
x=cv.filter2D(grayImage,cv.CV_16S,kernelx)
y=cv.filter2D(grayImage,cv.CV_16S,kernely)
print(x,file=doc)
#转unit8,图像融合
absX=cv.convertScaleAbs(x)
absY=cv.convertScaleAbs(y)
Roberts=cv.addWeighted(absX,0.5,absY,0.5,0)
#显示图形
titles=['src','robert operator']
image=[rgb_img,Roberts]
for i in range(2):
plt.subplot(1,2,i+1),plt.imshow(image[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
##############################################################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=cv.filter2D(grayImage,cv.CV_16S,kernelx)
y=cv.filter2D(grayImage,cv.CV_16S,kernely)
print(x,file=doc)
#转unit8,图像融合
absX=cv.convertScaleAbs(x)
absY=cv.convertScaleAbs(y)
Roberts=cv.addWeighted(absX,0.5,absY,0.5,0)
#显示图形
titles=['src','prewitt operator']
image=[rgb_img,Roberts]
for i in range(2):
plt.subplot(1,2,i+1),plt.imshow(image[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
######################################################################log算子
gaussian=cv.GaussianBlur(grayImage,(3,3),0)
dst=cv.Laplacian(gaussian,cv.CV_16S,ksize=3)
log=cv.convertScaleAbs(dst)
plt.rcParams['font.sans-serif']=['SimHei']
titles=['原始图像','LOG算子']
image=[rgb_img,log]
for i in range(2):
plt.subplot(1,2,i+1),plt.imshow(image[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
##############################################################sobel算子
x=cv.Sobel(grayImage,cv.CV_16S,1,0)
y=cv.Sobel(grayImage,cv.CV_16S,0,1)
absX=cv.convertScaleAbs(x)
absY=cv.convertScaleAbs(y)
sobel=cv.addWeighted(absX,0.5,absY,0.5,0)
plt.rcParams['font.sans-serif']=['SimHei']
titles=['原始图像','sobel算子']
image=[rgb_img,sobel]
for i in range(2):
plt.subplot(1,2,i+1),plt.imshow(image[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
结果图如下