一. Harris基本原理
Harris算子是一种基于信号的点特征提取算子,它是对Moravec算子的改进。其基本思想是:在图像中设计一个局部
检测窗口,当该窗口沿各个方向做微小移动时,考察窗口的平均能量变化,当该能量变化超过设定的阈值时,就将窗
口的中心像素点提取为角点。
二. Harris计算过程
Harris算子数学方程,如下所示:
进行泰勒级数展开等,矩阵形成如下所示:
其中,
和
是图像在
和
方向的导数,可使用cv2.Sobel()计算结果。
根据一个用来判定窗口内是否包含角点的等式进行打分。如下所示:
其中,
,
,
和
是矩阵
的特征值。
根据这些特征值,可以判断一个区域是否是角点,边界或者是平面,如下所示:
1. 当
和
都小时,
也小,表示这个区域是一个平坦区域。2. 当
或
时,
小于0,表示这个区域是边缘。3. 当
和
都很大,并且
时,
也很大(
和
中的最小值都大于阈值),表示这个区域是角点。
Harris角点检测的结果是一个由角点分数构成的灰度图像,选取适当的阈值对结果图像进行二值化就检测到了图像中
的角点。
三. OpenCV中的Harris算子
函数原型:cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]]) → dst。其中,img表示数据类型为float32的
输入图像。blockSize表示角点检测中要考虑的领域大小。ksize表示Sobel求导中使用的窗口大小。k表示Harris角点检
测方程中的自由参数。
import cv2
import numpy as np
filename = '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()
结果输出,如下所示:
四. 亚像素级精确度的角点
OpenCV中的函数cv2.cornerSubPix()可以提供亚像素级别的角点检测。首先找到Harris角点,然后将角点的重心传给
该函数进行修正。Harris角点用红色像素标出,绿色像素是修正后的像素。如下所示:
import cv2
import numpy as np
filename = 'chessboard2.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)
为了方便查看对角点的部分进行了放大,如下所示:
1. cv2.connectedComponentsWithStats(OpenCV 3.X)
解析:函数原型int connectedComponentsWithStats(InputArray image, OutputArray labels, OutputArray stats,
OutputArray centroids, int connectivity=8, int ltype=CV_32S)。
2. cv2.cornerSubPix
解析:函数原型void cornerSubPix(InputArray image, InputOutputArray corners, Size winSize, Size zeroZone,
TermCriteria criteria)。
参考文献:
[1] A Combined Corner and Edge Detector
[2] Harris Corner Detection:http://docs.opencv.org/3.0-
beta/doc/py_tutorials/py_feature2d/py_features_harris/py_features_harris.html