角点检测的三种方法

在计算机视觉和图像处理领域,角点检测技术至关重要,它被广泛应用于图像匹配、目标识别以及三维重建等任务。今天,我将重点介绍三种主流的角点检测方法:Harris角点检测、Shi-Tomasi角点检测以及亚像素级角点检测。通过Python语言的实践,我们来深入比较它们的精度和应用场景。

Harris 角点检测

Harris 角点检测算法简介

  1. 背景
    Harris角点检测算法于1988年由Chris Harris和Mike Stephens提出,是一种基于图像梯度信息的角点检测方法。它凭借计算简单、检测稳定且对噪声鲁棒性强等优势,被广泛应用于多个领域。
  2. 原理
    • 梯度计算:使用Sobel算子或Scharr算子计算图像每个像素点的水平和垂直方向梯度,梯度信息反映了图像在每个像素点的变化率。
    • 自相关矩阵计算:计算图像中每个像素点邻域内的自相关矩阵,该矩阵是一个2×2的矩阵,能够反映邻域内的梯度变化情况。公式如下:
      [
      M = \begin{bmatrix} \sum I_x^2 & \sum I_x I_y \ \sum I_x I_y & \sum I_y^2 \end{bmatrix}
      ]
    • 角点响应函数计算:通过角点响应函数 (R = \det(M) - k \cdot \text{trace}^2(M)) 判断一个点是否为角点。其中,(\det(M)) 是自相关矩阵的行列式,(\text{trace}(M)) 是自相关矩阵的迹,(k) 是一个常数(通常取0.04到0.06之间)。如果 (R) 的值大于某个阈值,则认为该点为角点。
  3. 优势
    Harris角点检测算法的计算效率高、检测结果稳定且对噪声鲁棒性强。它能够精准地定位角点,适用于各种复杂场景。

cornerHarris() 函数

在Python中,OpenCV库提供了cv2.cornerHarris()函数,用于实现Harris角点检测算法。函数原型如下:

cv2.cornerHarris(src, blockSize, ksize, k, dst=None)
  • src:输入图像,必须是单通道的灰度图像。
  • blockSize:用于计算自相关矩阵的邻域大小。通常取值为2、3或5。
  • ksize:Sobel算子的孔径大小,通常为3。
  • k:Harris角点检测算法中的自由参数,通常取值在0.04到0.06之间。
  • dst:可选参数,输出的角点响应图像。

该函数能够快速实现Harris角点检测,通过调整参数(如邻域大小、Sobel算子的孔径大小等),可以灵活地适应不同的图像处理需求。

Harris 角点检测实例展示

Python代码如下:

# cornerHarris()

import cv2 as cv

img = cv.imread("src.jpg", 0)

# 使用 Harris 角点检测算法对图像进行角点检测
# 参数解释:
# img:输入图像,必须是灰度图像
# 2:检测窗口的大小,表示在多大的邻域内检测角点
# 3:Sobel 算子的大小,用于计算图像的梯度
# 0.06:Harris 检测器的自由参数,影响角点检测的灵敏度
dst = cv.cornerHarris(img, 2, 3, 0.06)

# 对检测结果进行阈值化操作,将角点突出显示
# 参数解释:
# dst:Harris 角点检测的结果图像
# 0:阈值化操作的阈值
# 255:阈值化后的最大值
# cv.THRESH_BINARY:阈值化类型,大于阈值的像素值设为255,其余设为0
_, Harris_corner = cv.threshold(dst, 0, 255, cv.THRESH_BINARY)

cv.imshow("Harris_corner.jpg", Harris_corner)
cv.imwrite("Harris_corner.jpg", Harris_corner)
cv.waitKey(0)
cv.destroyAllWindows()

结果图片如下:

原图像
原图像
Harris角点检测图像
Harris角点检测图像

