OpenCV-Python(30):Harris角点检测

发布时间:2023年12月27日

目标

  • 理解Harris角点检测的概念
  • 掌握函数cv2.cornerHarris()、cv2.cornerSubPix()的用法

Harris算法原理

? ? ? ? 通过前面的图像特征介绍,我们知知道了角点的一个特性:向任何方向移动变化都很大Chris_Harris Mike_Stephens 在1988 年的文章《A Combined? Corner and Edge Detector》中就已经提出了焦点检测的方法被称为Harris 角点检测。Harris角点检测算法基于图像中角点的局部特征,通过计算每个像素点的响应函数来确定是否为角点。其原理如下:

  1. 图像梯度计算:首先对灰度图像进行梯度计算,常用的方法是使用Sobel算子计算图像在x和y方向上的梯度。
  2. 自相关矩阵计算:对于每个像素点,根据其周围的梯度值计算自相关矩阵,即计算该点的x方向梯度的平方和、y方向梯度的平方和以及x方向梯度与y方向梯度的乘积。
  3. Harris响应函数计算:根据自相关矩阵计算Harris响应函数,其定义为R = det(M) - k * trace(M)^2,其中M为自相关矩阵,det(M)为其行列式,trace(M)为其迹,k为一个经验参数。
  4. 非极大值抑制:对于计算得到的响应函数图像,对于局部最大值点保留,其余点设为0,以消除重复检测的角点。
  5. 阈值化:根据设定的阈值,将响应函数图像中低于阈值的点排除,以得到最终的角点位置。

????????Harris角点检测算法的基本思想是,角点处图像灰度变化明显,梯度方向变化也明显。因此,在角点处,自相关矩阵的特征值较大,而在非角点处,特征值较小。通过计算自相关矩阵的特征值来判断是否为角点,同时通过Harris响应函数的计算来量化角点的重要性。把这个思想换成数学形式,将窗口向各个方向移动(u,v)然后计算所有差异的总和。公式如下:

窗口函数可以是正常的矩形窗口也可以是对每一个像素给予不同权重的高斯窗口,角点检测中使E (μ, ν) 的值最大。就是必需要使方程右侧的第二项的取值最大。对上面的等式进行泰勒级数展开然后再进行几步数学换算(可以参考其他标准教材)我们得到下面的等式:

这里的 Ix 和Iy 是图像在x 和y 方向的导数。可以使用函数cv2.Sobel()计算得到。然后就是主要部分了。他们根据一个用来判定窗口内是否包角点的等式进行打分。?

?可以用下图来表示我们的结论:

????????所以Harris角点检测的结果是一个由角点分数构成的灰度图像。选取适当的阈值对结果图像进行二值化我们就检测到了图像中的角点。?

Harris角点检测步骤?

????????Harris角点检测是一种经典的图像处理算法,用于检测图像中的角点。角点是图像中局部区域的重要特征点具有很强的边缘信息。Harris角点检测算法通过计算图像中每个像素点的响应函数,来确定是否为角点。

以下是Harris角点检测的基本步骤:

1.灰度化:将彩色图像转换为灰度图像,以便进行后续处理。
2.计算图像梯度:使用Sobel等算子计算图像在x和y方向上的梯度。
3.计算梯度积方向矩阵:根据梯度计算每个像素点的自相关矩阵。
4.计算角点响应函数:对于每个像素点,根据自相关矩阵计算Harris响应函数。
5.非极大值抑制:在响应函数图像中,对于局部最大值点保留,其余点设为0。
6.阈值化:根据设定的阈值,将响应函数图像中低于阈值的点排除。
7.记录角点位置:根据阈值化后的响应函数图像,记录剩余点的位置,即为角点。

????????Harris角点检测算法的优点是简单高效,可以在实时或近实时的应用中使用。它在计算机视觉、图像处理和模式识别等领域中广泛应用,例如特征匹配、目标跟踪、图像拼接等。

OpenCV中角点检测实现

????????cv2.cornerHarris()函数是OpenCV中用于进行Harris角点检测的函数,其用法如下:

cv2.cornerHarris(src, blockSize, ksize, k, dst=None, borderType=None)

