8.2. 哈里斯角点检测

8.2.1. 目标

在本章中,

  • 我们将了解哈里斯角检测背后的概念。

  • 我们将看到以下功能: 柯纳哈里斯2号()cv2.角点组件()

8.2.2. 理论

在最后一章中,我们看到角是图像中各个方向强度变化较大的区域。一个早期的寻找这些角落的尝试是由 克里斯哈里斯和迈克斯蒂芬斯 在他们的报纸上 一种组合式角边缘检测器 1988年,现在它被称为哈里斯角探测器。他把这个简单的想法变成了数学形式。它基本上发现了 \((u,v)\) 四面八方。具体表现为:

\[E(u,v) = \sum_{x,y} \underbrace{w(x,y)}_\text{window function} \, [\underbrace{I(x+u,y+v)}_\text{shifted intensity}-\underbrace{I(x,y)}_\text{intensity}]^2\]

窗口函数可以是矩形窗口,也可以是高斯窗口,它为下面的像素赋予权重。

我们必须最大化这个功能 \(E(u,v)\) 用于拐角检测。也就是说,我们必须使第二项最大化。将泰勒展开式应用于上述方程,并使用一些数学步骤(请参考您喜欢的任何标准教科书进行完整推导),我们得到最终方程如下:

\[开始{aligned}E(u,v)大约{bmatrix}u&vend{bmatrix}Mbegin{bmatrix}u\vend{bmatrix}end{aligned}\]

在哪里?

\[开始{aligned}M=sum{x,y}w(x,y)begin{bmatrix}I_xi_xi_xi_xi_xi_xy \I_xi_yi_uy I_xi_xi_xi_xi_xi_xi_xy \end{aligned}\]

在这里, \(I_x\)\(I_y\) 分别是x和y方向的图像导数。(使用 第二节索贝尔()

接下来是主要部分。在这之后,他们创建了一个分数,基本上是一个等式,它将决定一个窗口是否可以包含一个角。

\[R=det(M)-k(trace(M))^2\]
在哪里?
- \(det(M) = \lambda_1 \lambda_2\) - \(trace(M) = \lambda_1 + \lambda_2\) - \(\lambda_1\) and \(\lambda_2\) are the eigen values of M

因此,这些特征值的值决定了区域是角点、边还是平面。

  • 什么时候? \(|R|\) 很小,当 \(\lambda_1\)\(\lambda_2\) 很小,区域很平坦。

  • 什么时候? \(R<0\) ,当 \(\lambda_1 >> \lambda_2\) 反之亦然,区域是边缘。

  • 什么时候? \(R\) 很大,当 \(\lambda_1\)\(\lambda_2\) 很大而且 \(\lambda_1 \sim \lambda_2\) ,区域是一个角。

它可以用一幅很好的图画来表示,如下所示:

因此Harris角点检测的结果是一幅灰度图像。一个合适的阈值给你在图像的角落。我们将用一个简单的图像来做。

8.2.3. OpenCV中的Harris角点检测器

OpenCV具有 柯纳哈里斯2号() 为此目的。其论点是:

  • img -输入图像,应为灰度和浮点32型。

  • 块大小 -它是用于角点检测的邻域大小

  • 大小 -使用索贝尔导数的孔径参数。

  • k -方程中的Harris检测器自由参数。

请参见下面的示例:

>>> %matplotlib inline
>>>
>>> import cv2
>>> import numpy as np
>>>
>>> filename = '/cvdata/chessboard.jpg'
>>> img = cv2.imread(filename)
>>> gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
>>>
>>> gray = np.float32(gray)
>>> dst = cv2.cornerHarris(gray,2,3,0.04)
>>>
>>> #result is dilated for marking the corners, not important
>>> dst = cv2.dilate(dst,None)
>>>
>>> # Threshold for an optimal value, it may vary depending on the image.
>>> img[dst>0.01*dst.max()]=[0,0,255]
>>>
>>> # cv2.imshow('dst',img)
>>> # if cv2.waitKey(0) & 0xff == 27:
>>> #     cv2.destroyAllWindows()
>>>
>>> import matplotlib.pyplot as plt
>>> plt.imshow(img)
<matplotlib.image.AxesImage at 0x7fa834f29f28>
../_images/sec02-features-harris_2_1.png
>>> plt.imshow(dst)
<matplotlib.image.AxesImage at 0x7fa834e97080>
../_images/sec02-features-harris_3_1.png

以下是三个结果:

8.2.4. 亚像素精度角点

有时,您可能需要以最大的精度找到拐角。OpenCV带有一个函数 cv2.角点组件() 它进一步细化了亚像素精度检测到的角点。下面是一个例子。像往常一样,我们需要先找到哈里斯角。然后我们通过这些角的质心(一个角上可能有一堆像素,我们取它们的质心)来细化它们。Harris角点用红色像素标记,精制角点用绿色像素标记。对于这个函数,我们必须定义停止迭代的条件。我们在指定的迭代次数或达到一定的精度后停止它,以先发生的为准。我们还需要定义它将搜索角落的邻居的大小。

>>> import cv2
>>> import numpy as np
>>>
>>> filename = '/cvdata/chessboard.jpg'
>>> img = cv2.imread(filename)
>>> gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
>>>
>>> # find Harris corners
>>> gray = np.float32(gray)
>>> dst = cv2.cornerHarris(gray,2,3,0.04)
>>> dst = cv2.dilate(dst,None)
>>> ret, dst = cv2.threshold(dst,0.01*dst.max(),255,0)
>>> dst = np.uint8(dst)
>>>
>>> # find centroids
>>> ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)
>>>
>>> # define the criteria to stop and refine the corners
>>> criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
>>> corners = cv2.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria)
>>>
>>> # Now draw them
>>> res = np.hstack((centroids,corners))
>>> res = np.int0(res)
>>> img[res[:,1],res[:,0]]=[0,0,255]
>>> img[res[:,3],res[:,2]] = [0,255,0]
>>>
>>> cv2.imwrite('subpixel5.png',img)
True

下面是结果,其中一些重要位置显示在缩放窗口中以进行可视化:

8.2.5. 额外资源

8.2.6. 练习