利用sobel算子进行边缘检测

1,214 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言:
本文章中的一部分代码写得比较仓促,虽然比原来写的结构性更强,但仍有缺陷,下一篇中的代码经过了稍微修改。

原理:
Sobel算子是整像素图像边缘检测中最重要的算子之一,该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像 作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘 检测的图像,其公式如下:

Gx=[10+120+210+1]AGy=[121000+1+2+1]AGx= \begin{gathered} \begin{bmatrix} -1 & 0 & +1 \\ -2 & 0 & +2 \\ -1 & 0 & +1 \\ \end{bmatrix} \end{gathered} *A \quad \quad Gy= \begin{gathered} \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ +1 & +2 & + 1 \\ \end{bmatrix} \end{gathered} *A

图像中每一个像素的横向及纵向梯度近似值可用以下公式结合,来计算梯度的大小:

G=Gx2+Gy2G=\sqrt{Gx^2+Gy^2}

以下公式用于计算梯度方向:

Θ=arctan(GyGx)\Theta=\arctan(\frac{Gy}{Gx})

用sobel算子进行卷积的方法: 将图像转化为矩阵后,首先设计卷积核,多数情况下是3*3的矩阵,这里把sobel算子作为卷积核,如下,依次在图像中移动卷积核:

20200610115743901.png

把被卷积核覆盖的区域中的对应元素相乘,然后9个值相加的和作为一个像素的值,赋给输出的矩阵:

20200610115812159.jpg

但这样做会导致图片变小,因此有一种做法就是在图片矩阵的四周加上0再运算,经过这样处理的图片与原图大小就可以保持一样了:

20200610120719825.png

举例:
这里有一张小狗的图片,大小为1024px*991px。

20200610115840450.jpg

尝试对此图进行边缘检测,为了节省工作量,已经事先将该图格式转换为24位bmp位图。

1.首先读取图片信息:

def oct1(a):
    return a[0]+a[1]*256+a[2]*4096+a[3]*65536

#这里狗图的储存位置为‘e:\images\12.bmp’
fp=open('e:\\images\\12.bm','rb')

#使用二进制写的方式新建生成的图片,路径为'e:\images\gaus_sobal12.bmp'
fg_gs=open('e:\\images\\gaus_sobal12.bmp')
#读取位图的前54字节文件头,写入gaus_sobe112.bmp。
fg_gs.write(fp.read(54))
#使读指针定位到文件起始处向后偏移18字节
fp.seek(18,0)
#在24位bmp位图中,第19-22这四个字节储荐了图片的宽度,第23-26这四字节储存了图片的高度
#读取图片大小,oct1()可以将4字节的16进制转化为10进制
width=oct1(fp.read(4))
height=oct1(fp.read(4))

上面的代码可以读出图片大小,同时为输出图像写入了24位bmp位图的文件头。 执行后,width=1024,height=991

2.把图片的每个像素作为一个元素储存在1024*991的矩阵中,便于计算:

2020061012003376.png

20200610120039824.png

运算结果:

20200610120053500.png

3.在2中我们获得了图像的矩阵,然后给周围加上0:

20200610120103278.png

输出结果:

20200610120120846.png

4.通常边缘检测前会使用高斯滤波对图片进行处理,高斯滤波的作用就是消除图片中的噪点,是图片更平滑。下面是公式,其中是sigma需要自己设置值。

20200610120144135.png

20200610120147664.png

用这些代码可以将图片进行平滑处理,sigma用来设置平滑的程度。
Sigma=1时:(左为原图,右为经过平滑处理后的图片,没有考虑颜色,导致图片成了黑白的,后者看着会比前者模糊,这是高斯滤波后的正常现象)

image.png

5.进行高斯滤波处理后就可以使用sobel算子了,使用原理与4一样:

20200610120402742.png

左为经过高斯滤波后的图像,右为将该图像边缘检测后的图像,可以明显的看出小狗的轮廓,这就是边缘检测。

image.png