天津中医药大学-20级医学信息工程 教师:王翌 学生:邓集亲
声明:本文章中所涉及的代码并非我个人独立完成的成果。
在撰写的过程中,我广泛地吸取了前一辈人,尤其是学长学姐们的宝贵学习经验。通过深入研究他们的学习轨迹,以及查阅和分析了众多相关的理论文献与资料,并在王老师的悉心指导下,经过反复的实验、调试与优化,最终得以总结完成本文所展现的代码。
建议各位学弟学妹们,先根据王老师的授课内容,独立思考一下应该如何完成。如果实在是有理解上的困难,不知道从何下手,再来学习和参考本文。
学长我是用Python写的,如果你使用MATLAB,同样可以参考此代码进行翻译。我在代码中加入了许多注释和测试环节,以便于理解。由于学长能力有限,代码中或许存在一些疏漏或错误,请批判性地参考。
实验八:边缘检测
作业要求:
- 参考“图像分割”课的内容,用Sobel算子提取输入的图像x方向上的梯度分量、y方向上的梯度分量以及梯度图像。
例子:
实验图片:
building.tif,再自选其它至少20张图片(包括灰度图片和彩色图片)。
边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。
在之前的作业中,我们已经知道,图像中的振幅(即灰度值曲线)在边缘点或噪声会有急剧变化。因此,我们可以通过计算图像中每个像素点处的梯度值,进而来确定该像素点是否位于边缘。
Sobel算子是一种常用的基于卷积运算实现的边缘检测算法。它通过对原始图像进行卷积运算来计算每个像素点处的梯度,并根据梯度大小和方向来确定该点是否为边缘。
具体而言,Sobel算子使用一个3x3或5x5的卷积核对原始图像进行卷积运算,得到每个像素点处的梯度值。然后,通过对梯度值进行阈值处理来确定哪些像素点是边缘。一般来说,如果梯度值超过了一个阈值,则将该像素点判定为边缘;否则将其判定为非边缘。
Windows图片文件目录:
ImageSet文件目录下储存其他待处理图片
Python代码:
#导入库
import cv2
import numpy as np
from matplotlib import pyplot
#定义函数提取x上分量,剩下y
def sobel_x(img):
# 定义Sobel算子
sobel_x = [[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]]
# 获取图像尺寸
height, width = img.shape
# 初始化结果数组
result = np.zeros((height - 2, width - 2))
# 遍历图像像素
for i in range(1, height - 1):
for j in range(1, width - 1):
# 计算Sobel算子卷积结果,为了更直观,用\连接
pixel = (sobel_x[0][0] * img[i-1][j-1]) + (sobel_x[0][1] * img[i-1][j]) + \
(sobel_x[0][2] * img[i-1][j+1]) + (sobel_x[1][0] * img[i][j-1]) + \
(sobel_x[1][1] * img[i][j]) + (sobel_x[1][2] * img[i][j+1]) + \
(sobel_x[2][0] * img[i+1][j-1]) + (sobel_x[2][1] * img[i+1][j]) + \
(sobel_x[2][2] * img[i+1][j+1])
# 将卷积结果存入结果数组中
if pixel>=0 and pixel<=255:
result[i-1][j-1] = pixel
return result
#定义函数提取y上分量,剩下x
def sobel_y(img):
# 定义Sobel算子
sobel_y = [[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]]
# 获取图像尺寸
height, width = img.shape
# 初始化结果数组
result = np.zeros((height - 2, width - 2))
# 遍历图像像素
for i in range(1, height - 1):
for j in range(1, width - 1):
# 计算Sobel算子卷积结果,为了更直观,用\连接
pixel = (sobel_y[0][0] * img[i-1][j-1]) + (sobel_y[0][1] * img[i-1][j]) + \
(sobel_y[0][2] * img[i-1][j+1]) + (sobel_y[1][0] * img[i][j-1]) + \
(sobel_y[1][1] * img[i][j]) + (sobel_y[1][2] * img[i][j+1]) + \
(sobel_y[2][0] * img[i+1][j-1]) + (sobel_y[2][1] * img[i+1][j]) + \
(sobel_y[2][2] * img[i+1][j+1])
# 将卷积结果存入结果数组中
if pixel>=0 and pixel<=255:
result[i-1][j-1] = pixel
return result
#读取图像
original = cv2.imread(r'D:\deng\smalljob\ImageSet\building.tif')
original_gray = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY) #将图像从RGB颜色空间转换到灰度颜色空间
img_y=sobel_x(original_gray)
img_x=sobel_y(original_gray)
img_xy=np.sqrt(img_x**2 + img_y**2)
#展示结果
pyplot.subplot(221),pyplot.imshow(original_gray,cmap='gray')
pyplot.title('original')
pyplot.axis('off')
pyplot.subplot(222),pyplot.imshow(img_x,cmap='gray')
pyplot.title('|G$_{x}$|')
pyplot.axis('off')
pyplot.subplot(223),pyplot.imshow(img_y,cmap='gray')
pyplot.title('|G$_{y}$|')
pyplot.axis('off')
pyplot.subplot(224),pyplot.imshow(img_xy,cmap='gray')
pyplot.title('|G$_{x}$|+|G$_{y}$|')
pyplot.axis('off')
pyplot.show()
运行结果:
以上是处理灰度图,以下是处理彩色图像
import cv2
import numpy as np
from matplotlib import pyplot
def sobel_x(img):
# 定义Sobel算子
sobel_x = [[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]]
# 获取图像尺寸
height, width = img.shape
# 初始化结果数组
result = np.zeros((height - 2, width - 2))
# 遍历图像像素
for i in range(1, height - 1):
for j in range(1, width - 1):
# 计算Sobel算子卷积结果,为了更直观,用\连接
pixel = (sobel_x[0][0] * img[i-1][j-1]) + (sobel_x[0][1] * img[i-1][j]) + \
(sobel_x[0][2] * img[i-1][j+1]) + (sobel_x[1][0] * img[i][j-1]) + \
(sobel_x[1][1] * img[i][j]) + (sobel_x[1][2] * img[i][j+1]) + \
(sobel_x[2][0] * img[i+1][j-1]) + (sobel_x[2][1] * img[i+1][j]) + \
(sobel_x[2][2] * img[i+1][j+1])
# 将卷积结果存入结果数组中
if pixel>=0 and pixel<=255:
result[i-1][j-1] = pixel
return result
def sobel_y(img):
# 定义Sobel算子
sobel_y = [[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]]
# 获取图像尺寸
height, width = img.shape
# 初始化结果数组
result = np.zeros((height - 2, width - 2))
# 遍历图像像素
for i in range(1, height - 1):
for j in range(1, width - 1):
# 计算Sobel算子卷积结果,为了更直观,用\连接
pixel = (sobel_y[0][0] * img[i-1][j-1]) + (sobel_y[0][1] * img[i-1][j]) + \
(sobel_y[0][2] * img[i-1][j+1]) + (sobel_y[1][0] * img[i][j-1]) + \
(sobel_y[1][1] * img[i][j]) + (sobel_y[1][2] * img[i][j+1]) + \
(sobel_y[2][0] * img[i+1][j-1]) + (sobel_y[2][1] * img[i+1][j]) + \
(sobel_y[2][2] * img[i+1][j+1])
# 将卷积结果存入结果数组中
if pixel>=0 and pixel<=255:
result[i-1][j-1] = pixel
return result
#读取图像
original = cv2.imread(r'D:\deng\smalljob\ImageSet\girl.jpg')
origin = cv2.cvtColor(original, cv2.COLOR_BGR2RGB) #将图像从BGR颜色空间转换到RGB颜色空间
b,g,r=cv2.split(origin)#分离颜色通道
img_b_y=sobel_x(b)
img_g_y=sobel_x(g)
img_r_y=sobel_x(r)
result_y=np.dstack((img_b_y,img_g_y,img_r_y))
result_y=np.abs(result_y).astype(np.float32)/255.0
img_b_x=sobel_y(b)
img_g_x=sobel_y(g)
img_r_x=sobel_y(r)
result_x=np.dstack((img_b_x,img_g_x,img_r_x))
result_x=np.abs(result_x).astype(np.float32)/255.0
result_xy=np.sqrt(result_x**2 + result_y**2)
#展示结果
pyplot.subplot(221),pyplot.imshow(origin,cmap='gray')
pyplot.title('original')
pyplot.axis('off')
pyplot.subplot(222),pyplot.imshow(result_x,cmap='gray')
pyplot.title('|G$_{x}$|')
pyplot.axis('off')
pyplot.subplot(223),pyplot.imshow(result_y,cmap='gray')
pyplot.title('|G$_{y}$|')
pyplot.axis('off')
pyplot.subplot(224),pyplot.imshow(result_xy,cmap='gray')
pyplot.title('|G$_{x}$|+|G$_{y}$|')
pyplot.axis('off')
pyplot.show()
运行结果: