BRISK算法一种特征提取算法,也是一种二进制的特征描述算子。

它具有较好的旋转不变性、尺度不变性,较好的鲁棒性等。在图像配准应用中,速度比较:SIFT<SURF<BRISK<FREAK<ORB,在对有较大模糊的图像配准时,BRISK算法在其中表现最为出色。

BRISK算法

Brisk(Binary Robust Invariant Scalable Keypoints)特征 相比于 SURF SIFT 有些步骤是相同的

  1. 构建尺度空间
  2. 特征点检测
  3. FAST9-16寻找特征   连续 9-16 个点小于或大于当前值,就把其当作特征点的候选者
  4. 特征点定位
  5. 关键点描述子

特征点检测

BRISK算法主要利用FAST9-16进行特征点检测(为什么是主要?因为用到一次FAST5-8),可参见博客:FAST特征点检测。要解决尺度不变性,就必须在尺度空间进行特征点检测,于是BRISK算法中构造了图像金字塔进行多尺度表达。

建立尺度空间

构造n个octave层(用ci表示)和n个intra-octave层(用di表示),文章中n=4,i={0,1,...,n-1}。假设有图像img,octave层的产生:c0层就是img原图像,c1层是c0层的2倍下采样,c2层是c1层的2倍下采样,以此类推。intra-octave层的产生:d0层是img的1.5倍下采样,d1层是d0层的2倍下采样(即img的2*1.5倍下采样),d2层是d1层的2倍下采样,以此类推。则ci、di层与原图像的尺度关系用t表示为:

ci、di层与原图像大小关系为:
                                                     

由于n=4,所以一共可以得到8张图,octave层之间尺度(缩放因子)是2倍关系,intra-octave层之间尺度(缩放因子)也是2倍关系。

特征点检测

对这8张图进行FAST9-16角点检测,得到具有角点信息的8张图,对原图像img进行一次FAST5-8角点检测(当做d(-1)层,虚拟层),总共会得到9幅有角点信息的图像。

非极大值抑制

对这9幅图像,进行空间上的非极大值抑制(同SIFT算法的非极大值抑制):特征点在位置空间(8邻域点)和尺度空间(上下层2x9个点),共26个邻域点的FAST的得分值要最大,否则不能当做特征点;此时得到的极值点还比较粗糙,需要进一步精确定位。

亚像素插值

进过上面步骤,得到了图像特征点的位置和尺度,在极值点所在层及其上下层所对应的位置,对FAST得分值(共3个)进行二维二次函数插值(x、y方向),得到真正意义上的得分极值点及其精确的坐标位置(作为特征点位置);再对尺度方向进行一维插值,得到极值点所对应的尺度(作为特征点尺度)。
                         

特征点描述

高斯滤波

现在,我们得到了特征点的位置和尺度(t)后,要对特征点赋予其描述符。均匀采样模式:以特征点为中心,构建不同半径的同心圆,在每个圆上获取一定数目的等间隔采样点(所有采样点包括特征点,一共N个),由于这种邻域采样模式会引起混叠效应,所以需要对同心圆上的采样点进行高斯滤波。

采样模式如下图,蓝圈表示;以采样点为中心,为方差进行高斯滤波,滤波半径大小与高斯方差的大小成正比,红圈表示。最终用到的N个采样点是经过高斯平滑后的采样点。下图是t=1时的。(文章中:N=60)
          

局部梯度计算

由于有N个采样点,则采样点两两组合成一对,共有N(N-1)/2钟组合方式,所有组合方式的集合称作采样点对,用集合表示,其中像素分别是,δ表示尺度。用表示特征点局部梯度集合,则有:

定义短距离点对子集、长距离点对子集(L个):

其中,,t是特征点所在的尺度。

现在要利用上面得到的信息,来计算特征点的主方向(注意:此处只用到了长距离子集),如下:

特征描述符

要解决旋转不变性,则需要对特征点周围的采样区域进行旋转到主方向,旋转后得到新的采样区域,采样模式同上。BRISK描述子是二进制的特征,由采样点集合可得到N(N-1)/2对采样点对,就可以得到N(N-1)/2个距离的集合(包含长、短距离子集),考虑其中短距离子集中的512个短距离点对,进行二进制编码,判断方式如下:

其中,带有上标,表示经过旋转a角度后的,新的采样点。由此可得到,512Bit的二进制编码,也就是64个字节(BRISK64)。

匹配方法

汉明距离进行比较,与其他二进制描述子的匹配方式一样。

实例(opencv2):

