特征点又称兴趣点、关键点,它是在图像中突出且具有代表意义的一些点,通过这些点我们可以用来识别图像、进行图像配准、进行3D重建等。本文主要介绍OpenCV中几种定位与表示关键点的函数。

一、Harris角点

角点是图像中最基本的一种关键点,它是由图像中一些几何结构的关节点构成,很多都是线条之间产生的交点。Harris角点是一类比较经典的角点类型,它的基本原理是计算图像中每点与周围点变化率的平均值。

   (1)

  (2)

其中I(x+u,y+u)代表了点(x,y)邻域点的灰度值。通过变换可以将上式变化为一个协方差矩阵求特征值的问题(2),具体数学原理本文不过多描述。

OpenCV的Hairrs角点检测的函数为cornerHairrs(),但是它的输出是一幅浮点值图像,浮点值越高,表明越可能是特征角点,我们需要对图像进行阈值化。我们使用一张建筑图像来显示:

int main()
{
Mat image=imread("../buliding.png");
Mat gray;
cvtColor(image,gray,CV_BGR2GRAY); Mat cornerStrength;
cornerHarris(gray,cornerStrength,,,0.01);
threshold(cornerStrength,cornerStrength,0.001,,THRESH_BINARY);
return ;
}

首先我们来说明一下cornerHairrs()这个函数参数的意思:

前2参数是输入与输出,输入是一个灰度图像,输出是一个浮点图像,第三个参数指定角点分析的邻域,第4个参数实际上在角点求取过程中计算梯度图像的核窗口大小,第5个参数是它原理公式(2)中的一个系数。

从上面的例子的结果我们可以看到,有很多角点都是粘连在一起的,我们下面通过加入非极大值抑制来进一步去除一些粘在一起的角点。

非极大值抑制原理是,在一个窗口内,如果有多个角点则用值最大的那个角点,其他的角点都删除,窗口大小这里我们用3*3,程序中通过图像的膨胀运算来达到检测极大值的目的,因为默认参数的膨胀运算就是用窗口内的最大值替代当前的灰度值。程序的最后使用了一个画角点的函数将角点显示在图像中,这个函数与本系列第5篇中画角点的函数是一致的。

int main()
{
Mat image=imread("../buliding.png");
Mat gray;
cvtColor(image,gray,CV_BGR2GRAY); Mat cornerStrength;
cornerHarris(gray,cornerStrength,,,0.01); double maxStrength;
double minStrength;
// 找到图像中的最大、最小值
minMaxLoc(cornerStrength,&minStrength,&maxStrength); Mat dilated;
Mat locaMax;
// 膨胀图像,最找出图像中全部的局部最大值点
dilate(cornerStrength,dilated,Mat());
// compare是一个逻辑比较函数,返回两幅图像中对应点相同的二值图像
compare(cornerStrength,dilated,locaMax,CMP_EQ); Mat cornerMap;
double qualityLevel=0.01;
double th=qualityLevel*maxStrength; // 阈值计算
threshold(cornerStrength,cornerMap,th,,THRESH_BINARY);
cornerMap.convertTo(cornerMap,CV_8U);
// 逐点的位运算
bitwise_and(cornerMap,locaMax,cornerMap); drawCornerOnImage(image,cornerMap);
namedWindow("result");
imshow("result",image);
waitKey(); return ;
}
void drawCornerOnImage(Mat& image,const Mat&binary)
{
Mat_<uchar>::const_iterator it=binary.begin<uchar>();
Mat_<uchar>::const_iterator itd=binary.end<uchar>();
for(int i=;it!=itd;it++,i++)
{
if(*it)
circle(image,Point(i%image.cols,i/image.cols),,Scalar(,,),);
}
}

现在我们得到的效果就比默认的函数得到的结果有相当的改善。

由于cornerHarris的一些缺点,OpenCV提供了另一个相似的函数GoodFeaturesToTrack()它用角点间的距离限制来防止角点粘连在一起。

goodFeaturesToTrack(image,corner,
, // 最多检测到的角点数
0.01, // 阈值系数
); // 角点间的最小距离

它可以得到与上面基本一致的结果。

二、FAST特征点

