用Python进行边缘检测

2022-11-14 14:38:21 浏览数 (2)

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

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

拉普拉斯算子(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&0end{bmatrix}begin{bmatrix}1&1&1\1&-8&1\1&1&1end{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&-2end{bmatrix}

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

(1)begin{bmatrix}0&-1&0\-1&5&-1\0&-1&0end{bmatrix}begin{bmatrix}-1&-1&-1\-1&9&-1\-1&-1&-1end{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')

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

png

0 人点赞