#include <cv.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <Windows.h>  using namespace cv;
using namespace std;  int main()
{  //Load Image  Mat c_src1 =  imread( "1.png");  Mat c_src2 = imread("2.png");  Mat src1 = imread( "1.png", CV_LOAD_IMAGE_GRAYSCALE);  Mat src2 = imread( "2.png", CV_LOAD_IMAGE_GRAYSCALE);  if( !src1.data || !src2.data )  {  cout<< "Error reading images " << std::endl;  return -1;  }  //feature detect  BRISK detector;  vector<KeyPoint> kp1, kp2;  double start = GetTickCount();  detector.detect( src1, kp1 );  detector.detect( src2, kp2 );  //cv::BRISK extractor;  Mat des1,des2;//descriptor  detector.compute(src1, kp1, des1);  detector.compute(src2, kp2, des2);  Mat res1,res2;  int drawmode = DrawMatchesFlags::DRAW_RICH_KEYPOINTS;  drawKeypoints(c_src1, kp1, res1, Scalar::all(-1), drawmode);//画出特征点  drawKeypoints(c_src2, kp2, res2, Scalar::all(-1), drawmode);  cout<<"size of description of Img1: "<<kp1.size()<<endl;  cout<<"size of description of Img2: "<<kp2.size()<<endl;  BFMatcher matcher(NORM_HAMMING);  vector<DMatch> matches;  matcher.match(des1, des2, matches);  double end = GetTickCount();  cout<<"耗时:"<<(end - start) <<"ms"<<endl;  Mat img_match;  drawMatches(src1, kp1, src2, kp2, matches, img_match);  cout<<"number of matched points: "<<matches.size()<<endl;  imshow("matches",img_match);  cvWaitKey(0);  cvDestroyAllWindows();  return 0;
}  

from:https://www.cnblogs.com/welen/articles/6088639.html

实例(opencv3):

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main(int argc, char** argv)
{   Mat img1 = imread("D:/cv400/data/box.png", 0);Mat img2 = imread("D:/cv400/data/box_in_scene.png", 0);if (img1.empty() || img2.empty()) {cout << "Load image error..." << endl;return -1;}imshow("object image", img1);imshow("object in scene", img2);// surf featurs extractiondouble t1 = (double)getTickCount();//int minHessian = 400;Ptr<Feature2D> detector = BRISK::create();vector<KeyPoint> keypoints_obj;vector<KeyPoint> keypoints_scene;Mat descriptor_obj, descriptor_scene;detector->detectAndCompute(img1, Mat(), keypoints_obj, descriptor_obj);detector->detectAndCompute(img2, Mat(), keypoints_scene, descriptor_scene);// matchingBFMatcher matcher(NORM_L2);vector<DMatch> matches;matcher.match(descriptor_obj, descriptor_scene, matches);double t2 = (double)getTickCount();double t = (t2 - t1) / getTickFrequency();cout << "spend time : " << t << "s" << endl;//求匹配点最近距离double minDist = 1000;for (int i = 0; i < descriptor_obj.rows; i++){double dist = matches[i].distance;if (dist < minDist) minDist = dist;    }cout<<"min distance : "<< minDist<<endl;//距离较近即匹配较好的点vector<DMatch> goodMatches;for (int i = 0; i < descriptor_obj.rows; i++){double dist = matches[i].distance;if (dist < max(2* minDist, 0.02)) goodMatches.push_back(matches[i]);   }//寻找匹配上的关键点的变换vector<Point2f> obj;  //目标特征点vector<Point2f> objInScene;  //场景中目标特征点for (size_t t = 0; t < goodMatches.size(); t++) {obj.push_back(keypoints_obj[goodMatches[t].queryIdx].pt);objInScene.push_back(keypoints_scene[goodMatches[t].trainIdx].pt);}Mat imgBH = findHomography(obj, objInScene, RANSAC);//映射点vector<Point2f> obj_corners(4);vector<Point2f> scene_corners(4);obj_corners[0] = Point(0, 0);obj_corners[1] = Point(img1.cols, 0);obj_corners[2] = Point(img1.cols, img1.rows);obj_corners[3] = Point(0, img1.rows);perspectiveTransform(obj_corners, scene_corners, imgBH);//四个点之间画线Mat dst;cvtColor(img2, dst, COLOR_GRAY2BGR);for(int i=0;i<4;i++)line(dst, scene_corners[i%4], scene_corners[(i+1)%4], Scalar(0, 0, 255), 2, 8, 0);imshow("find object in sence", dst);waitKey(0);return 0;
}

from:https://blog.csdn.net/andylanzhiyong/article/details/84865807

