Moravec算子
说白了就是求两个像素点之间的差,然后平方一下给它变成正值。
其中,x,y表示像素点,u、v表示水平竖直方向的偏移量;w(x,y)为滤波函数,一般直接等于常数1。 I(x+u,x+v)、I(x,y )表示像素点(x+u,x+v)、(x,y)的灰度值。
Harris算子
将moravec算子进一步推导,根据泰勒展开,仅保留二阶项的公式为:
把上面公式带入moravec算子中,得到:
Ix和Iy就是我们讲边缘检测时候的水平竖直梯度,可以用sobel算子作为滤波器进行计算。
再进一步简化公式,变成矩阵形式:
我们令
接下来,我们对一个窗口的角点进行打分,通过公式:
λ1、λ2表示M的特征值。特征值表示2个方向上的变化(变化最快和最慢的方向),特征值大变化快,特征值小变化慢;k是一个常数值,人为设定
(1)若λ1、λ2都很小,接近于0,那么R也不大,这样的区域就是平坦区域。
(2)若一个大,一个小(接近于0),那么R<0,这样是边缘区域。
(3)若两个都很大,这样就是角点区域。
这个我们可以用一个形象的图像来举例子:
这有个图,是一个矩形。我们选择最左边那条边的一个点,然后向上移动。
我们会发现,在这条线上面的任意一个点,Y方向的像素值没有变化,而X方向移动一格,像素值变化很大。这就说是(2)的情况,也就是特征值一个大一个小。也就是边缘。
我们一直移动,直到如下图的绿色点:
这一点Y方向、X方向移动一格,像素值都变化很大,所以这个点是(3)情况,特征值两个都大,是角点。
我们把绿色的点再往上面移动,我们会发现像素都是白色了,Y方向、X方向移动一格,像素值都毫无变化,这就是(1)的情况,是平坦区域。
实战
输入
最后奉上代码:
import cv2
import numpy as np
#导入图片
img = cv2.imread('chessboard.png')
#显示图片
cv2.namedWindow("origin", cv2.WINDOW_NORMAL)
cv2.imshow('origin',img)
#转换为灰度图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
#Harris角点检测,2表示u,v的值,3表示sobel卷积核是3*3的,0.03为k值
dst = cv2.cornerHarris(gray,2,3,0.03)
# 膨胀一下角点,使得更清晰
dst = cv2.dilate(dst,np.ones((15, 15), np.uint8))
# 设定阈值为0.01*角点里面的最大值,小于的角点都舍去
img[dst>0.01*dst.max()]=[0,0,255]
#显示图片
cv2.namedWindow("dst", cv2.WINDOW_NORMAL)
cv2.imshow('dst',img)
#按任意键结束
cv2.waitKey()
cv2.destroyAllWindows()