一、原理
对于一幅图像内的边界与角点,边界的特征是其边界的灰度级沿着水平或者竖直方向其中之一变化特别迅速,而另一方向变化则比较缓慢。而角点则是沿着两个方向的灰度级变化都比较明显。
在定位角点的过程中,使用自相关函数来判断平移后的窗口与原来灰度变化的差异性,也就说选取图像某一部分然后将其沿着某一方向平移,通过其相关性函数来判断当前所选择的区域是平面还是角点还是边界。(平面的话无论沿那个方向移动,其灰度级变化都不是很明显)。
详细的数学推导这里不再解释,通过数学变换自相关函数整理成一个对角矩阵形式,并使其近似于一个两个特征值的特征值矩阵。然后通过判断特征值矩阵的特征情况,就可以对当前选定的区域进行判断。
边界特点:一个特征值大,一个小。自相关函数在某一方向上增大,在其他方向上减小。
平面特点:两个特征值都比较小,且近似相等。自相关函数在各个方向上都比较小。
角点特点:两个特征值都大,且近似相等。自相关函数在所有方向都增大。
根据三个边界特点,求出一个R值角点响应来进一步作为判别依据:
R = a 1 a 2 − α ( a 1 + a 2 ) 2 R = a1a2 - \alpha(a1+a2)^2 R=a1a2−α(a1+a2)2
a1,a2表示两个特征值,根据上面的特点,得知若为边界,那么边界对应R>0, 平面R≈0(很小), 角点<0。由此,可根据R值来很好的判断边界。
二、函数使用
cv2.cornerHarris()
参数:
img:传入图片
blockSize:角点检测中指定区域的大小
ksize:Sobel求导中使用的窗口大小
k:就是上式子中的α,取值为[0.04, 0.06]
代码如下:
def corner():
"""
角点检测
:return:
"""
img = cv.imread('img.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
dst = cv.cornerHarris(gray, 2, 3, 0.04)
print(dst.shape, img.shape)
# 获取角点的索引,0.1为一个超参数,越大其获取到的角点越少,角点越大。将角点绘制为红色
img[dst>0.1*dst.max()] = [0, 0, 255]
cv_show(img)