OpenCV3学习(11.7) BRISK特征检测器及BRISK描述符相关推荐

  1. OpenCV3学习(11.6) ORB特征检测器及BRIEF描述符

    ORB是ORiented Brief的简称,在ORB的方案中,先采用了FAST作为特征点检测算子,再使用改进BRIEF进行描述符的计算的.ORB的一个重要贡献就是引入了定位关键点的方向. BRIEF描 ...

  2. CVPR2020:端到端学习三维点云的局部多视图描述符

    CVPR2020:端到端学习三维点云的局部多视图描述符 End-to-End Learning Local Multi-View Descriptors for 3D Point Clouds 论文地 ...

  3. 操作系统学习(五) 、代码段和数据段描述符

    一.代码段和数据段描述符格式 段描述符通用格式如下所示: 代码段和数据段描述符中各个位的含义如下所示: 二.代码段和数据段描述符类型 当段描述符中S标志位(描述符类型)被置位,则该描述符用于代码段或数 ...

  4. JNI学习积累之二 ---- 数据类型映射、域描述符说明

    本文原创,转载请注明出处:http://blog.csdn.NET/qinjuning 在Java存在两种数据类型: 基本类型 和 引用类型 ,大家都懂的 . 在JNI的世界里也存在类似的数据类型,与 ...

  5. OpenCV3学习(11.8) FREAK描述符提取器

    FREAK算法是一种二进制的特征描述算子.它与BRISK算法非常相似,个人觉得就是在BRISK算法上的改进,关于BRISK算法详见上一篇博文:BRISK特征提取算法.FREAK依然具有尺度不变性.旋转 ...

  6. brisk matlab,opencv学习笔记三十七:BRISK特征点检测与匹配

    简介 BRISK算法是2011年ICCV上<BRISK:Binary Robust Invariant Scalable Keypoints>文章中,提出来的一种特征提取算法,也是一种二进 ...

  7. 【特征匹配】BRISK原文内容翻译

    本文转自:http://www.2cto.com/kf/201602/490778.html 原文:Stefan Leutenegger, Margarita Chli et al.<BRISK ...

  8. 【特征匹配】BRISK原文翻译

    原文:Stefan Leutenegger, Margarita Chli et al.<BRISK: Binary Robust Invariant Scalable Keypoints> ...

  9. 图像局部特征(十二)--BRISK特征

    原文: http://www.mamicode.com/info-detail-940675.html 简介 BRISK算法是2011年ICCV上<BRISK:Binary Robust Inv ...

最新文章

  1. OpenCV之imwrite()等基本操作
  2. Python3--爬取数据之911网站信息爬取
  3. 【解决方案】MTU现场能源发电机,点亮孤岛的文明之光
  4. django shortcut函数
  5. yum -y list java* 缓存加载不了_Java开发面试宝典:分布式相关篇
  6. 在Java中将前导零添加到数字? [重复]
  7. mfc gridctrl 设置某列自动伸长_三明桥梁智能张拉设备数控智能张拉系统全自动智能张拉系统...
  8. 人生的意义,在于不断地超越自己
  9. python如何登录并爬取获得百度指数统计图数据
  10. BeyondCompare4破解最佳实践
  11. 再见 Wordpress!这个开源建站神器有点吊
  12. 离散数学——数学结构
  13. GNS3 v0.8.6简体中文官方版本下载
  14. 【Derivation】正态分布特征函数证明-X~N(a,sigma^2)
  15. char、char*、char**数组
  16. project子项目之间任务关联_任务关联的类型(Project)
  17. 习题 5.11 有一行电文,已按下面规律译成密码:A-Z a-z即第一个字母变成第26个字母,第i个字母变成第(26-i+1)个字母。非字母字符不变。要求编程序将密码译回原文,并输出密码和原文。
  18. Java通SAS下载sas脚本
  19. 7.6 曲面及其方程
  20. Elan触控板双击右键失效 - 解决方案

热门文章

  1. PHP获取input中的值相同报错,laravel单元测试之phpUnit中old()函数报错解决_php实例...
  2. 助力 Android 抗衡 iOS,华为发布方舟编译器!
  3. 渗透测试入门9之域渗透
  4. java基础运算符、键盘录入
  5. maven添加本地包命令mvn install:install-file
  6. js实现操作等待提示loading……
  7. ruby on rails ajax select
  8. [Winodows Phone 7控件详解]Silverlight toolkit for Windows Phone 7.1控件-3
  9. Flutter AnimatedSwitcher 动画切换组件的基本使用
  10. java基础—GUI概述