边缘提取
1. 边缘提取
梯度:记向量(矢量)
滤波/卷积
边缘有正负之分,就像导数有正值也有负值一样:由暗到亮为正,由亮到暗为负
求边缘幅度的算法:sobel、prewitt、laplace、Canny算子
2. 图像锐化
图像锐化是为了突出图像上的物的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强。
图像平滑
目的是使图像亮度平缓渐变,减小突变梯度,改善图像质量。
3. Prewitt、Sobel算子
Sobel算子
对x方向求导,得到的是y方向的边缘;
对y方向求导,得到的是x方向的边缘。
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
dst = cv2.addWeighted(absX,0.5,absY,0.5,0)
Prewitt算子
就是图像平滑 Gx,Gy
4. Canny边缘检测算法
- 对图像进行灰度化
- 对图像进行高斯滤波:
根据待滤波的像素点及其邻域点的灰度值按照一定的参数规则进行加权平均。这样可以有效滤去理想图像中叠加的高频噪声。 - 检测图像中的水平、垂直和对角边缘(如Prewitt,Sobel算子等)。
- 对梯度幅值进行非极大值抑制(非极大值抑制,简称为NMS算法,英文为Non-Maximum Suppression。其思想是搜素局部最大值,抑制非极大值。)
- 将当前像素的梯度强度与沿正负梯度方向上的两个像素进行比较。
- 如果当前像素的梯度强度与另外两个像素相比最大,则该像素点保留为边缘点,否则该像素点将被抑制(灰度值置为0)
根据C点坐标求梯度,求dTmp1,dTmp2,用插值算法求f(x,y)像素值。
如果c>tmp1 and c > tmp2
- 用双阈值算法检测和连接边缘
4-5步是Canny的重点-做减法。
代码:
# -*- coding: utf-8 -*-
'''@Time: 2024/5/5 17:43
'''
import numpy as np
import matplotlib.pyplot as plt
import math
if __name__ == '__main__':
pic_path = '../lenna.png'
img = plt.imread(pic_path)
print("image", img)
if pic_path[-4:] == '.png': # .png图片在这里的存储格式是0到1的浮点数,所以要扩展到255再计算
img = img * 255 # 还是浮点数类型
img = img.mean(axis=-1) # 取均值的方法进行灰度化
# 1、高斯平滑
# sigma = 1.52 # 高斯平滑时的高斯核参数,标准差,可调
sigma = 0.5 # 高斯平滑时的高斯核参数,标准差,可调
dim = 5 # 高斯核尺寸
Gaussian_filter = np.zeros([dim, dim]) # 存储高斯核,这是数组不是列表了
tmp = [i - dim // 2 for i in range(dim)] # 生成一个序列
n1 = 1 / (2 * math.pi * sigma ** 2) # 计算高斯核
n2 = -1 / (2 * sigma ** 2)
for i in range(dim):
for j in range(dim):
Gaussian_filter[i, j] = n1 * math.exp(n2 * (tmp[i] ** 2 + tmp[j] ** 2))
Gaussian_filter = Gaussian_filter / Gaussian_filter.sum()#归一化
dx, dy = img.shape
img_new = np.zeros(img.shape) # 存储平滑之后的图像,zeros函数得到的是浮点型数据
tmp = dim // 2
img_pad = np.pad(img, ((tmp, tmp), (tmp, tmp)), 'constant') # 边缘填补
for i in range(dx):
for j in range(dy):
img_new[i, j] = np.sum(img_pad[i:i + dim, j:j + dim] * Gaussian_filter)
plt.figure(1)
plt.imshow(img_new.astype(np.uint8), cmap='gray') # 此时的img_new是255的浮点型数据,强制类型转换才可以,gray灰阶
plt.axis('off')
# 2、求梯度。以下两个是滤波用的sobel矩阵(检测图像中的水平、垂直和对角边缘)
sobel_kernel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
sobel_kernel_y = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
img_tidu_x = np.zeros(img_new.shape) # 存储梯度图像
img_tidu_y = np.zeros([dx, dy])
img_tidu = np.zeros(img_new.shape)
img_pad = np.pad(img_new, ((1, 1), (1, 1)), 'constant') # 边缘填补,根据上面矩阵结构所以写1
for i in range(dx):
for j in range(dy):
img_tidu_x