- 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.5 介绍SURF(加速稳健特征)
目标
在这一章中,
- 我们将学习SURF的基础知识
- 我们将学习OpenCV中的SURF
理论基础
在上一章中,我们学习了SIFT的关键点检测和描述。 但是速度比较慢,人们需要更加快速的算法。 2006 年,Bay, H. , Tuytelaars, T. 和 Van Gool, L 三人发表了另一篇名为《SURF: Speeded Up Robust Features》^1 的论文,其中介绍了一种名为 SURF 的新算法。 顾名思义,这是 SIFT 的加速版本。
在 SIFT 中,Lowe 用高斯差分来近似拉普拉斯高斯算子来寻找尺度空间。 SURF走得更远一点,用盒式滤波器逼近LoG。 下图是这种近似的演示。 这种近似的一大优点是,利用积分图像可以容易地计算与盒式滤波器的卷积。 它可以在不同的尺度上并行完成。 SURF 依赖于 Hessian 矩阵的行列式和位置的行列式。
对于方向分配,SURF 使用水平和垂直方向的小波响应来确定6s的邻域。 适当的高斯权值也适用于它。 然后将它们绘制在下图中给出的空间中。 通过计算在角度60度的滑窗内的所有响应的总和来估计主导方向。 有趣的是,可以很容易地在任何尺度上使用积分图像找出小波响应。 对于许多应用来说,旋转不变是不需要的,所以不需要找到这个方向,这就加快了这个过程。 SURF提供了称为Upright-SURF 或 U-SURF 的功能。 它提高了速度,并且在 $\pm 15^{\circ}$ 之中稳健的。 OpenCV 两种都支持,取决于标志,upright
。 如果是0,则计算方向。 如果是1,则不计算方向,速度更快。
对于特征描述,SURF使用水平和垂直方向的小波响应(再一次地,我们使用积分图像使其更容易)。 大小为20s×20s的邻域是围绕s的大小的关键点。 它被分为4x4个分区域。 对于每个子区域,采取水平和垂直小波响应,并且形成像这样的矢量,
$$
v=(\sum {d_x},\sum {d_y},\sum {| d_x |},\sum {| d_y |})
$$
这表示为一个向量,SURF 特征描述符总共有 64 个维度。 维度越低,计算和匹配的速度越高,也能提供更好的特征的独特性。
为了更好的独特性,SURF特征描述符具有扩展的 128 维版本。
$d_y <0$ 和 $d_y\geq 0$ 对应的 $d_x$ 和 $|d_x|$ 的总和被分别计算出来。
类似地,$d_y$ 和 $|d_y|$ 的总和也按照 $d_x$ 的符号进行分割,从而使特征的数量加倍。 它不会增加太多的计算复杂性。 OpenCV 支持通过设置标志extended
的值分别为0和1,来分别表述使用64-dim 和 128-dim 的 SURF 描述符(默认为 128-dim)。
另一个重要的改进是使用拉普拉斯符号(Hessian矩阵的转置)作为潜在兴趣点。 它不会增加计算成本,因为它在检测期间已经被计算。 拉普拉斯的标志在黑暗的背景下将明亮的斑点与相反的情况区分开来。 在匹配阶段,我们只比较具有相同类型对比度的特征(如下图所示)。 这个最小的信息允许更快的匹配,而不降低描述符的性能。
总之,SURF增加了很多功能来提高每一步的速度。 分析显示,它比SIFT快3倍,而性能与SIFT相当。 SURF擅长处理模糊和旋转的图像,但不擅长处理视点变化和光照变化。
OpenCV 中的 SURF
OpenCV 的 SURF 功能就像 SIFT 一样。你用一些可选的条件来初始化一个SURF对象,比如64/128-dim描述符,Upright/Normal SURF等等。所有的细节在文档中都有很好的解释。 然后就像我们在SIFT中所做的那样,我们可以使用 SURF.detect()
,SURF.compute()
等来查找关键点和描述符。
首先,我们将看到一个关于如何找到SURF关键点和描述符并绘制的简单演示。
img = cv2.imread('fly.png',0)
# 创建一个SURF对象。你可以就在这里写明参数或者等以后再写
# 这里我们设置Hessian阈值为400
surf = cv2.xfeatures2d.SURF_create(400)
# 直接寻找关键点和描述符
kp, des = surf.detectAndCompute(img,None)
len(kp) # 699
在图片中显示1199个关键点显得有些太多了。我们把这一数字减小到50。
# 检测现有的Hessian阈值
print(surf.getHessianThreshold()) # 400.0
# 我们将其设置为50000
# 这仅仅是为了显示方便
# 在实际使用中,这个值最好是300-500中的一个值
surf.setHessianThreshold(50000)
# 重新计算关键点和描述符
kp, des = surf.detectAndCompute(img,None)
print(len(kp)) # 47
小于50个,我们可以在图上把它画出来了。
img2 = cv2.drawKeypoints(img,kp,None,(255,0,0),4)
plt.imshow(img2)
plt.show()
你可以看出 SURF 更像一个斑点检测器。它检测出了蝴蝶翅膀上的白色斑点。你可以在其他图片上尝试一下。
现在我们想要使用U-SURF,这样找到的特征就不会包含方向信息了。
# 检查upright标志,如果它是False,置为True
print(surf.getUpright()) # False
surf.setUpright(True)
# 重新计算关键点和描述符,并绘制图像
kp = surf.detect(img,None)
img2 = cv2.drawKeypoints(img,kp,None,(255,0,0),4)
plt.imshow(img2)
plt.show()
所有的方向都指向了同一方向。这样做大大加快了速度。如果对于你现在在做的事来说方向不那么重要(全景拼接等),这么做更好。
最后,我们检测描述符的大小,如果是 64-dim 的,就将其更改为 182-dim。
# 检测描述符大小
print(surf.descriptorSize()) # 64
# 这意味着“extended”标志是False
surf.getExtended() # False
# 我们将其置为True来获得128-dim的描述符。
surf.extended = True
kp, des = surf.detectAndCompute(img,None)
print(surf.descriptorSize()) # 128
print(des.shape) # (47, 128)
接下来要做的事就是匹配特征点了,我们将在另外一章中讲述相关内容。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论