参数说明:

  • src:输入图像,灰度图像,数据类型为float32。
  • blockSize:角点检测中使用的邻域大小,一般为2、3、4等奇数,默认值为3。
  • ksize:Sobel算子的大小,一般为3,默认值为3。
  • k:Harris角点检测方程中的自由参数,一般取值为0.04到0.06,默认值为0.04。
  • dst:输出图像,与输入图像大小相同,数据类型为float32。
  • borderType:像素的边界模式,可选参数,默认值为cv2.BORDER_DEFAULT。

????????该函数返回的dst图像是一个与输入图像大小相同的角点响应图像,其中每个像素点的值表示该点的Harris响应函数值。

使用示例:

import cv2
import numpy as np

# 读取图像并转换为灰度图像
image = cv2.imread('chessboard.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

gray = np.float32(gray)

# 计算Harris角点响应图像,最后一个参数在0.04 到0.06之间
dst = cv2.cornerHarris(gray, 2, 3, 0.04)

#dst = cv2.dilate(dst,None)

# 对响应图像进行阈值化,得到角点位置
threshold = 0.01 * dst.max()
corners = np.where(dst > threshold)

# 在图像上标记检测到的角点
image[corners] = [0, 0, 255]  # 标记为红色

# 显示结果图像
cv2.imshow('Corners', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

在以上示例中,我们首先读取图像并将其转换为灰度图像,然后使用cv2.cornerHarris()函数计算Harris角点响应图像。接着,我们对响应图像进行阈值化,得到角点位置,并在原始图像上标记检测到的角点,最后显示结果图像。

?

亚像素级精确度的角点检测

????????有时我们需要最大精度的􄎁角点检测。OpenCV 为我们提供了函数cv2.cornerSubPix(),它可以提供亚像素级别的角点检测。下面是一个例子。首先我们先找到Harris角点􈙽,然后将角点的重心传给这个函数进行修正。Harris 角点用红色像素标出,绿色像素是修正后的像素。在使用这个函数时我们需要定义一个迭代停止条件。当迭代次数达到或者精度条件满足后迭代就会停止。我们同样需要定义角点搜索的领域大小。

cv2.cornerSubPix()函数定义:

cv2.cornerSubPix(image, corners, winSize, zeroZone, criteria)

参数说明:

  • image:输入图像,灰度图像,数据类型为float32。
  • corners:角点位置的数组,每个角点由一个二维坐标表示,数据类型为float32。
  • winSize:搜索窗口的大小,一般为二元组(width, height),默认值为(11, 11)。
  • zeroZone:死区的大小,一般为二元组(width, height),默认值为(-1, -1)。
  • criteria:角点搜索的停止准则,包含最大迭代次数和最大误差值。默认值为(30, 0.01)。

该函数会使用亚像素级别的优化方法,在指定的搜索窗口内对角点进行迭代搜索,以获得更精确的角点位置。

使用示例:

import cv2
import numpy as np

# 读取图像并转换为灰度图像
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 计算Harris角点响应图像
dst = cv2.cornerHarris(gray, 2, 3, 0.04)

# 对响应图像进行阈值化,得到角点位置
threshold = 0.01 * dst.max()
corners = np.where(dst > threshold)

# 使用亚像素级别的角点精确定位
corners = np.float32(np.transpose(corners))
cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01))

# 在图像上标记检测到的角点
for corner in corners:
    x, y = corner.ravel()
    cv2.circle(image, (x, y), 3, (0, 0, 255), -1)

# 显示结果图像
cv2.imshow('Corners', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

????????在以上示例中,我们首先读取图像并将其转换为灰度图像,然后使用cv2.cornerHarris()函数计算Harris角点响应图像。接着,我们对响应图像进行阈值化,得到角点位置,并将角点位置转换为float32类型的数组。然后,我们使用cv2.cornerSubPix()函数对角点进行亚像素级别的精确定位。最后,在原始图像上标记检测到的角点,并显示结果图像。

结果如下,为了方便查看我们对角点的部分进行了放大:

?

文章来源:https://blog.csdn.net/mzl_18353516147/article/details/135239328
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。