OpenCV Fast角点检测算法的使用和原理

OpenCV Fast角点检测算法的使用和原理_第1张图片


代码及解析

import numpy as np
import cv2

img = cv2.imread("fast_check3.jpg",0)  # 读取图片

# Initiate FAST object with default values
fast = cv2.FastFeatureDetector_create()  # 实例化fast
# find and draw the keypoints
kp = fast.detect(img, None)  # 找出图片中的关键点
img2 = cv2.drawKeypoints(img, kp, None, color=(255, 0, 0))  # 画出检测出来的点

cv2.imshow('fast.png', img2)  # 显示图片
cv2.waitKey(0)

Fast角点检测的算法原理

我们可以根据图像局部的自相关函数来求得Harris角点,虽然在有些实验环境中已经达到了实时,但是我们实践工程应用中,特征点的提取与匹配只是整个应用算法中的一部分,所以我们对于特征点的提取必须有更高的要求

FAST角点定义为:若某像素点与其周围领域内足够多的像素点处于不同的区域,则该像素点可能为角点。也就是某些属性与众不同,考虑灰度图像,即若该点的灰度值比其周围领域内足够多的像素点的灰度值大或者小,则该点可能为角点。

FAST算法步骤

  1. 从图片中选取一个像素P,下面我们将判断它是否是一个特征点。我们首先把它的亮度值设为Ip。
  2. 设定一个合适的阈值t
  3. 虑以该像素点为中心的一个半径等于3像素的离散化的Bresenham圆,这个圆的边界上有16个像素(如下图所示)
    OpenCV Fast角点检测算法的使用和原理_第2张图片
    如果在这个大小为16个像素的圆上有n个连续的像素点,它们的像素值要么都比Ip+t大,要么都比Ip−t小,那么它就是一个角点。(如上图中的白色虚线所示)。n的值可以设置为12或者9,实验证明选择9可能会有更好的效果。

上面的算法中,对于图像中的每一个点,我们都要去遍历其邻域圆上的16个点的像素,效率较低。

我们下面提出了一种高效的测试(high-speed test)来快速排除一大部分非角点的像素。

该方法仅仅检查在位置1,9,5和13四个位置的像素,首先检测位置1和位置9,如果它们都比阈值暗或比阈值亮,再检测位置5和位置13。

如果P是一个角点,那么上述四个像素点中至少有3个应该必须都大于Ip+t或者小于Ip−t,因为若是一个角点,超过四分之三圆的部分应该满足判断条件。

如果不满足,那么p不可能是一个角点。

对于所有点做上面这一部分初步的检测后,符合条件的将成为候选的角点,我们再对候选的角点,做完整的测试,即检测圆上的所有点。

虽然算法效率很高,但是有点一些缺点:

  1. 当我们设置n<12时就不能使用快速算法来过滤非角点的点;
  2. 检测出来的角点不是最优的,这是因为它的效率取决于问题的排序与角点的分布;
  3. 对于角点分析的结果被丢弃了;
  4. 多个特征点容易挤在一起。

使用机器学习做一个角点分类器

  1. 首先选取你进行角点提取的应用场景下很多张的测试图片
  2. 运行FAST角点检测算法来获取测试图片集上的所有角点特征
  3. 对于每个角点,我们把它邻域圆上的16个点存储下来保存在一个vector内,处理所有步骤2中得到的角点,并把它们存储在P中。
  4. 对于图像上的点p,它周围邻域圆上位置为x,x∈{1…16}的点表示为p→x,可以用下面的判断公式将该点p→x分为3类:
    OpenCV Fast角点检测算法的使用和原理_第3张图片
  5. 设P为训练图像集中所有像素点的集合,我们任意16个位置中的一个位置x,可以把集合P分为三个部分Pd,Ps和Pb,其中Pd的定义如下,Ps和Pb的定义与其类似 P b = p ∈ P : S p → x = b Pb={p∈P:Sp→x=b} Pb=pP:Spx=b。换句话说,对于任意给定的位置x,它都可以把所有图像中的点分为三类,第一类Pd包括了所有位置x处的像素在阈值t下暗于中心像素,第二类Ps包括了所有位置x处的像素在阈值t下近似于中心像素,Pb包括了所有位置x处的像素在阈值t下亮于中心像素。
  6. 定义一个新的布尔变量Kp,如果p是一个角点,那些Kp 为值,否则为假。
  7. 使用ID3算法(决策树分类器)来查询每一个子集。
  8. 递归计算所有的子集直到Kp的熵为0
  9. 被创建的决策树就用于于其他图片的FAST检测

非极大值抑制
从邻近的位置选取了多个特征点是另一个问题,我们可以使用Non-Maximal Suppression来解决(本文的案例就是使用了非极大值抑制的方式,如果不使用,需要添加一下代码)

fast.setNonmaxSuppression(0)  # 不使用非极大值抑制
kp = fast.detect(img, None)

实现的原理

  1. 为每一个检测到的特征点计算它的响应大小(score function)V。这里V定义为点p和它周围16个像素点的绝对偏差的和。
  2. 考虑两个相邻的特征点,并比较它们的V 值。
  3. V值较低的点将会被删除

你可能感兴趣的:(OpenCV)