Python - opencv (九)角点检测
参考:https://blog.csdn.net/poem_qianmo/article/details/29356187
https://zhuanlan.zhihu.com/p/68571164
在图像处理和与计算机视觉领域,兴趣点(interest points),或称作关键点(keypoints)、特征点(feature points) 被大量用于解决物体识别,图像识别、图像匹配、视觉跟踪、三维重建等一系列的问题。我们不再观察整幅图,而是选择某些特殊的点,然后对他们进行局部有的放矢的分析。如果能检测到足够多的这种点,同时他们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就有使用价值。
图像特征类型可以被分为如下三种:
<1>边缘
<2>角点 (感兴趣关键点)
<3>斑点(Blobs)(感兴趣区域)
其中,角点是个很特殊的存在。他们在图像中可以轻易地定位,同时,他们在人造物体场景,比如门、窗、桌等出随处可见。因为角点位于两条边缘的交点处,代表了两个边缘变化的方向上的点,,所以他们是可以精确定位的二维特征,甚至可以达到亚像素的精度。且其图像梯度有很高的变化,这种变化是可以用来帮助检测角点的。需要注意的是,角点与位于相同强度区域上的点不同,与物体轮廓上的点也不同,因为轮廓点难以在相同的其他物体上精确定位。
1. Harris
将窗口向各个方向 移动(u , v)然后计算所有差异的总和。表达式如下:
数学转换后:
其中:
和 是图像在 x 和 y 方向的导数(可以用函数cv2.Sobel()
计算得到).
最终,根据一个用来判定窗口内是否包含角点的等式进行打分:
其中:
- 。
- 。
- 和 是矩阵 M 的特征值。
我们根据这些特征来判断一个区域是角点,边界还是平面: - 当 和 都小时, 也小,则为平面区域。 - 当 或者 时,R小于0,则为边缘。 - 当 和 都很大时,且 中时,R也很大,( 和 中的最小值都大于阈值),则为角点。
如图所示:
代码:
cv2.cornerHarris()
可以用来进行角点检测,参数如下:
- img - 输入图像。
- blockSize - 角点检测中领域像素的大小。
- ksize - Sobel 求导中使用的窗口大小
- k - Harris 角点检测方程中的自由参数,取值参数为 [0,04,0.06]
示例:
将一个棋盘作为输入,来计算它的角点:
代码:
1 import numpy as np 2 import cv2 3 4 def harris(image, opt=1): 5 # Detector parameters 6 blockSize = 2 7 apertureSize = 3 8 k = 0.04 9 10 # Preprocess 11 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 12 ret, thresh1 = cv2.threshold(gray,65,255,cv2.THRESH_BINARY) 13 ret = cv2.morphologyEx(thresh1, cv2.MORPH_OPEN, np.ones((5,5), np.uint8)) 14 15 # Detecting corners 16 dst = cv2.cornerHarris(ret, blockSize, apertureSize, k) 17 image[dst>0.1*dst.max()]=[0,0,255] 18 return image
结果:
2. Shi-thomas
✔️ Shi-Tomas是源于《Good Features to Track》,其中对Harris角点检测算法改进后的新算法。
✔️ Shi-Tomas使用的打分函数为:
如果打分超过阈值,则认为它是一个角点,只有当 和 都大于之最小值,才可以被认为是角点(绿色区域)
代码:
1 def shi_thomas(image, opt=1): 2 # Detecting corners 3 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 4 ret, thresh1 = cv2.threshold(gray,65,255,cv2.THRESH_BINARY) 5 ret = cv2.morphologyEx(thresh1, cv2.MORPH_OPEN, np.ones((5,5), np.uint8)) 6 corners = cv2.goodFeaturesToTrack(ret, 80, 0.05, 10) 7 print(len(corners)) 8 for pt in corners: 9 print(pt) 10 b = np.random.random_integers(0, 256) 11 g = np.random.random_integers(0, 256) 12 r = np.random.random_integers(0, 256) 13 x = np.int32(pt[0][0]) 14 y = np.int32(pt[0][1]) 15 cv2.circle(image, (x, y), 5, (int(b), int(g), int(r)), 2) 16 # output 17 return image
用cornerSubPix可以令goodFeaturesToTrack效果更出色。