同样在这里要把我们老演员拿出来遛一遛(doge

原图像
原图像
Harris角点检测图像
Harris角点检测图像

Harris 角点检测的应用场景

Harris角点检测算法在图像匹配、目标识别和三维重建等领域都有广泛的应用。例如,在图像匹配任务中,它能够精准地定位图像中的角点,为后续的特征匹配提供重要依据;在目标识别中,它提取的角点特征可用于目标定位和识别;在三维重建中,它提取的特征点可用于计算图像之间的匹配关系。

Shi-Tomasi 角点检测

Shi-Tomasi 角点检测算法简介

  1. 背景
    Shi-Tomasi角点检测算法由Shi和Tomasi在1994年提出,是对Harris角点检测算法的改进。它通过优化角点响应函数,进一步提高了角点检测的稳定性和准确性,特别适用于目标跟踪和运动估计等应用。
  2. 原理
    • 梯度计算:计算图像在每个像素点的水平方向和垂直方向的梯度,梯度信息反映了图像在每个像素点的变化率。
    • 自相关矩阵计算:计算图像中每个像素点邻域内的自相关矩阵。公式如下:
      [
      M = \begin{bmatrix} \sum I_x^2 & \sum I_x I_y \ \sum I_x I_y & \sum I_y^2 \end{bmatrix}
      ]
    • 角点响应函数计算:Shi-Tomasi算法通过计算自相关矩阵的最小特征值来判断一个点是否为角点。公式为 (R = \min(\lambda_1, \lambda_2)),其中,(\lambda_1) 和 (\lambda_2) 是自相关矩阵的两个特征值。如果 (R) 的值大于某个阈值,则认为该点为角点。
  3. 优势
    Shi-Tomasi角点检测算法的计算效率高、检测结果稳定且对噪声鲁棒性强。它能够更准确地检测出角点。

goodFeaturesToTrack() 函数

在Python中,OpenCV库提供了cv2.goodFeaturesToTrack()函数,用于实现Shi-Tomasi角点检测算法。函数原型如下:

cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance, corners=None, mask=None, blockSize=None, useHarrisDetector=None, k=None)
  • image:输入图像,必须是单通道的灰度图像。
  • maxCorners:希望检测到的最大角点数量。
  • qualityLevel:角点检测的质量水平,范围在0到1之间。它表示最小的特征值与最大特征值的比率。
  • minDistance:检测到的角点之间的最小欧几里得距离。
  • corners:可选参数,输出的角点列表。
  • mask:可选参数,指定检测角点的区域。
  • blockSize:计算自相关矩阵的邻域大小,默认值为3。
  • useHarrisDetector:布尔值,是否使用Harris角点检测算法。默认为False,即使用Shi-Tomasi算法。
  • k:Harris角点检测算法中的自由参数,仅当useHarrisDetector=True时有效。

该函数能够快速实现Shi-Tomasi角点检测,通过调整参数(如最大角点数量、质量水平、最小距离等),可以灵活地适应不同的图像处理需求。

Shi-Tomasi角点检测实例展示

# Shi-Tomasi
# goodFeaturesToTrack()

import numpy as np
import cv2 as cv

# 定义角点检测的参数
max_corners = 20 # 最大角点数量
quality_level = 0.01 # 角点检测的质量水平(阈值)
min_dist = 50 # 角点之间的最小欧几里得距离

# 读取图像,以灰度模式加载
# 参数 'src.jpg' 是图像文件的路径,0 表示以灰度模式读取
img = cv.imread('src.jpg', 0)

# 使用 Shi-Tomasi 角点检测算法检测角点
# 参数解释:
# img:输入图像,必须是灰度图像
# max_corners:检测到的最大角点数量
# quality_level:角点检测的质量水平,值越低,检测到的角点越多
# min_dist:角点之间的最小欧几里得距离
corners = cv.goodFeaturesToTrack(img, max_corners, quality_level, min_dist)

# 将检测到的角点坐标转换为整数类型
# np.int32 是 32 位整数类型,用于确保角点坐标值不会被截断
corners = np.int32(corners)

# 遍历检测到的角点,并在图像上绘制圆形标记
for i in corners:
# ravel() 将角点坐标数组展平为一维数组
x, y = i.ravel()
# 在图像上绘制圆形标记
# 参数解释:
# (x, y):圆心坐标
# 5:圆的半径
# (128, 128, 128):圆的颜色(灰度值)
# -1:填充圆
cv.circle(img, (x, y), 5, (128, 128, 128), -1)

cv.imwrite('Shi_Tomasi_corner_2.jpg', img)
cv.imshow('Shi_Tomasi_corner_2.jpg', img)
cv.waitKey(0)
cv.destroyAllWindows()

结果展示如下:

原图像
原图像
Shi-Tomasi角点检测图像
Shi-Tomasi角点检测图像

Shi-Tomasi 角点检测的应用场景

Shi-Tomasi角点检测算法在目标跟踪、图像拼接和三维重建等领域都有广泛的应用。例如,在目标跟踪任务中,它能够精准地定位图像中的角点,为后续的目标跟踪提供重要依据;在图像拼接中,它提取的特征点可用于计算图像之间的匹配关系。

亚像素级角点检测

亚像素级角点检测简介

  1. 背景
    亚像素级角点检测是一种将角点定位精度提升到亚像素级别的技术。它通过优化算法,在像素级别检测的基础上进一步细化角点的位置,从而提高角点检测的精度。在目标跟踪、三维重建和图像拼接等对精度要求较高的应用中具有重要意义。
  2. 原理
    • 像素级别角点检测:使用传统的角点检测算法(如Harris、Shi-Tomasi或FAST)检测出像素级别的角点。
    • 亚像素级优化:在像素级别检测到的角点附近,使用迭代优化算法进一步搜索更精确的角点位置。通常使用零阶矩和一阶矩的组合来计算角点的亚像素位置。优化算法的目标是最小化角点附近的梯度变化,从而找到更精确的角点位置。
    • 收敛条件:当迭代优化算法达到预设的迭代次数或角点位置的变化小于某个阈值时,算法停止迭代。
  3. 优势
    亚像素级角点检测的主要优势在于其高精度和对噪声的鲁棒性。它能够显著提高角点检测的精度,适用于对精度要求较高的应用。

