前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用Python进行边缘检测

用Python进行边缘检测

作者头像
mythsman
发布2022-11-14 14:38:21
1.5K0
发布2022-11-14 14:38:21
举报
文章被收录于专栏:mythsman的个人博客

边缘检测在图像的检测中是经常会用到的。图片的边缘会包含大量的信息,因此在图像的分割、识别、分析中通常可以取边缘作为图像特征。边缘检测最经典的应用就是图像的锐化了,想必大家都用过。

为了进行边缘检测,我们通常会用到以下的一些算子,即一阶算子(梯度算子)和二阶算子(拉普拉斯算子)。

拉普拉斯算子(Laplacian Operator)

拉普拉斯算子其实就是二阶微分算子,具有各向同性。他也会增强噪声,因此在使用拉普拉斯算子之前需要进行平滑处理。他的主要用处其实是判断一个像素是处于图像的亮区还是暗区。

拉普拉斯算子定义式:

\begin{aligned}\nabla^2 f(x,y)&=\frac{\partial^2 f}{\partial x}+\frac{\partial^2 f}{\partial y}\\&=f(x+1,y)+f(x-1,y)+f(x,y+1)+f(x,y-1)-4f(x,y)\end{aligned}

常用模板公式:(1)\begin{bmatrix}0&1&0\\1&-4&1\\0&1&0\end{bmatrix}\begin{bmatrix}1&1&1\\1&-8&1\\1&1&1\end{bmatrix}

拉普拉斯模板有多个变种,上面是常用的两个,对于每一个像素,我们把他作为模板的中心元素,套用公式进行更新。需要注意的是,与梯度算子不同,他是各向同性的,因此不需要G_xG_y两个模板,也就不能区分边缘的方向了。

还有一个常用的高斯-拉普拉斯算子(Gauss-Laplacian Operator),将平滑滤波器和拉普拉斯边缘检测算子结合起来的:

高斯-拉普拉斯算子模板:\begin{bmatrix}-2&-4&-4&-4&-2\\-4&0&8&0&-4\\-4&8&24&8&-4\\-4&0&8&0&-4\\-2&-4&-4&-4&-2\end{bmatrix}

另外,拉普拉斯算子有一个很实用的用途,就是对图像进行锐化,这时候只要将常用模板稍微改动一下即可得到锐化模板

(1)\begin{bmatrix}0&-1&0\\-1&5&-1\\0&-1&0\end{bmatrix}\begin{bmatrix}-1&-1&-1\\-1&9&-1\\-1&-1&-1\end{bmatrix}

测试

OK,最后就是用代码实现一下了,总体还是很简单的,而且类似于OpenCV之类的库都有实现的函数。不过我还是用pil来简单实现一下:

代码语言:javascript
复制
import Image,matplotlib,sys,ImageEnhance,ImageFont,ImageDraw
import numpy as np

def gauss(im_arr):
    mat=np.array([[-2,-4,-4,-4,-2],[-4,0,8,0,-4],[-4,8,24,8,-4],[-4,0,8,0,4],[-2,-4,-4,-4,-2]])
    height,width=im_arr.shape
    ans=np.zeros((height-4,width-4))
    for i in range(height-4):
    	for j in range(width-4):
    	    ans[i,j]=np.sum(im_arr[i:i+5,j:j+5]*mat)
    return ans

def laplacian(im_arr):
    mat=np.array([[1,1,1],[1,-8,1],[1,1,1]])
    height,width=im_arr.shape
    ans=np.zeros((height-2,width-2))
    for i in range(height-2):
    	for j in range(width-2):
    	    ans[i,j]=np.sum(im_arr[i:i+3,j:j+3]*mat)
    return ans

def sharpen(im_arr):
    mat=np.array([[-1,-1,-1],[-1,9,-1],[-1,-1,-1]])
    height,width=im_arr.shape
    ans=np.zeros((height-2,width-2))
    for i in range(height-2):
    	for j in range(width-2):
    	    ans[i,j]=np.sum(im_arr[i:i+3,j:j+3]*mat)
    return ans

def robert(im_arr):
    height,width=im_arr.shape
    ans=np.zeros((height-1,width-1))
    for	i in range(height-1):
    	for j in range(width-1):
    		ans[i,j]=np.abs(im_arr[i,j]-im_arr[i+1,j+1])+np.abs(im_arr[i+1,j]-im_arr[i,j+1])
    return ans

def sobel(im_arr):
    matx=np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
    maty=np.array([[1,2,1],[0,0,0],[-1,-2,-1]])
    height,width=im_arr.shape
    gx=np.zeros((height-2,width-2))
    gy=np.zeros((height-2,width-2))
    for i in range(height-2):
    	for j in range(width-2):
    		gx[i][j]=np.sum(matx*im_arr[i:i+3,j:j+3])
		gy[i][j]=np.sum(maty*im_arr[i:i+3,j:j+3])
    ans=np.abs(gx)+np.abs(gy)
    return ans

def prewitt(im_arr):
    matx=np.array([[1,0,-1],[1,0,-1],[1,0,-1]])
    maty=np.array([[-1,-1,-1],[0,0,0],[1,1,1]])
    height,width=im_arr.shape
    gx=np.zeros((height-2,width-2))
    gy=np.zeros((height-2,width-2))
    for i in range(height-2):
    	for j in range(width-2):
    		gx[i][j]=np.sum(matx*im_arr[i:i+3,j:j+3])
    		gy[i][j]=np.sum(maty*im_arr[i:i+3,j:j+3])
    ans=np.abs(gx)+np.abs(gy)
    return ans

def isotropic(im_arr):
    matx=np.array([[1,0,-1],[1.414,0,-1.414],[1,0,-1]])
    maty=np.array([[-1,-1.414,-1],[0,0,0],[1,1.414,1]])
    height,width=im_arr.shape
    gx=np.zeros((height-2,width-2))
    gy=np.zeros((height-2,width-2))
    for i in range(height-2):
    	for j in range(width-2):
    		gx[i][j]=np.sum(matx*im_arr[i:i+3,j:j+3])
    		gy[i][j]=np.sum(maty*im_arr[i:i+3,j:j+3])
    ans=np.abs(gx)+np.abs(gy)
    return ans

def show(im_arr,name):
    im=Image.fromarray(im_arr)
    draw=ImageDraw.Draw(im)
    font = ImageFont.truetype('/usr/share/fonts/truetype/liberation/LiberationMono-BoldItalic.ttf', 18)
    draw.text((0,0),name,font=font,fill='red')
    del draw
    im=im.convert('L')
    im.save(name+'.png')

if __name__=='__main__':
    im=Image.open(sys.argv[1])
    im=im.convert('L')
    im.save('source.png')
    show(laplacian(np.array(im,'int64')),'Laplace')
    show(sobel(np.array(im,'int64')),'Sobel')
    show(robert(np.array(im,'int')),'Robert')
    show(prewitt(np.array(im,'int64')),'Prewitt')
    show(isotropic(np.array(im,'int64')),'Isotropic')
    show(sharpen(np.array(im,'int64')),'sharpen')
    show(gauss(np.array(im,'int64')),'gauss-laplace')
test
test
source
source
Sobel
Sobel
sharpen
sharpen
Robert
Robert
Prewitt
Prewitt
Isotropic
Isotropic
Laplace
Laplace
gauss-laplace
gauss-laplace

最后用他来处理一下lena.png,会的到上面的结果。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 拉普拉斯算子(Laplacian Operator)
  • 测试
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档