OpenCV 尺度不变特征检测:SIFT、SURF、BRISK、ORB

Jacob的全景图像融合算法系列
OpenCV 尺度不变特征检测:SIFT、SURF、BRISK、ORB
OpenCV 匹配兴趣点:SIFT、SURF 和二值描述子
OpenCV 估算图像的投影关系:基础矩阵和RANSAC
OpenCV 单应矩阵应用:全景图像融合原理
图像融合:拉普拉斯金字塔融合算法

这个学期在上数字图像处理这门课。这门课没有考试,只有大作业,要求使用labwindows和NI Vision进行开发。我选的题目是全景图像的合成(图像拼接),其中要使用到一些特征点检测和匹配的算法。本文主要讨论一下opencv中一些尺度不变特征检测算法的实现。


乔帮主

1.概述

在计算机视觉领域,兴趣点(也称关键点特征点)的概念已经得到了广泛的应用,包括目标识别、图像配准、视觉跟踪、三维重建等。这个概念的原理是,从图像中选取某些特征点并对图像进行局部分析(即提取局部特征),而非观察整幅图像。只要图像中有足够多的可检测的兴趣点,并且这些兴趣点各不相同且特征稳定、能被精确地定位,上述方法就十分有效。

因为要用于图像内容的分析,所以不管图像拍摄时使用了什么视角、尺度和方位,理想情况下同一场景或目标位置都要检测到特征点。视觉不变性是图像分析中一个非常重要的属性,目前有大量关于它的研究。

目前一些广为人知的特征点检测算法有:

  1. 不带尺度不变特征的检测,如Harris、FAST、AGAST等。在我上一篇文章中提到过,本文不进行讨论。
  2. 尺度不变特征的检测,如SIFT、SURF、BRISK、ORB等。本文主要讨论SIFT。

2.算法原理

根据我的理解,尺度不变特征检测的算子基本都基于这样一个假设

对图像进行缩放或者进行高斯滤波,可以模拟人眼在不同距离下观察物体时的场景

SIFT算法的第一个步骤,就是通过对原图像进行不断的缩小和高斯滤波,生成图像金字塔,以用来进行后续的分析.

图像金字塔

SIFT算法使用了高斯差分(DOG)这个概念。高斯滤波器可以提取图像的低频成分,过滤的频率范围取决于参数σ。那么,用两个不同带宽的高斯滤波器对一幅图像做滤波,然后相减,就可以得到图像中的一定频段构成的图像。这种运算就叫高斯差分。而SIFT算法对每个Octave的图像进行不同程度的高斯滤波后生成高斯差分金字塔

高斯差分金字塔

得到DOG金字塔之后,通过检测不同层之间的图像的极值点来进行关键点的初步探查。这个过程很简单,就是与周围的像素点进行比较,当大于或小于所有相邻点时,即为极值点。下图中的X不仅要跟周围的O进行比较,还要跟上一层和下一层的9x2个O进行比较,才能确定是否是极值点。
极值检测

我们找到的极值点是离散的,我们需要使用泰勒展开式来拟合真正的极值点

泰勒展开式(二阶)

精确定位

上述步骤找到的极值点很多都是处于边缘区域的点。我们要找的兴趣点是角点,角点的特征是纵向和横向的变化都很大,而边缘点只有一个方向变化比较大。于是,可以使用Hessian矩阵进行筛选。这个实际上是计算两个方向上的二阶导数。

Hessian(海塞)矩阵

得到特征点的位置之后,我们需要求取它们的方向。对于在DOG金字塔检测到的关键点,采集所在图像3σ邻域窗口内像素的梯度和方向特征,并进行统计。取幅值最高的方向为主方向,超过峰值百分之80的方向为辅方向

m为梯度幅值 Θ为幅角

确定主方向

我们已经得到了关键点的所需要的信息,接下来就是用一组向量将关键点描述出来。为了保证特征向量具有旋转不变性,需要将坐标轴旋转到关键点的方向。

坐标轴旋转

最后就是生成特征匹配点。将特征点邻域分为几个区块,计算八个方向的梯度方向直方图。这里有16个区域,所以生成了16x8=128个维度的数据。在进行统计之前,还要进行一次高斯加权,特征点附近的区域权值大,相反权值小。

采样

