1. Harris 角点检测
Harris 角点检测通过图像的一个小部分窗口观察图像。角点的特点是窗口向任意方向移动都会引起图像灰度的显著变化。
将上述思想转化为数学形式,即将局部窗口向各个方向移动(u,v),计算所有灰度差的总和。
其中 I(x,y) 是局部窗口的图像灰度, I(x+u,y+v) 为平移后的图像灰度,w(x,y) 是窗口函数。窗口可以是矩形窗口,也可以是为每个像素分配不同权重的高斯窗口,如下图:
在角点检测中,E(u,v) 的值被最大化。 使用一阶泰勒展开式:
其中 Ix 和 Iy 沿着 x 和 y 方向的导数可以用sobel算子计算。 推导如下:
M 矩阵确定 E(u,v) 的值。 下面我们使用 M 来寻找角点。 M 是 Ix 和 Iy 的二次项函数,可以用椭圆来表示。 椭圆的长短半轴由M的特征值λ1和λ2决定,方向由特征向量决定,如下图:
Harris 给出的角点计算方法不需要计算具体的特征值,而是计算一个角点响应值R来判断角点。 R的计算公式为:
其中detM是矩阵M的行列式,traceM 是矩阵 M 的迹,α为常数,取值范围为0.04~0.06。
由于:
特征值隐含在detM和traceM中。
如下图所示:
当R为正数且取值较大时为角点;当 R 为负数且绝对值较大时为边界;当 R 是较小的数时为平坦区域。
cv.cornerHarris(src, blockSize, ksize, k)
参数:
img 输入图像,数据类型为 float32。
blockSize 角点检测中要考虑的邻域大小
ksize sobel求导使用的核大小
k 角点检测方程中的自由参数,取值参数为 [0.04,0.06]。
Harris 角点检测的优点:
旋转不变性,椭圆旋转一定角度但形状保持不变,特征值保持不变。 图像灰度级的仿射变化是部分不变的。 因为只使用了图像的一阶导数,所以图像灰度平移变化不变,图像灰度尺度变化不变。
Harris 角点检测的缺点: 它对尺度非常敏感,不具有几何尺度不变性。提取的角点是像素级的。
2. Shi-Tomasi算法
Shi-Tomasi算法是Harris角点检测算法的改进。Harris 算法的角点响应函数是从矩阵 M 的行列式值 中减去 M 的迹,利用差值来判断是否为角点。 后来Shi和Tomasi提出了一种改进方法,如果矩阵M的两个特征值中较小的一个大于阈值,则认为是角点,即R=min(λ1,λ2)。如下图所示:
可以看出,只有当λ1和λ2均大于最小值时,才认为是角点。
cv.goodFeaturesToTrack(image, maxcorners, qualityLevel, minDistance)
参数:
image 输入灰度图像
maxcorners 获取角点数的数目
qualityLevel 该参数指出最低可接受的角点质量水平,在0-1之间。
minDistance 角点之间最小的欧氏距离,避免得到相邻特征点。
返回值:
搜索到的角点。
3. SIFT 算法
SIFT 算法的本质是在不同尺度空间中寻找关键点(特征点)并计算关键点的方向。 SIFT查找到的关键点是一些非常突出的点,不会因为光照、仿射变换和噪声等因素而改变,比如角点、边缘点、暗区的亮点、亮区的暗点。
SIFT算法可以分解为以下四个步骤:
1)尺度空间极值检测:在所有尺度上搜索图像位置。通过高斯差分函数识别对尺度和旋转不变的潜在关键点。
2)关键点定位:在每个候选位置,使用一个精细拟合的模型来确定位置和尺度。关键点的选择取决于它们的稳定性程度。
3)关键点方向确定:根据图像的局部梯度方向,为每个关键点位置分配一个或多个方向。所有后续对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,从而保证了这些变换的不变性。
4)关键点描述:在每个关键点周围的邻域内,在选定的尺度上测量图像的局部梯度。这些梯度用作关键点描述符,允许相对较大的局部形状变形或光照变化。
cv.xfeatures2d.SIFT_create()
返回值:SIFT对象
sift.detectAndCompute(gray)
参数:
gray 进行关键点检测的灰度图像
返回值:
kp 关键点信息,包括位置,尺度,方向信息。
des 关键点描述符,每个关键点对应128个梯度信息的特征向量。
cv.drawKeypoints(image, keypoints, outputimage, color, flags)
参数:
image 原始图像
keypoints 关键点信息,将其绘制在图像上。
outputimage 输出图片,可以是原始图像。
color 颜色设置,通过修改(b, g, r)的值,更改画笔的颜色。
flags 绘图功能的标识设置:
cv.DRAW_MATCHES_FLAGS_DEFAULT 创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征点,对每一个关键点只绘制中间点 。
cv.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG 不创建输出图像矩阵,而是在输出图像上绘制匹配对。
cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS 对每一个特征点绘制带大小和方向的关键点图形。
cv.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS 单点的特征点不被绘制。
例:对下面的图像使用Harris、Shi-Tomas和SIFT方法检测角点。
import matplotlib
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
font = {
"family": "Microsoft YaHei"
}
matplotlib.rc("font", **font)
img = cv.imread("./image/tv.jpg")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
gray_32 = np.float32(gray)
# Harris
dst = cv.cornerHarris(gray_32, 2, 3, 0.04)
# 绘制角点
img[dst > 0.001 * dst.max()] = [0, 0, 255]
plt.imshow(img[:, :, ::-1])
plt.title("Harris角点检测")
plt.show()
# Shi-Thomas
corners = cv.goodFeaturesToTrack(gray, 1000, 0.01, 10)
# 绘制角点
for i in corners:
x, y = i.ravel()
cv.circle(img, (x, y), 2, (0, 0, 255), -1)
plt.imshow(img[:, :, ::-1])
plt.title("Shi-Thomas角点检测")
plt.show()
# SIFT
sift = cv.xfeatures2d.SIFT_create()
kp, des = sift.detectAndCompute(gray, None)
# 绘制角点
cv.drawKeypoints(img, kp, img, flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
plt.imshow(img[:, :, ::-1])
plt.title("SIFT角点检测")
plt.show()
输出: