【OpenCV 例程300篇】238. OpenCV 中的 Harris 角点检测

『youcans 的 OpenCV 例程300篇 - 总目录』


【youcans 的 OpenCV 例程 300篇】238. OpenCV 中的 Harris 角点检测

角是直线方向的快速变化。角点通常被定义为两条边的交点,或者说角点的邻域应该具有两个不同区域的不同方向的边界。

角是高度有效的特征。角点检测(Corner Detection)广泛应用于运动检测、图像匹配、视频跟踪、三维重建和目标识别。


6.1 哈里斯-斯蒂芬斯角检测器(Harris)

在基于灰度变换的角点检测算法中,Harris 算法重复性良好、检测效率较高,应用较为广泛。

哈里斯-斯蒂芬斯角检测器(Harris and Stephens)的原理是,通过检测窗口在图像上移动,计算移动前后窗口中像素的灰度变化。角点是两条边的交点,其特征是检测窗口沿任意方向移动都会导致灰度的显著变化。

对于点 ( x , y ) (x,y) (x,y),令 w ( x , y ) w(x,y) w(x,y) 为矩形检测窗口或高斯检测窗口, I ( x , y ) I(x,y) I(x,y) 是检测窗口在点 ( x , y ) (x,y) (x,y) 的灰度值, I ( x + u , y + v ) I(x+u,y+v) I(x+u,y+v) 是检测窗口滑动 ( u , v ) (u,v) (u,v) 距离之后的灰度值。

计算窗口 w ( x , y ) w(x,y) w(x,y) 滑动 ( u , v ) (u,v) (u,v) 距离之后的灰度变化:
E ( u , v ) = ∑ x , y w ( x , y ) [ I ( x + u , y + v ) − I ( x , y ) ] 2 E(u,v) = \sum _{x,y} w(x,y) [I(x+u, y+v) - I(x,y)]^2 E(u,v)=x,yw(x,y)[I(x+u,y+v)I(x,y)]2
对于很小的位移 ( u , v ) (u,v) (u,v),使用一阶泰勒展开进行简化:

E ( u , v ) = ∑ x , y w ( x , y ) [ I ( x , y ) + u I x + v I y + O ( u 2 , v 2 ) − I ( x , y ) ] 2 ≈ ∑ x , y w ( x , y ) [ u 2 I x 2 + 2 u v I x I y + v 2 I y 2 ] ≈ [ u , v ] ∑ x , y w ( x , y ) [ I x I x I x I y I x I y I y I y ] [ u v ] \begin{aligned}E(u,v) = &\sum_{x,y} w(x,y) [I(x,y) + uI_x + vI_y +O(u^2,v^2)- I(x,y)]^2 \\\approx & \sum_{x,y} w(x,y) [u^2 I_x^2 + 2uv I_x I_y + v^2 I_y^2] \\\approx & [u,v] \sum_{x,y}w(x,y)\begin{bmatrix}I_x I_x & I_x I_y \\I_x I_y & I_y I_y\end{bmatrix}\begin{bmatrix}u\\v\end{bmatrix}\end{aligned} E(u,v)=x,yw(x,y)[I(x,y)+uIx+vIy+O(u2,v2)I(x,y)]2x,yw(x,y)[u2Ix2+2uvIxIy+v2Iy2][u,v]x,yw(x,y)[IxIxIxIyIxIyIyIy][uv]
I x , I y I_x,I_y Ix,Iy 分别是在 x, y 方向的导数,可以由 Sobel 梯度算子求出。

记 M 为梯度的协方差矩阵:
M = ∑ x , y w ( x , y ) [ I x I x I x I y I x I y I y I y ] M =\sum_{x,y} w(x,y)\begin{bmatrix}I_x I_x & I_x I_y \\I_x I_y & I_y I_y\end{bmatrix} M=x,yw(x,y)[IxIxIxIyIxIyIyIy]

在几何模型中通过判断两个特征值的大小,来判定像素的属性。矩阵 M 是 I x , I y I_x,I_y IxIy 的二次函数,可以表示为椭圆形状,椭圆的长短半轴由矩阵 M 的特征值 λ 1 , λ 2 \lambda _1,\lambda _2 λ1λ2 决定,方向由特征向量决定。

定义角点响应函数 R:
R = d e t ( M ) − k [ t r a c e ( M ) ] 2 d e t ( M ) = λ 1 ∗ λ 2 t r a c e ( M ) = λ 1 + λ 2 \begin{aligned}R =& det(M) - k [trace(M)]^2 \\&det(M) = \lambda _1 * \lambda _2 \\&trace(M) = \lambda _1 + \lambda _2\end{aligned} R=det(M)k[trace(M)]2det(M)=λ1λ2trace(M)=λ1+λ2
k 是调节参数(通常取 0.04~0.06)。

角点响应函数 R 只与矩阵 M 的特征值 λ 1 , λ 2 \lambda _1,\lambda _2 λ1λ2 有关,可以用来判断区域是拐角、边缘还是平坦:

  • λ 1 , λ 2 \lambda _1,\lambda _2 λ1λ2 较小时, ∣ R ∣ |R| R 较小,即各个方向上灰度基本不变,表明检测器处于平坦区域;
  • λ 1 > > λ 2 \lambda _1 >> \lambda _2 λ1>>λ2 或 $ \lambda _2 >> \lambda _1$ 时, R < 0 R <0 R<0 ,即灰度在某个方向变化,但在其正交方向不变化,表明检测器处于边缘区域;
  • λ 1 , λ 2 \lambda _1,\lambda _2 λ1λ2 较大且 λ 1 ∼ λ 2 \lambda _1 \sim \lambda _2 λ1λ2时, ∣ R ∣ |R| R 很大,即灰度在所有方向都发生重大变化,表明检测器包含角点(或孤立点。

6.2 OpenCV 中的 Harris 角检测器

OpenCV 中提供了 Harris 角点检测函数 cv.cornerHarris()


函数说明:

cv.cornerHarris(src, blockSize, ksize, k[, dst=None, borderType=BORDER_DEFAULT]	) → dst
cv.cornerEigenValsAndVecs(src, blockSize, ksize[, dst=None, borderType=BORDER_DEFAULT]) → dst
cv.cornerMinEigenVal(src, blockSize[, dst=None, ksize=3, borderType=BORDER_DEFAULT]) → dst

函数 cv.cornerHarris 运行 Harris 角检测器。

函数 cv.cornerEigenValsAndVecs 计算图像矩阵的特征值和特征向量。

函数 cv.cornerMinEigenVal 计算用于角点检测的梯度矩阵的最小特征值。

对于每个像素 (x,y) 计算梯度协方差矩阵 M ( x , y ) M(x,y) M(x,y)。然后计算特征:
d s t ( x , y ) = d e t M ( x , y ) − k ⋅ ( t r M ( x , y ) ) 2 dst(x,y) = det M^{(x,y)} - k \cdot (tr M^{(x,y)})^2 dst(x,y)=detM(x,y)k(trM(x,y))2

则角点在特征响应图像中是局部极大值。 实践中定义当 R 大于设定阈值,且为局部最大值的点为角点 。

参数说明:

  • src:输入图像,单通道的 8位图像或浮点数图像
  • dst:输出图像,Harris 检测器的响应,大小与 src 相同,格式为 CV_32FC1
  • blockSize:邻域尺寸
  • ksize:Sobel 算子的孔径参数
  • k:Harris 检测器调节参数,通常取 0.04~0.06
  • borderType:边界扩充类型
    • cv.BORDER_CONSTANT
    • cv.BORDER_REPLICATE
    • cv.BORDER_REFLECT
    • cv.BORDER_REFLECT_101
    • cv.BORDER_TRANSPARENT

注意事项:

函数 cv.cornerMinEigenVal 类似于 cv.cornerEigenValsAndVecs,但它仅计算和保存矩阵 M 的最小特征值,即 m i n ( λ 1 , λ 2 ) min(\lambda_1, \lambda_2) min(λ1,λ2)


例程 14.19:特征检测之 Harris 角检测器

    # 14.19 角点检测之 Harris 算法
    img = cv2.imread("../images/Chess01.png", flags=1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # (600, 540)
    # gray = np.float32(gray)  # uint8,float32 都支持

    blockSize = [2, 3, 5]  # 滑动窗口大小
    ksize = [3, 5, 9]  # Sobel 核函数大小
    plt.figure(figsize=(9, 9))
    for i in range(len(blockSize)):
        for j in range(len(ksize)):
            dst = cv2.cornerHarris(gray, blockSize[i], ksize[j], k=0.04)
            imgCorner = np.copy(img)
            imgCorner[dst > 0.01*dst.max()] = [0, 0, 255]  # 筛选角点,红色标记
            plt.subplot(3,3,i*len(ksize)+j+1), plt.axis('off')
            plt.imshow(cv2.cvtColor(imgCorner, cv2.COLOR_BGR2RGB))
            plt.title("blockSize={},ksize={}".format(blockSize[i], ksize[j]))

    plt.tight_layout()
    plt.show()

在这里插入图片描述


【本节完】

版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/125820758)
Copyright 2022 youcans, XUPT
Crated:2022-7-15

238. OpenCV 中的 Harris 角点检测
239. Harris 角点检测之精确定位(cornerSubPix)
240. OpenCV 中的 Shi-Tomas 角点检测

猜你喜欢

转载自blog.csdn.net/youcans/article/details/125820758
今日推荐