本文介绍了如何实现角点检测,主要使用到了两种方法:基于Harris 角点检测器以及基于 H 矩阵最小特征值的检测方法。[1]
包含方法原理与步骤、代码、结果比对。
如果觉得有帮助,请点赞关注我。
角点
角点是指图像中在两个或多个方向上都有较大灰度变化的像素点。从数学角度来看,角点是图像函数的局部极值点,其在某个邻域内具有显著的梯度变化。通常可以认为,角点是图像中两条边缘相交的点,可以用来表示图像中物体结构变化的显著特征。
角点检测在计算机视觉领域有着广泛的应用,例如图像匹配、目标识别、三维重建和运动估计等。
Harris 角点检测器
Harris 角点检测器是一种经典的角点检测方法,由Chris Harris和Mike Stephens在 1988 年提出。该方法通过分析图像的梯度信息来识别角点。
步骤
基于H矩阵最小特征值的角点检测器
这种方法也是基于图像的梯度信息,但它直接使用H矩阵的特征值来确定角点。
步骤
代码
def corner_detect(img, block_size, nms_size, method, k):
# 计算图像的梯度
dx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
dy = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
# 计算自相关矩阵的分量
Ixx = dx * dx
Ixy = dx * dy
Iyy = dy * dy
# 对自相关矩阵进行高斯滤波,以减小噪声的影响
window_size = block_size # 使用block_size作为高斯滤波的窗口大小
ksize = (window_size, window_size)
Ixx = cv2.GaussianBlur(Ixx, ksize, 0)
Ixy = cv2.GaussianBlur(Ixy, ksize, 0)
Iyy = cv2.GaussianBlur(Iyy, ksize, 0)
# 初始化角点响应图
R = np.zeros_like(img, dtype=np.float32)
if method == 'harris':
det_H = Ixx * Iyy - Ixy * Ixy
trace_H = Ixx + Iyy
R = det_H - k * (trace_H ** 2)
elif method == 'eigenvalue':
# 对每个像素点计算H矩阵的特征值
for y in range(block_size, img.shape[0] - block_size):
for x in range(block_size, img.shape[1] - block_size):
# 构建单个像素点的自相关矩阵
H = np.array([[Ixx[y, x], Ixy[y, x]], [Ixy[y, x], Iyy[y, x]]])
# 计算特征值
eig_vals = np.linalg.eigvals(H)
# 保存最小特征值
min_eig = min(eig_vals)
R[y, x] = min_eig
# 根据阈值筛选角点
threshold = 0.01
corners = (R > threshold* R.max()).astype(np.uint8) * 255
# 应用非最大值抑制
for y in range(nms_size, img.shape[0] - nms_size):
for x in range(nms_size, img.shape[1] - nms_size):
if corners[y, x] == 255:
local_max = True
for dy in range(-nms_size, nms_size + 1):
for dx in range(-nms_size, nms_size + 1):
if corners[y, x] < corners[y + dy, x + dx]:
local_max = False
break
if not local_max:
break
if local_max:
corners[y, x] = 255
else:
corners[y, x] = 0
return corners, R
在这个函数中基本的处理就是使用cv2.Sobel来计算横向以及纵向的梯度,然后按照前面的公式计算计算自相关矩阵H的分量,并对这些分量进行高斯滤波,使用blo ck_size作为高斯滤波的窗口大小。
在这里如果method == 'harris',那么按照R的计算公式计算每一个像素值是角点的可能性,如果method == 'eigenvalue',那么构建每一个像素点的H矩阵,求解其特征值,选择最小的那个特征值作为R。
阈值的选取是选择R中最大值乘以threshold。Threshold值会影响后面角点的检测,其越大检测到的角点数就越小。corners = (R > threshold* R.max()).astype(np.uint8) * 255这句代码使用了布尔索引,将角点响应图R中高于阈值的像素值设置为255(白色), 其余设置为0(黑色),从而生成一个二值图像corners,其中白色点表示检测到的角点, 应用非最大值抑制来减少噪声,最后返回结果。
def image_read():
# 读取图像
image = cv2.imread('your_img.jpg')
print(image.shape)
if image is None:
print("Error: Image not found.")
exit()
# 将图像转换为灰度图
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 调用Harris角点检测函数
corners, R = corner_detect(gray_image,5, 3, 'harris', 0.05)
print(corners.shape)
# 在原图上标注角点
for y in range(corners.shape[0]):
for x in range(corners.shape[1]):
if corners[y, x] == 255:
# 将角点位置的像素值设为红色
image[y, x] = [0, 0, 255]
# 显示结果
cv2.imshow('Harris Corner Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存图像
cv2.imwrite('harris_corners_detected.jpg', image)
这段代码的逻辑很简单,使用cv2读取图片,并将图像转换为灰度图,调用 corner _detect 函数进行 Harris 角点检测。参数解释:传入灰度图像,邻域大小为5,非最大值抑制大小为3,方法('harris'或'eigenvalue')和 Harris 参数 k为0.05。
结果展示
运行代码,选择method为harris,得到检测结果:
保持其它参数不变,将前面提到的threshold改为0.02,运行代码得到检测结果:
运行代码,选择method为eigenvalue,得到检测结果:
调用现成函数cv2.cornerHarris 进行检测,代码来源网络教程[2] ,得到检测结果:
[1] Harris C G , Stephens M J .A combined corner and edge detector[C]//Alvey visio n conference.1988.DOI:10.5244/C.2.23.
[2] (2024) Opencv之图像SIFT 特征检测与Harris角点检测. Available at: Opencv之图像SIFT 特征检测与Harris角点检测_harris 焦点检测器-CSDN博客 (Accessed: 25 February 2025).