前面描述角点检测的时候说到,角点其实也是一种图像特征点,对于一张图像来说,特征点分为三种形式包括边缘,焦点和斑点,在OPENCV中,加上角点检测,总共提供了以下的图像特征点检测方法
接下来分别讲述这是一种图像特征检测算法,但是首先,需要了解OPENCV的一种数据结构, KeyPoint结构,该结构的头文件定义如下:
class KeyPoint
{
Point2f pt; //该图像特征点的坐标
float size; //特征点邻域直径
float angle; //特征点的方向,值为[零,三百六十),负值表示不使用,有了这个方向,能够让特征点拥有更高的辨识度,否则仅仅坐标和直径有时会误判特征点
float response;//响应程度,代表该点的强壮程度,也就是该点角点程度,用于后期使用和排序
int octave; //特征点所在的图像金字塔的组
int class_id; //用于聚类的id
}
每个图像特征点检测算法最终的目标之一,而当一张图像的特征点被检测出来之后,就可以和另一张图像的特征点进行匹配,根据相似级别判定两个图像的相似程度.
比如我们可以在图像中检测一张人脸的特征点,从而来检索在另一张图中是否存在相似程度很高的特征点集,从而确认另一张图像中的人脸以及人脸的位置,等,特征点检测算法在物体检测,视觉跟踪,3D重建的时候都有着重要的作用.
一. 图像特征点检测的通用接口
Opencv为了方便用户使用图像特征点检测的相应算法,将全部的特征点检测都封在一个类似的API中,名为Ptr的模板类,也就是说,所有的特征检测算法都实现了相同的借口,detect 检测图像特征点.使用方法类似于
Ptr<相应的特征点检测类名>变量名 = 相应的特征点检测类::create()
变量名->detect(原图像,特征点向量).
使用上面描述的算法,就可以调用几乎全部的图像特征检测算法.但是注意,create函数有多个重载函数,如果为空,每个图像检测算法都会使用自己的一套默认的初始值来初始化类,如果想修改参数,那么create函数调用的时候需要根据检测类的不同,设置不同的初始化变量.
另外,opencv提供而一个快速显示图像特征点的函数,如下
drawKeyPoints(画布图像,特征点向量集,输出的绘制结果,绘制颜色值,绘制模式)
一般来说,画布图像会使用我们检测特征点的原图像(一般检测特征点都是原图像变换为灰度图像之后进行的检测,简单算法复杂度).
绘制模式有以下方法可以选择,是DrawMatchesFlags枚举
DEFAULT:只绘制特征点的坐标点,显示在图像上就是一个个小圆点,每个小圆点的圆心坐标都是特征点的坐标.
DRAW_OVER_OUTIMG:函数不创建输出的图像,而是直接在输出图像变量空间绘制,要求本身输出图像变量就是一个初始化好了的,size与type都是已经初始化好的变量
NOT_DRAW_SINGLE 单点的特征点不被绘制
DRAW_RICH_KEYPOINT 绘制特征点的时候绘制的是一个个带有方向的圆,这种方法同时显示图像的坐标,size,和方向,是最能显示特征的一种绘制方式,但是缺点就是绘制结果太杂乱.
FAST算法是基于角点检测的图像特征.
一个特征点检测的算法的第一步是定义什么是特征点,FAST算法定义特征点是如果某个像素点和他周围领域足够多的像素点处于不同区域,那么这个像素点就是特征点,对于灰度图像来说,也就是该点的灰度值和其周围足够多的像素点的灰度值不同,那么这个像素点就是一个特征点.
该算法的详细计算步骤如下
黑点坐标为(0,0),坐标step为1
以上就是快速特征点检测的原理,OPENCV中定义的快速特征点检测算法的检测API如下
static Ptr<FastFeatureDetector> create( int threshold=10, bool nonmaxSuppression=true,
int type=FastFeatureDetector::TYPE_9_16 );
threshold是指比较时边缘轨迹点和中心点的差值,也就是第三步的阈值t, nonmaxSuppression代表是否使用第五步非极大值抑制,如果发现fast检测的结果有聚簇情况,那么可以考虑采用,第三个参数type的取值来自于FastFeatureDetector枚举,有如下取值:
综上所述我们可以看出,FAST检测算法没有多尺度的问题,所以计算速度相对较快,但是当图片中的噪点较多的时候,会产生较多的错误特征点,健壮性并不好,并且, 算法的效果还依赖于一个阈值t。而且FAST不产生多尺度特征而且FAST特征点没有方向信息,这样就会失去旋转不变性.但是在要求实时性的场合,比如视频监控的物体识别,是可以使用的.
使用代码如下
//fast int main(int argc,char* argv[]) { Mat srcImage = imread("F:\\opencv\\OpenCVImage\\FeatureDetectSrc1.jpg"); Mat srcGrayImage; if (srcImage.channels() == 3) { cvtColor(srcImage,srcGrayImage,CV_RGB2GRAY); } else { srcImage.copyTo(srcGrayImage); } vector<KeyPoint>detectKeyPoint; Mat keyPointImage1,keyPointImage2; Ptr<FastFeatureDetector> fast = FastFeatureDetector::create(); fast->detect(srcGrayImage,detectKeyPoint); drawKeypoints(srcImage,detectKeyPoint,keyPointImage1,Scalar(0,0,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS); drawKeypoints(srcImage,detectKeyPoint,keyPointImage2,Scalar(0,0,255),DrawMatchesFlags::DEFAULT); imshow("src image",srcImage); imshow("keyPoint image1",keyPointImage1); imshow("keyPoint image2",keyPointImage2); imwrite("F:\\opencv\\OpenCVImage\\FeatureDetectSrc1FASTKeyPointImageDefault.jpg",keyPointImage2); waitKey(0); return 0; }