sobel边缘检测即实现对图像边缘的提取,输入为一幅图像,输出为图像轮廓。
sobel算法步骤:
(1)将输入图像转为灰度图;
(2)对灰度图进行二值化处理(此过程采用otsu二值化算法,具体otsu算法参看上一篇博客);
(3)定义sobel竖直和水平卷积算子;
(4)遍历图像像素点,除边缘像素点外,每个像素点的领域像素点(共计九个像素点)分别与sobel算子(竖直和水平卷积算子)值相乘累加;
(5)将竖直和水平sobel算子乘积值绝对值之后相加,赋于新的与原图像相等大小的矩阵中。
import cv2 as cv
import math
import numpy as np
def rgb2gray(img):
h=img.shape[0]
w=img.shape[1]
img1=np.zeros((h,w),np.uint8)
for i in range(h):
for j in range(w):
img1[i,j]=0.144*img[i,j,0]+0.587*img[i,j,1]+0.299*img[i,j,1]
return img1
def otsu(img):
h=img.shape[0]
w=img.shape[1]
m=h*w # 图像像素点总和
otsuimg=np.zeros((h,w),np.uint8)
threshold_max=threshold=0 # 定义阈值
histogram=np.zeros(256,np.int32) # 初始化各灰度级个数统计参数
probability=np.zeros(256,np.float32) # 初始化各灰度级占图像中的分布的统计参数
for i in range (h):
for j in range (w):
s=img[i,j]
histogram[s]+=1 # 统计灰度级中每个像素在整幅图像中的个数
for k in range (256):
probability[k]=histogram[k]/m # 统计每个灰度级占图像中的分布
for i in range (255):
w0 = w1 = 0 # 定义前景像素点和背景像素点灰度级占图像中的分布
fgs = bgs = 0 # 定义前景像素点灰度级总和and背景像素点灰度级总和
for j in range (256):
if j<=i: # 当前i为分割阈值
w0+=probability[j] # 前景像素点占整幅图像的比例累加
fgs+=j*probability[j]
else:
w1+=probability[j] # 背景像素点占整幅图像的比例累加
bgs+=j*probability[j]
u0=fgs/w0 # 前景像素点的平均灰度
u1=bgs/w1 # 背景像素点的平均灰度
g=w0*w1*(u0-u1)**2 # 类间方差
if g>=threshold_max:
threshold_max=g
threshold=i
print(threshold)
for i in range (h):
for j in range (w):
if img[i,j]>threshold:
otsuimg[i,j]=255
else:
otsuimg[i,j]=0
return otsuimg
def sobel(img):
h=img.shape[0]
w=img.shape[1]
sobelimg=np.zeros((h,w),np.uint8)
sobelx=[[-1,0,1],
[-2,0,2],
[-1,0,1]]
sobely=[[1,2,1],
[0,0,0],
[-1,-2,-1]]
sobelx=np.array(sobelx)
sobely=np.array(sobely)
gx=0 # 垂直方向上的梯度模长
gy=0 # 水平方向上的梯度模长
for i in range(1,h-1):
for j in range(1,w-1):
edgex=0
edgey=0
for k in range(-1,2):
for l in range(-1,2):
edgex+=img[k+i,l+j]*sobelx[1+k,1+l]
edgey+=img[k+i,l+j]*sobely[1+k,1+l]
gx=abs(edgex)
gy=abs(edgey)
gramag=gx+gy
sobelimg[i,j]=gramag
return sobelimg
image=cv.imread("D:/sobel.png")
grayimage=rgb2gray(image)
otsuimage=otsu(grayimage)
sobelimage=sobel(otsuimage)
cv.imshow("image",image)
cv.imshow("sobelimage",sobelimage)
cv.waitKey(0)
cv.destroyAllWindows()
实验结果:
通过实验结果可以看出效果并不好,说明关于源码编写仍有不少瑕疵,希望各位可以分享更为高效的代码,谢谢。