OpenCV-Python教程:34.Harris角点检测

理论

我们知道角点是图像里在各个方向变化最大的区域。早起尝试找到这些角的是Chris Harris和Mike Stephens,在他们的论文A Combined Corner and Edge Detector里,所以现在叫Harris角点检测。他把这个简单想法用数学形式表达,基本上就是对(u,v)在各个方向移动找强度的变化。表达式如下:

Window function是一个矩形窗口或者高斯窗口,给其下的像素权重。

我们应该最大化这个函数E(u, v)来检测角点。这表示,我们应该放大第二个条件,应用泰勒展开上面的等式,然后经过数学步骤,我们可以得到最终的等式:

其中



这里,Ix 和Iy 是图像在x和y方向分别的导数(可以用cv2.Sobel()很容易得到)

然后是主要部分,在这个之后,它们创建了一个分数,基本上市一个等式,来决定一个窗口是否能包含一个角。


其中:

·det(M) = λ1λ2

·trace(M) = λ1 + λ2

·λ1和λ2是M的特征值

所以这些特征值决定了区域是否是角,边缘或者无反差的。

·当|R|小的时候,也就是λ1和λ2小的时候,区域是无反差的

·当R < 0, 页就是λ1 >> λ2时,区域是边缘

·当R很大,是λ1和λ2很大并且λ1 ~ λ2时区域是角

可以用图片来表示:

OpenCV-Python教程:34.Harris角点检测_第1张图片

所以Harris角点检测是一个有这些分数的灰度图,用一个合适的阈值你就可以得到图像的角。

OpenCV里的Harris角点检测

OpenCV有一个函数cv2.cornerHarris()来做这个,参数是:

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-Python教程:34.Harris角点检测_第2张图片

有时候,你可能需要更准确的找到角,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)

下面是结果,一些重要的位置放大显示了:

OpenCV-Python教程:34.Harris角点检测_第3张图片

END

你可能感兴趣的:(OpenCV-Python教程:34.Harris角点检测)