- 1. 学习如何在你的电脑上配置OpenCV-Python环境!
- 1.1 开始了解OpenCV-Python
- 1.2 在 Windows 下安装 OpenCV-Python
- 1.3 在 Fedora 环境下安装 OpenCV-Python
- 1.4 在 Debian(Ubuntu)中配置 OpenCV-Python
- 1.5 在Docker中安装OpenCV-Python
- 1.6 在树莓派配置OpenCV-Python
- 2. OpenCV中的GUI功能
- 2.1 开始使用图像
- 2.2 开始使用视频
- 2.3 OpenCV 中的绘图函数
- 2.4 以鼠标为画笔
- 2.5 用滑块控制条做调色板
- 3. OpenCV中的GUI功能
- 3.1 图片基本操作
- 3.2 图像算术操作
- 3.3 性能评估与改进技巧
- 4. OpenCV中的图像处理
- 4.1 更换颜色空间
- 4.2 对图像进行几何变换
- 4.3 图像二值化处理
- 4.4 平滑图像
- 4.5 形态学转换
- 4.6 图像梯度
- 4.7 Canny边缘检测
- 4.8 图像金字塔
- 4.9.1 直方图:查找,绘制,分析
- 4.9.2 直方图均衡化
- 4.9.3 二维直方图
- 4.9.4 直方图反投影
- 4.10 OpenCV中的图像变换
- 4.10.1 傅立叶变换
- 4.11 模板匹配
- 4.12 霍夫直线变换
- 4.13 霍夫圆变换
- 4.14 基于分水岭算法的图像分割
- 4.14 使用 GrabCut 算法交互式前景提取
- 5. 特征检测和描述符
- 5.1 理解特征
- 5.2 Harris 角点检测
- 5.3 Shi-Tomasi 角点检测 & 适合用来跟踪的特征
- 5.4 介绍SIFT(尺度不变特征转换)
- 5.5 介绍SURF(加速稳健特征)
- 5.6 角点检测的FAST算法
- 5.7 BRIEF特征点描述算法
- 5.8 ORB 特征描述符(Oriented FAST and Rotated BRIEF)
- 5.9 特征匹配
- 5.10 特征匹配和使用单应性匹配来搜索物体
- 6. 视频分析
- 6.1 Meanshift和Camshift
- 6.2 光流
- 6.3 背景分割
- 7. 相机校准和3D重建
- 7.1 相机校准
- 7.2 姿势估计
- 7.3 极线几何
- 7.4 来自立体图像的深度图
- 8. 机器学习
- 8.1 K-最近邻算法
- 8.1.1 了解k-最近邻算法
- 8.1.2 使用kNN进行手写字符的OCR
- 8.2 支持向量机(SVM)
- 8.2.1 理解SVM
- 8.2.2 使用SVM的手写数据的OCR
- 8.3 K-Means聚类
- 8.3.1 理解 K-Means 聚类
- 8.3.2 OpenCV中的K-Means聚类
- 9. 计算摄影学
- 9.1 图像去噪
- 9.2 图像修复
- 9.3 高动态范围(HDR)
- 10. 目标检测
- 10.1 使用 Haar Cascades 的面部识别
- 11. OpenCV-Python 绑定
- 11.1 OpenCV-Python绑定如何工作?
5.2 Harris 角点检测
目标
在这一章中,
- 我们将会理解 Harris 角点检测背后的概念
- 我们会了解
cv2.cornerHarris()
和cv2.cornerSubPix()
函数的使用方法
理论基础
上一章中,我们已经看到边角是在图像中各个方向上亮度都变化非常大的区域。试图找到这些边角的一个早期尝试由 Chris Harris 和 Mike Stephens 在它们1988年的的论文《A Combined Corner and Edge Detector》^1 中提出,所以这个方法现在就叫 Harris 角点检测。他把这个简单的想法变成了数学形式。它基本上找到了在所有方向上 $f(u,v)$ 位移的亮度差异。这个方法由下面的的式子表述:
$$
E(u,v) = \sum{x,y} \underbrace{w(x,y)}{window\ function} \, [\underbrace{I(x+u,y+v)}{shifted\ intensity}-\underbrace{I(x,y)}{intensity}]^2
$$
窗口函数是一个矩形窗口或高斯窗口,它给其中的像素一个权重。
我们必须最大化这个函数 $E(u,v)$ 来进行角点检测。 这意味着,我们必须取第二项的最大值。 将泰勒展开应用到上面的方程式上,并使用一些数学方法(请参考你喜欢的任何标准教科书以获得全面的推导),我们得到最终方程式为:
$$
E(u,v) \approx
\begin{bmatrix} u & v \end{bmatrix} M \begin{bmatrix} u \ v \end{bmatrix} \
where \
M = \sum_{x,y} w(x,y) \begin{bmatrix}I_x I_x & I_x I_y \ I_x I_y & I_y I_y \end{bmatrix}
$$
这里 $I_x$ 和 $I_y$ 是图像在 $x$ 和 $y$ 方向上的导数。(这可以使用 cv2.Sobel()
容易地求出。)
然后就是最主要的部分。 在上面这些步骤之后,他们创造了一个分值,基本上是一个方程式,它将决定一个窗口是否包含了一个边角。
$$
R = det(M) - k(trace(M))^2 \
where
$$
- $det(M) = \lambda_1 \lambda_2$
- $trace(M) = \lambda_1 + \lambda_2$
- $\lambda_1$ 和 $\lambda_2$ 是 $M$ 的特征值
从这些特征值的值就能看出一个区域是边角,边缘还是平坦的。
- 当 $|R|$ 很小,而且$\lambda_1$和$\lambda_2$也很小,这个区域是平坦的。
- 当 $R<0$ 且$\lambda_1 >> \lambda_2$或$\lambda_2 >> \lambda_1$,这个区域是边缘。
- 当R很大且 $\lambda_1$ 和 $\lambda_2$ 也很大,但$\lambda_1\sim\lambda_2$,这个区域是一个边角。
所以Harris角点检测的结果是一张包含了这些分数的灰度图像,取图像超过一个阈值的部分,你会得到图片的边角。我们将会在一张简单的图片上实践一下。
OpenCV 中的 Harris 角点检测
OpenCV 有 cv2.cornerHarris()
函数来进行 Harris 角点检测。
参数如下:
img
- 输入图片,它应该是灰度图,类型应该是float32
。blockSize
- 角点检测考虑的区域大小ksize
- 使用Sobel求导数时使用的光圈参数k
- 方程中Harris检测器的自由参数
下面是样例代码:
import cv2
import numpy as np
filename = 'chessboard.png'
img = cv2.imread(filename)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv2.cornerHarris(gray,2,3,0.04)
# 结果被膨胀来显示出边缘,这不重要
dst = cv2.dilate(dst,None)
# 取图像超过一个最优化的阈值的部分,阈值根据图像会有所不同
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)
# 寻找Harris角点
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)
# 寻找质心
ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)
# 定义停止标准并改进角点
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)
# 把它们画出来
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论