cornerSubPix() 函数

在Python中,OpenCV库提供了cv2.cornerSubPix()函数,用于实现亚像素级角点检测。函数原型如下:

cv2.cornerSubPix(image, corners, winSize, zeroZone, criteria)
  • image:输入图像,必须是单通道的灰度图像。
  • corners:像素级别检测到的角点列表,通常由cv2.goodFeaturesToTrack()或其他角点检测函数返回。
  • winSize:搜索窗口的大小,格式为(winSize, winSize),表示以每个角点为中心的搜索窗口的半径。
  • zeroZone:死区的大小,格式为(zeroZone, zeroZone),表示在搜索窗口中心的区域内不考虑梯度信息。如果为(-1, -1),则表示没有死区。
  • criteria:迭代优化算法的终止条件,通常是一个包含最大迭代次数和精度阈值的元组。例如,criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)表示最大迭代次数为30,精度阈值为0.001。

该函数能够在像素级别检测的基础上进一步优化角点位置,从而提高角点检测的精度。通过调整参数(如搜索窗口大小、死区大小和迭代终止条件等),可以灵活地适应不同的图像处理需求。

示例

以下是一个使用OpenCV的cv2.cornerSubPix()函数进行亚像素级角点检测的简单示例,并与Shi-Tomasi角点检测的goodFeaturesToTrack()函数进行坐标精度的对比。

# 比较 Shi-Tomasi 角点检测与亚像素角点检测的精度

import cv2 as cv
import numpy as np

src = cv.imread('src.jpg', 0)

# 定义 Shi-Tomasi 角点检测的参数
max_corners = 20 # 最大角点数量
quality_level = 0.01 # 角点检测的质量水平,值越低,检测到的角点越多
min_dist = 50 # 角点之间的最小欧几里得距离
block_size = 3 # 梯度计算的窗口大小
use_harris = False # 是否使用 Harris 角点检测器
k = 0.04 # Harris 角点检测器的自由参数(仅在 use_harris=True 时有效)

# 创建图像的拷贝,用于绘制角点
copy1 = np.copy(src) # 用于绘制 Shi-Tomasi 角点
copy2 = np.copy(src) # 用于绘制亚像素角点

# 使用 Shi-Tomasi 角点检测算法检测角点
# 参数解释:
# src:输入图像,必须是灰度图像
# max_corners:检测到的最大角点数量
# quality_level:角点检测的质量水平
# min_dist:角点之间的最小欧几里得距离
# None:不指定掩模(默认检测整个图像)
# blockSize:梯度计算的窗口大小
# useHarrisDetector:是否使用 Harris 角点检测器
# k:Harris 角点检测器的自由参数
corners = cv.goodFeaturesToTrack(src, max_corners, quality_level, min_dist, None, blockSize=block_size, useHarrisDetector=use_harris, k=k)

# 定义绘制角点的圆的半径
radius = 8

# 遍历检测到的角点,并在图像上绘制圆形标记
for i in range(corners.shape[0]):
# 将浮点数坐标转换为整数类型,因为 cv2.circle 需要整数坐标
x, y = int(corners[i, 0, 0]), int(corners[i, 0, 1])
# 在图像上绘制圆形标记
# 参数解释:
# (x, y):圆心坐标
# radius:圆的半径
# (128, 128, 128):圆的颜色(灰度值)
# -1:填充圆
cv.circle(copy1, (x, y), radius, (128, 128, 128), -1)

# 将绘制了 Shi-Tomasi 角点的图像保存到文件
cv.imwrite("Shi_tomasi.jpg", copy1)
cv.imshow('Shi_tomasi.jpg', copy1)

# 打印 Shi-Tomasi 角点坐标
print("Shi-Tomasi 角点坐标")
for i in range(corners.shape[0]):
# 打印角点坐标,保留浮点数的精度
print("坐标", i, ": (", corners[i, 0, 0], ",", corners[i, 0, 1], ")")

# 定义亚像素角点检测的参数
win_size = (5, 5) # 搜索窗口的大小
zero_zone = (-1, -1) # 零区域的大小(-1 表示没有零区域)
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_COUNT, 40, 0.001) # 终止条件