harris特征在算法复杂性上比较高,在大的复杂的目标识别或匹配应用上效率不能满足要求,OpenCV提供了一个快速检测角点的类FastFeatureDetector,而实际上FAST并不是快的意思,而是Features from Accelerated Segment Test,但这个算法效率确实比较高,下面我们来看看这个类的用法。

OpenCV里为角点检测提供了统一的接口,通过类下面的detect方法来检测对应的角点,而输出格式都是vector<KeyPoint>。

vector<KeyPoint> keypoints;
FastFeatureDetector fast( // 定义检测类
); //40是检测的阈值
fast.detect(image,keypoints); drawKeypoints(image,keypoints,image,Scalar(,,),
DrawMatchesFlags::DRAW_OVER_OUTIMG);

其中drawKeypoints是OpenCV提供的在图像上画角点的函数。它的参数可以让我们选择用不同的方式标记出特征点。

三、尺度不变的SURF特征

surf特征是类似于SIFT特征的一种尺度不变的特征点,它的优点在于比SIFT效率要高,在实际运算中可以达到实时性的要求,关于SURF的原理这里就不过多的介绍,网络上这类的文章很多。

类似于FAST特征点的求法,SURF也可以使用通用接口求得,而SURF特征的类为SurfFeatureDetector,类似的SIFT特征点的检测类为SiftFeatureDetector。

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/features2d.hpp> using namespace cv; int main()
{
Mat image=imread("../buliding.png"); vector<KeyPoint> keypoints; SurfFeatureDetector surf(.);
surf.detect(image,keypoints); drawKeypoints(image,keypoints,image,Scalar(,,),
DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
namedWindow("result");
imshow("result",image);
waitKey(); return ;
}

这里有一个值得说明的问题是:OpenCV2.4版本后好像把SurfFeatureDetector这个类的定义移到了头文件nonfree/features2d.hpp

中,所以头文件中要加入该文件,并且要把opencv_nonfree24xd.lib加入属性表的链接器熟悉的输入中,其中x换成你当前opencv的版本号。

最终的显示效果如下:

四、SURF特征的描述

在图像配准中,特征点的描述往往不是位置这么简单,而是使用了一个N维向量来描述一个特征点,这些描述子之间可以通过定义距离公式来比较相近程度。

SurfDescriptorExtractor 是一个提取SURF特征点以及其描述的类。

下面是一个宽景图像的拼接配准的例子:

 

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/legacy/legacy.hpp> using namespace cv;
int main()
{
Mat image1=imread("../b1.png");
Mat image2=imread("../b2.png");
// 检测surf特征点
vector<KeyPoint> keypoints1,keypoints2;
SurfFeatureDetector detector();
detector.detect(image1, keypoints1);
detector.detect(image2, keypoints2);
// 描述surf特征点
SurfDescriptorExtractor surfDesc;
Mat descriptros1,descriptros2;
surfDesc.compute(image1,keypoints1,descriptros1);
surfDesc.compute(image2,keypoints2,descriptros2); // 计算匹配点数
BruteForceMatcher<L2<float>>matcher;
vector<DMatch> matches;
matcher.match(descriptros1,descriptros2,matches);
std::nth_element(matches.begin(),matches.begin()+,matches.end());
matches.erase(matches.begin()+,matches.end());
// 画出匹配图
Mat imageMatches;
drawMatches(image1,keypoints1,image2,keypoints2,matches,
imageMatches,Scalar(,,)); namedWindow("image2");
imshow("image2",image2);
waitKey(); return ;
}

程序中我们选择了25个配准点,得到最后的匹配如下:

OpenCV成长之路(9):特征点检测与图像匹配的更多相关文章

  1. OpenCV成长之路:图像滤波

    http://ronny.blog.51cto.com/8801997/1394138 OpenCV成长之路:图像滤波 2014-04-11 14:28:44 标签:opencv 边缘检测 sobel ...

  2. OpenCV成长之路:直线、轮廓的提取与描述

    http://ronny.blog.51cto.com/8801997/1394139 OpenCV成长之路:直线.轮廓的提取与描述 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 . ...

  3. OpenCV成长之路:图像直方图的应用

    OpenCV成长之路:图像直方图的应用 2014-04-11 13:57:03 标签:opencv 图像 直方图 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否 ...

  4. OpenCV成长之路(8):直线、轮廓的提取与描述

    基于内容的图像分析的重点是提取出图像中具有代表性的特征,而线条.轮廓.块往往是最能体现特征的几个元素,这篇文章就针对于这几个重要的图像特征,研究它们在OpenCV中的用法,以及做一些简单的基础应用. ...

  5. OpenCV成长之路(7):图像滤波

    滤波实际上是信号处理里的一个概念,而图像本身也可以看成是一个二维的信号.其中像素点灰度值的高低代表信号的强弱. 高频:图像中灰度变化剧烈的点. 低频:图像中平坦的,灰度变化不大的点. 根据图像的高频与 ...

  6. OpenCV成长之路(2):图像的遍历

    我们在实际应用中对图像进行的操作,往往并不是将图像作为一个整体进行操作,而是对图像中的所有点或特殊点进行运算,所以遍历图像就显得很重要,如何高效的遍历图像是一个很值得探讨的问题. 一.遍历图像的4种方 ...

  7. OpenCV成长之路(6):数学形态学基本操作及其应用

    数学形态学实际上可以理解为一种滤波行为,所以很多地方称它为形态学滤波.有了个这概念,我们就能更好的理解它.我们滤波中用的滤波器(kernel)在这里被称为结构元素,结构元素往往是由一个特殊的形状构成, ...

  8. OpenCV成长之路(5):图像直方图的应用

    正如第4篇文章所说的图像直方图在特征提取方面有着很重要的作用,本文将举两个实际工程中非常实用的例子来说明图像直方图的应用. 一.直方图的反向映射. 我们以人脸检测举例,在人脸检测中,我们第一步往往需要 ...

  9. OpenCV成长之路(4):图像直方图

    一.图像直方图的概念 图像直方图是反映一个图像像素分布的统计表,其实横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的.纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比. 图 ...

随机推荐

  1. Bois设置教程

    BIOS设置图解教程之Award篇 (目前主板上常见的BIOS主要为AMI与AWARD两个系列,如何辨别BIOS品牌系列请移步,本文详细讲解Award系列的BIOS设置图解教程,如果你的BIOS为AM ...

  2. 自然语言16_Chunking with NLTK

    Chunking with NLTK 对chunk分类数据结构可以图形化输出,用于分析英语句子主干结构 # -*- coding: utf-8 -*-"""Created ...

  3. Java数据结构——优先级队列

    //================================================= // File Name : PriorityQueue_demo //------------ ...

  4. Java抽象类与接口的关系

  5. ecshop新增一个编辑器

    在ecshop的后台新增一个编辑器框 步骤一:找到lib_main.php 文件:admin/includes/lib_main.php. 找到变量:function create_html_edit ...

  6. PHP代码质量优化

    最近总结了一些平常写PHP代码时的一些优化分享给大家. 1.尽量使用绝对路径 相对路径中会检查很多路径,这时我们可以使用绝对路径,但绝对路径不利于后期维护,所以define定义的时候使用__FILE_ ...

  7. WebGrid Helper with Check All Checkboxes

    WebGrid Helper with Check All Checkboxes myEvernote Link Tuesday, September 13, 2011ASP.NET ASP.NET ...

  8. Hello World(本博客启程篇)

    Hello World 作为本博客第一篇日志,作为程序员,无论走到哪里,做什么事,必须先输出这句话. 一个想法 从今天3月份到现在一直在学技术,过程中坑的解决.知识的总结以及想法等都写到了" ...

  9. JaxWsProxyFactoryBean 与 JaxWsDynamicClientFactory

    1. JaxWsProxyFactoryBean    简介:调用方式采用了和RMI类似的机制,即客户端直接调用服务器端提供的服务接口(interface),CXF通过运行时代理生成远程服务的代理对象 ...

  10. Navicat For Mysql快捷键

    1.ctrl+q           打开查询窗口 2.ctrl+/            注释sql语句 3.ctrl+shift +/  解除注释 4.ctrl+r           运行查询窗 ...