在学习时主要参考了1.http://blog.csdn.net/xiaowei_cqu/article/details/7805206和opencv-python官方的关于harris的文档(http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_features_harris/py_features_harris.html#harris-corners)。
1.原理
对于角点的检测,harris依据一下直观判断:角点应该在窗口的各个方向都有变化,而边界会在某个方向基本不变,而平坦区域在各个方向变化都小。
因此我们要衡量在某个方向上的变化大小,定义
E(u,v) = \sum_{x,y} w(x,y)~[I(x+u, y+v) - I(x,y)]^2
其中,w(x,y)是窗口函数;向量[u, v]表示某个方向,以及在该方向上的位移。由以上公式可知,E(u,v)表示在某个方向上图像灰度的变化。我们首先要研究在那个方向上,灰度变化最大(即令E(u,v)最大)。求解这个问题,我们通过泰勒展开公式(二元公式为:)可以得到:
记上式最后的结果为,则我们可以得到:
注意这个推导过程在http://blog.csdn.net/xiaowei_cqu/article/details/7805206中有一步是错误的!
这时我们知道找两个特征值中较大的对应的特征方向就是变化较大的方向。
但是我们考虑的问题不是得到窗口沿[u,v]移动变化最大,而是要衡量这个窗口内各个方向变化是否大。这就需要用特征值来衡量。
直观上考虑:
都小 : 区域平坦;
: 边界
且都大:角点
基于以上原理,我们定义
这时,
R小,说明两个特征值都小,对应区域平坦;
R<0,说明,对应边界;
R大,说明且都大,对应角点。
所以可以用R>阈值作为条件判断是否是角点。
2.python代码
关键命令是:cv2.cornerHarris(src, blocksize, ksize, k [, dst [, borderType ]]) -> dst
参数如下:
ksize:Sobel的孔径参数(aperture parameter),也就是Sobel核的半径,如1、3、5、7
k:R公式中的k,默认取0.04
blocksize:窗口大小,示例中取2
【python代码如下】
import cv2
import numpy as np
#读入图像并转化为float类型,用于传递给harris函数
filename = 'Dirk.jpg'
img = cv2.imread(filename)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray_img = np.float32(gray_img)
#对图像执行harris
Harris_detector = cv2.cornerHarris(gray_img, 2, 3, 0.04)
#膨胀harris结果
dst = cv2.dilate(Harris_detector, None)
# 设置阈值
thres = 0.01*dst.max()
img[dst > thres] = [255,0,0]
cv2.imshow('show', img)
cv2.waitKey()