Sobel算子是图像边缘检测中最重要的算子之一,该算子包含两组3×3的矩阵,分别为横向及纵向,将之与图像作2D卷积,即可分别得出横向及纵向的亮度差分近似值。Gx,Gy的值如下所示:
将图像I分别和G x , G y G_x,G_y G x ,G y 作2D卷积,得到G x ′ , G y ′ G_x’,G_y’G x ′,G y ′
图像的每一个像素的横向及纵向梯度近似值可用以下两个公式结合,来计算梯度的大小。
G = ∣ G x ′ ∣ + ∣ G y ′ ∣ G=|G_x’|+|G_y’|G =∣G x ′∣+∣G y ′∣
G = G x ′ 2 + G y ′ 2 G=\sqrt{G_x’^2+G_y’^2}G =G x ′2 +G y ′2
计算得到G之后,我们只需要设定一个阈值G m a x G_{max}G m a x (比如说:100,一般来讲0-255左右为宜),若梯度G大于阈值G m a x G_{max}G m a x ,则可认为该点是一个边界点。
代码如下:
import torch
from PIL import Image
import numpy as np
def color2gray(img):
return 0.3*img[:,:,0]+0.59*img[:,:,1]+0.11*img[:,:,2]
def sobel(img,mode,Gmax):
h,w=img.shape
sobel_img=np.zeros((h,w))
Gx=np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
Gy=np.array([[1,2,1],[0,0,0],[-1,-2,-1]])
for i in range(h):
for j in range(w):
tmp1=0
tmp2=0
for kx in range(3):
for ky in range(3):
if i+kx-1>=0 and i+kx-1<h and j+ky-1>=0 and j+ky-1<w:
tmp1+=img[i+kx-1][j+ky-1]*Gx[kx][ky]
tmp2+=img[i+kx-1][j+ky-1]*Gy[kx][ky]
if mode==0:
if np.abs(tmp1)+np.abs(tmp2)>Gmax:
sobel_img[i][j]=255
else:
sobel_img[i][j]=0
else:
if np.sqrt(tmp1**2+tmp2**2)>Gmax:
sobel_img[i][j]=255
else:
sobel_img[i][j]=0
return sobel_img
img_PIL = Image.open("test.jpg")
img_PIL.show()
img_PIL = np.array(img_PIL)
gray_img=color2gray(img_PIL)
image=Image.fromarray(np.uint8(gray_img))
image.show()
sobel_img=sobel(gray_img,1,127)
image=Image.fromarray(np.uint8(sobel_img))
image.show()
结果展示:
当对精度的要求较高时可以使用S c h a r r 滤 波 器 Scharr滤波器S c h a r r 滤波器,Scharr滤波器水平方向与竖直方向的核为:
边缘检测的效果如下:
不知为何,效果反而变差了.
改进
去掉了G m a x G_{max}G m a x 这个阈值的判断,将范围压缩至[0,255]后直接显示灰度图像,效果明显好了很多:
改进后的代码如下所示:
import torch
from PIL import Image
import numpy as np
def color2gray(img):
return 0.3*img[:,:,0]+0.59*img[:,:,1]+0.11*img[:,:,2]
def sobel(img,mode,Gmax):
h,w=img.shape
sobel_img=np.zeros((h,w))
Gx=np.array([[-3,0,3],[-10,0,10],[-3,0,3]])
Gy=np.array([[-3,-10,-3],[0,0,0],[3,10,3]])
for i in range(h):
for j in range(w):
tmp1=0
tmp2=0
for kx in range(3):
for ky in range(3):
if i+kx-1>=0 and i+kx-1<h and j+ky-1>=0 and j+ky-1<w:
tmp1+=img[i+kx-1][j+ky-1]*Gx[kx][ky]
tmp2+=img[i+kx-1][j+ky-1]*Gy[kx][ky]
if mode==0:
sobel_img[i][j]=np.abs(tmp1)+np.abs(tmp2)
else:
sobel_img[i][j]=np.sqrt(tmp1**2+tmp2**2)
max=np.max(sobel_img)
min=np.min(sobel_img)
sobel_img=np.round((sobel_img-min)/(max-min)*255)
return sobel_img
img_PIL = Image.open("test.jpg")
img_PIL.show()
img_PIL = np.array(img_PIL)
gray_img=color2gray(img_PIL)
image=Image.fromarray(np.uint8(gray_img))
image.show()
sobel_img=sobel(gray_img,1,60)
image=Image.fromarray(np.uint8(sobel_img))
image.show()
Original: https://blog.csdn.net/qq_40268672/article/details/122878596
Author: FPGA硅农
Title: 【图像处理】sobel边缘检测的实现
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/633635/
转载文章受原作者版权保护。转载请注明原作者出处!