# 使用亚像素角点检测算法进一步精确角点位置
# 参数解释:
# src:输入图像,必须是灰度图像
# corners:初始角点坐标(由 Shi-Tomasi 检测得到)
# win_size:搜索窗口的大小
# zero_zone:零区域的大小
# criteria:终止条件
corners = cv.cornerSubPix(src, corners, win_size, zero_zone, criteria)

# 遍历亚像素角点,并在图像上绘制圆形标记
for i in range(corners.shape[0]):
# 将浮点数坐标转换为整数类型,因为 cv2.circle 需要整数坐标
x, y = int(corners[i, 0, 0]), int(corners[i, 0, 1])
# 在图像上绘制圆形标记
cv.circle(copy2, (x, y), radius, (128, 128, 128), -1)

cv.imwrite("Sub_pixel.jpg", copy2)
cv.imshow("Sub_pixel.jpg", copy2)

# 打印亚像素角点坐标,保留高精度的小数点
print("亚像素角点坐标打印")
for i in range(corners.shape[0]):
# 使用格式化字符串打印角点坐标,保留小数点后五位
print(f"坐标 {i}: ({corners[i, 0, 0]:.5f}, {corners[i, 0, 1]:.5f})")

cv.waitKey(0)
cv.destroyAllWindows()

两种方法图像对比(好像用肉眼看不出来,毕竟是小数的区别:

Shi-Tomasi角点检测图像
Shi-Tomasi角点检测图像
亚像素级角点检测图像
亚像素级角点检测图像

以下为 Shi-Tomasi 角点检测坐标打印结果:

Shi-Tomasi 角点坐标
坐标 0 : ( 449.0 , 285.0 )
坐标 1 : ( 551.0 , 228.0 )
坐标 2 : ( 347.0 , 228.0 )
坐标 3 : ( 551.0 , 112.0 )
坐标 4 : ( 347.0 , 112.0 )
坐标 5 : ( 449.0 , 55.0 )
坐标 6 : ( 144.0 , 141.0 )
坐标 7 : ( 275.0 , 174.0 )
坐标 8 : ( 71.0 , 174.0 )
坐标 9 : ( 409.0 , 106.0 )
坐标 10 : ( 173.0 , 289.0 )
坐标 11 : ( 173.0 , 58.0 )
坐标 12 : ( 199.0 , 203.0 )
坐标 13 : ( 147.0 , 203.0 )
坐标 14 : ( 487.0 , 229.0 )
坐标 15 : ( 411.0 , 229.0 )
坐标 16 : ( 198.0 , 144.0 )
坐标 17 : ( 487.0 , 111.0 )
坐标 18 : ( 525.0 , 170.0 )
坐标 19 : ( 378.0 , 170.0 )

以下为亚像素角点坐标打印结果:

亚像素角点坐标打印
坐标 0: (449.00000, 285.00000)
坐标 1: (551.00000, 228.00000)
坐标 2: (347.00000, 228.00000)
坐标 3: (551.00000, 112.00000)
坐标 4: (347.00000, 112.00000)
坐标 5: (449.00000, 55.00000)
坐标 6: (147.41205, 144.31113)
坐标 7: (275.00000, 174.00000)
坐标 8: (71.00000, 174.00000)
坐标 9: (411.58264, 110.43745)
坐标 10: (173.00000, 289.00000)
坐标 11: (173.00000, 58.00000)
坐标 12: (198.89714, 203.04985)
坐标 13: (147.41327, 203.26128)
坐标 14: (486.85046, 229.60292)
坐标 15: (411.14954, 229.60292)
坐标 16: (198.69484, 143.99083)
坐标 17: (486.85046, 110.39708)
坐标 18: (525.00000, 170.00000)
坐标 19: (378.37875, 170.00000)

显然,亚像素级角点检测的精度更高,坐标精度可以达到小数点后五位

应用场景

亚像素级角点检测在目标跟踪、三维重建和图像拼接等领域都有广泛的应用。例如,在目标跟踪任务中,它能够提供更精确的角点位置,从而提高目标跟踪的精度;在三维重建中,它提取的特征点可用于计算图像之间的匹配关系。

三种角点检测技术的对比

为了更好地理解这三种角点检测技术的特点和适用场景,我们从以下几个维度进行对比:

特性 Harris 角点检测 Shi-Tomasi 角点检测 亚像素级角点检测
检测精度 像素级 像素级 亚像素级
计算复杂度
对噪声的鲁棒性 更强
适用场景 图像匹配
目标识别
三维重建
目标跟踪
图像拼接
三维重建
目标跟踪
三维重建
图像拼接

通过上表可以看出,Harris和Shi-Tomasi角点检测算法适用于大多数常见的计算机视觉任务,并且具有较低的计算复杂度和较强的鲁棒性。而亚像素级角点检测则在精度上有显著提升,适用于对精度要求更高的场景,但计算复杂度也相对较高。