原文作者:aircraft
原文地址:https://www.cnblogs.com/DOMLX/p/8763369.html
参考文献----------OpenCV-Python-Toturial-中文版.pdf
参考博客----------http://www.bubuko.com/infodetail-2498014.html
不废话进入主题:
角点是一类具有特定特征的点,角点也是处在一个无论框框往哪边移动 框框内像素值都会变化很大的情况而定下来的点 可以这么去理解。。。。
如上图有三个颜色的框框,如果我们对蓝色框框进行移动,无论是水平 还是垂直的方向移动 都不会对框框内像素造成很大的变化。。。这种是内部区域
如果我们对黑色的框框进行移动,那么水平方向上移动 像素值是不会有什么太大的变化的 如果是垂直方向上移动那么就会变化很大 这种一般称为边缘区域
最后的重点 我们对红色的框框进行移动 无论是往哪个方向进行偏移 都会对框框内的像素值 造成很大的变动 那么红色框框 框住的区域的边角点 我们就称为角点
通过以上的几句话 我们大家应该大概的理解了角点是什么意思了、、、、
就这样一直说下去 解释下去 肯定是比较枯燥的 大家估计都是想先看看这个cv2.cornerHarris()函数的作用是什么。。。那么我们就先来看看成果图 在解释过程
那些红色的 绿色的就是通过我们函数圈出来的角点。。。
下面就解释一下原理 后面会给出简单的示例代码
在 1988 年的文章《A CombinedCorner and Edge Detector》中就已经提出了焦点检测的方法,被称为Harris 角点检测。他把这个简单的想法转换成了数学形式。将窗口向各个方向移动(u,v)然后计算所有差异的总和。表达式如下:
窗口函数可以是正常的矩形窗口也可以是对每一个像素给予不同权重的高斯窗口
角点检测中要使 E (μ,ν) 的值最大。这就是说必须使方程右侧的第二项的取值最大。对上面的等式进行泰勒级数展开然后再通过几步数学换算(可以参考其他标准教材),我们得到下面的等式:
其中
这里 I x 和 I y 是图像在 x 和 y 方向的导数。(可以使用函数 cv2.Sobel()
计算得到)。
然后就是主要部分了。他们根据一个用来判定窗口内是否包含角点的等式进行打分。
其中
? λ 1 和 λ 2 是矩阵 M 的特征值所以根据这些特征中我们可以判断一个区域是否是角点,边界或者是平面。
? 当 λ 1 和 λ 2 都小时,|R| 也小,这个区域就是一个平坦区域。
? 当 λ 1 ? λ 2 或者 λ 1 ? λ 2 ,时 R 小于 0,这个区域是边缘
? 当 λ 1 和 λ 2 都很大,并且 λ 1 ~λ 2 中的时,R 也很大,(λ 1 和 λ 2 中的最小值都大于阈值)说明这个区域是角点。
可以用下图来表示我们的结论:
cv2.cornerHarris()函数的返回值其实就是R值构成的灰度图像 灰度图像坐标会与原图像对应 R值就是角点分数 当R值很大的时候 就可以认为这个点是一个角点
OpenCV 中的 Harris 角点检测
Open 中的函数 cv2.cornerHarris() 可以用来进行角点检测。参数如
下:
• img - 数据类型为 float32 的输入图像。
• blockSize - 角点检测中要考虑的领域大小。
• ksize - Sobel 求导中使用的窗口大小
• k - Harris 角点检测方程中的自由参数,取值参数为 [0,04,0.06].
python 实现代码如下:
1 # -*- coding: utf-8 -*- 2 3 4 import cv2 5 import numpy as np 6 7 8 filename = ‘chessboard5.jpg‘ 9 img = cv2.imread(filename) 10 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 11 gray = np.float32(gray) 12 13 # 输入图像必须是 float32 ,最后一个参数在 0.04 到 0.05 之间 14 dst = cv2.cornerHarris(gray,2,3,0.04) 15 16 #result is dilated for marking the corners, not important 17 dst = cv2.dilate(dst,None) 18 19 # Threshold for an optimal value, it may vary depending on the image. 20 img[dst>0.01*dst.max()]=[0,0,255] 21 22 cv2.imshow(‘dst‘,img) 23 if cv2.waitKey(0) & 0xff == 27: 24 cv2.destroyAllWindows()
dst = cv2.dilate(dst,None) 这段代码是膨胀 提升后续图像角点标注的清晰准确度 可有可无 也可以注释掉
估计大家最有疑问的应该是:
img[dst>0.01*dst.max()]=[0,0,255]这段代码是什么意思吧 dst>0.01*dst.max()这么多返回是满足条件的dst索引值 根据索引值来设置这个点的颜色
这里是设定一个阈值 当大于这个阈值分数的都可以判定为角点 (好像说跟没说一样是吧)hhhh
在看上面我讲的 这里的dst其实就是一个个角度分数R组成的 当 λ 1 和 λ 2 都很大,并且 λ 1 ~λ 2 中的时,R 也很大,(λ 1 和 λ 2 中的最小值都大于阈值)说明这个区域是角点。
那么这里为什么要大于0.01×dst.max()呢 注意了这里R是一个很大的值 我们选取里面最大的R 然后 只要dst里面的值大于百分之一的R的最大值 那么此时这个dst的R值也是很大的 可以判定他为角点
也不一定要0.01 可以根据图像自己选取不过如果太小的话 可能会多圈出几个不同的角点
代码结果上面已经看过了 在放出来一次吧:
若有兴趣交流分享技术,可关注本人公众号,里面会不定期的分享各种编程教程,和共享源码,诸如研究分享关于c/c++,python,前端,后端,opencv,halcon,opengl,机器学习深度学习之类有关于基础编程,图像处理和机器视觉开发的知识