加权并统计

SIFT是十分经典的算法,但有以下缺点:

  • 实时性不高
  • 特征点比较少
  • 对边缘光滑的图像有时无能为力

至此,SIFT的原理介绍到这里。这个算法比较复杂,我花了不少时间去理解,但笔者水平有限,理解十分粗浅,可能会有错误。所以还是以维基和论文为准比较稳妥。

至于SURF、BRISK、ORB基本都是在SIFT算法的基础上进行改进,只要理解SIFT,其他算法相对而言也比较好办。这里不对其他算法进行讨论,读者可以查看文末贴出的博文自行了解。

3.算法实现

/******************************************************
 * Created by 杨帮杰 on 9/29/18
 * Right to use this code in any way you want without
 * warranty, support or any guarantee of it working
 * E-mail: yangbangjie1998@qq.com
 * Association: SCAU 华南农业大学
 ******************************************************/

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>


#define IMAGE1_PATH "/home/jacob/下载/church01.jpg"
#define IMAGE2_PATH "/home/jacob/下载/church02.jpg"

using namespace cv;
using namespace cv::xfeatures2d;
using namespace std;

int main()
{
    Mat image= imread(IMAGE1_PATH,0);
    if (!image.data)
        return 0;

    //SURF
    vector<KeyPoint> keypoints;

    //创建一个Hessian矩阵的阈值为2000的SURF检测器
    //这个值越大,检测到的点越少
    Ptr<SurfFeatureDetector> ptrSURF = SurfFeatureDetector::create(2000.0);
    ptrSURF->detect(image, keypoints);

    Mat featureImage;
    drawKeypoints(image,keypoints,featureImage,
                  Scalar(255,255,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    imshow("IMAGE1_SURF",featureImage);

    cout << "Number of IMAGE1_SURF keypoints: " << keypoints.size() << endl;

    //读取第二个图像进行比较
    image = imread(IMAGE2_PATH,0);

    keypoints.clear();
    ptrSURF->detect(image,keypoints);

    drawKeypoints(image,keypoints,featureImage,
                  Scalar(255,255,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    imshow("IMAGE2_SURF",featureImage);
    cout << "Number of IMAGE2_SURF keypoints: " << keypoints.size() << endl;


    //SIFT
    image = imread(IMAGE1_PATH,0);

    keypoints.clear();
    Ptr<SiftFeatureDetector> ptrSIFT = SiftFeatureDetector::create();
    ptrSIFT->detect(image, keypoints);

    drawKeypoints(image,keypoints,featureImage,
                  Scalar(255,255,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    imshow("SIFT",featureImage);

    cout << "Number of SIFT keypoints: " << keypoints.size() << endl;

    //BRISK
    keypoints.clear();
    cv::Ptr<cv::BRISK> ptrBRISK = cv::BRISK::create(
        60,  // AGAST(FAST的加速版)检测的阈值,阈值越大检测到的点越小
        5);  // 金字塔的层数

    ptrBRISK->detect(image,keypoints);

    drawKeypoints(image,keypoints,featureImage,
                  Scalar(255,255,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    imshow("BRISK", featureImage);

    cout << "Number of BRISK keypoints: " << keypoints.size() << endl;

    //ORB
    keypoints.clear();
    cv::Ptr<cv::ORB> ptrORB = cv::ORB::create(
        75, // 关键点的数量
        1.2, // 金字塔每一层的缩放比例
        8);  // 金字塔的层数
    ptrORB->detect(image, keypoints);

    drawKeypoints(image,keypoints,featureImage,
                  Scalar(255,255,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    imshow("ORB",featureImage);

    cout << "Number of ORB keypoints: " << keypoints.size() << endl;

    waitKey();
    return 0;
}

结果如下


SURF

SIFT、ORB、BRISK

关键点的数量

References:
SIFT算法详解
SIFT特征匹配算法介绍
SURF特征提取分析
BRISK特征提取算法
ORB特征提取与匹配
opencv计算机视觉编程攻略(第三版) —— Robert

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,504评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,898评论 1 300
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,218评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,322评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,693评论 3 290
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,812评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,747评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,476评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,700评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,190评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,541评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,206评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,129评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,903评论 0 199
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,894评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,748评论 2 274

推荐阅读更多精彩内容