SUSAN 的全名是:Smallest Univalue Segment Assimilating Nucleus。它是一种很有特色高效的边缘和角点检测算子,它不仅可以检测图像目标的边界点,而且能够较Robust(鲁棒) 地检测目标的角点。并且具有结构保留的降噪功能,是一种基于灰度的特征点获取方法, 适用于图像中边缘和角点的检测, 可以去除图像中的噪声, 它具有简单、有效、抗噪声能力强、计算速度快的特点。
SUSAN 边缘检测算法原理借助上图进行阐述。其中图片是白色背景,有一个颜色比较暗淡的矩形(dark area)。用一个园形模板在图像上移动,若模板内的像素灰度与模板中心的像素(被称为核 Nucleus)灰度值小于一定的阈值,则认为该点与核 Nucleus 具有相同的灰度,满足该条件的像素组成的区域就称为 USAN(Univalue Segment Assimilating Nucleus)。
在图片上有 5 个圆形区域。圆形区域表示的是掩码区域。把圆形区域内的每一个位置的像素值与圆心处的像素值相比较,那么圆中的的像素可以分为两类,一类是像素值与圆心处的像素值相近的,另一类是像素值与圆心的处的像素值相差比较大的。如果将模板中各个像素的灰度都与模板中心的核像素的灰度进行比较,那么就会发现总有一部分模板区域和灰度与核像素的灰度相同或相似,这部分区域可以称为 USAN(Univalue Segment Assimilating Nuclues).USAN 区域包含很多与图像结构有关的信息。利用这种区域的尺寸、重心、二阶矩的分析,可以得到图像中的角点,边缘等信息。从上图所示,当核像素处在图像中的灰度一致区域时,USAN 的面积会达到最大。第 e 个模板就是属于这种情况。
运行代码说明
1.要改变代码中的图片地址(地址不能有中文)
更改
put(path)
函数中的路径put(r'../image/image1.jpg')
2.注意最后的
plt.savefig('1.new.jpg')
是保存plt图像,如果不使用可以注释掉代码依赖包:
matplotlib 3.4.2 numpy 1.20.3 opencv-python 4.1.2.30 pillow 8.2.0
# pip安装 pip install matplotlib numpy opencv-python pillow
import cv2
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def img_extraction(image):
""" img_extraction 函数利用susan角点检测算法,对图像进行处理"""
print("最小灰度值,%d" % image.min())
print("最大灰度值,%d" % image.max())
threshold_value = (int(image.max())-int(image.min()))/10
print("初始阈值为: %d" % threshold_value)
offsetX = [
-1, 0, 1,
-2, -1, 0, 1, 2,
-3, -2, -1, 0, 1, 2, 3,
-3, -2, -1, 0, 1, 2, 3,
-3, -2, -1, 0, 1, 2, 3,
-2, -1, 0, 1, 2,
-1, 0, 1
]
offsetY = [
-3, -3, -3,
-2, -2, -2, -2, -2,
-1, -1, -1, -1, -1, -1, -1,
0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2,
3, 3, 3
]
for i in range(3, image.shape[0] - 3): # 利用圆形模板遍历图像,计算每点处的USAN值
for j in range(3, image.shape[1] - 3):
same = 0
for k in range(0, 37):
if abs(int(image[i + int(offsetY[k]), j + int(offsetX[k]), 0]) - int(image[i, j, 0])) < threshold_value: # 计算相似度
same += 1
# print()
if same < 18:
image[i, j, 0] = 18 - same
image[i, j, 1] = 18 - same
image[i, j, 2] = 18 - same
else:
image[i, j, 0] = 0
image[i, j, 1] = 0
image[i, j, 2] = 0
def img_revise(image):
"""img_revise 函数用于对角点处理后的图像,进行非极大值抑制修正"""
X = [-1, -1, -1, 0, 0, 1, 1, 1] # X轴偏移
Y = [-1, 0, 1, -1, 1, -1, 0, 1] # Y轴偏移
for i in range(4, image.shape[0]-4):
for j in range(4, image.shape[1]-4):
flag = 0
for k in range(0, 8):
# print(i)
if image[i, j, 0] <= image[int(i + X[k]), int(j + Y[k]), 0]:
flag += 1
break
if flag == 0: # 判断是否是周围8个点中最大的值,是则保留
image[i, j, 0] = 255
image[i, j, 1] = 255
image[i, j, 2] = 255
else:
image[i, j, 0] = 0
image[i, j, 1] = 0
image[i, j, 2] = 0
def put(path):
img = cv2.imread(path,0)
# img = cv2.imread(os.path.join(base, path),0)
# L为灰度 为RGB分量
im = np.array(Image.open(path).convert('L').convert('RGB'))
img_extraction(im) # susan角点检测算法
img_revise(im) # 非极大值抑制修正
plt.subplot(121), plt.imshow(img, "gray")
plt.title("灰度图"), plt.axis('off')
plt.subplot(122), plt.imshow(im, "gray")
plt.title("susan边缘检测 "), plt.axis('off')
# plt.savefig('1.new-img.jpg')
plt.show()
# 图像处理函数,要传入路径
put(r'../image/image1.jpg')