OpenCV角点检测—Harris,SIFT,ORB(7)

1. Harris:https://editor.csdn.net/md/?articleId=124154443

2.特征检测与匹配

特征点的检测和匹配是计算机视觉中最用要的技术之一。在物体检测,视觉跟踪,三维重建等领域广泛使用。
OpenCV的10种特征检测方法:
FAST , STAR, SIFT, SURF, ORB, MSER, GFTT, HARRIS, Dense, SimpleBlob
其中最常用的是SIFT,SURF,ORB.

2.1 SURF特征点检测

2.1.1 SURF算法概览

2.1.2 SURF算法原理

2.1.3 SURF类相关OpenCV源码剖析

在OpenCV中关于SURF算法的部分,常与SURF,SurfFeatureDector,SurfDescriptorExtractor这三个类有关。
从解压完成后的opencv的源码目录下,可以找到存放不同特征检测算子所依赖的特征检测和匹配相关的俄核心代码 cat ~/Documents/test_code/opencv-3.4.15/modules/features2d/include/opencv2/features2d.hpp
由于我opencv的版本是3.4.15的,查看features2.hpp没有发现SURF相关的类,所以本节就对和SURF相似的SIFT作解释。
features2d.hpp头文件中,有这么两句定义:
在这里插入图片描述这两句表明SIFT类有两个新别名:SiftFeatureDetector和SiftDescriptorExtractor,三者等价。
通过看源码,可以看到这两句的上方是SIFT类的全貌。
在这里插入图片描述在这里插入图片描述
OpenCV角点检测—Harris,SIFT,ORB(7)_第1张图片
在这里插入图片描述

由此可以看到SIFT,SiftFeatureDector, SiftDescriptorExtractor(三者typedef)都继承自Feature2D,而Feature2D,FeatureDetector, DescriptorExtractor(三者typdef)类都虚继承自Alorithm类。

2.1.4 绘制关键点:drawKeypoints()函数

绘制关键点函数:
函数原型:void drawKeypoints(const Mat& image, const vector& keypoints, Mat& outImge, const Scalar& color=Scalar::all(-1), int flags=DrawMatchesFlags::DEFAULT);

  • 参数一:输入的图片;
  • 参数二:根据原图像得到的特征点,它是一个输出参数。
  • 参数三:输出图像,其内容取决于第五个参数的flags;
  • 参数四:const Scalar&类型的color,关键点的颜色,默认为Scalar::all(-1);
  • 参数五:绘制关键点的特征标志符,有默认置DrawMatchFlags::DEFAULT,可以从下面的结构体中选值。
 struct  DrawMatchesFlags 
 {
 	enum
 	{
 		DEFAULT = 0,  //创建图像矩阵(使用Mat::create()),使用现存的输出图像来绘制关键点和匹配点。对每一个关键点只绘制中间点
 		DRAW_OVER_OUTIMG = 1, //不创建输出图像矩阵,而是在输出图像上绘制匹配对
 		NOT_DRAW_SINGLE_POINTS = 2, //单点特征点不被绘制
 		DRAW_PITCH_KEYPOINTS = 4  //对每一个关键点,绘制带大小和方向的关键点圆圈
 	};
 };

2.1.5 KeyPoint类

KeyPoint类是一个为特征点检测而生的数据结构,用于表示特征点。
在这里插入图片描述

class KeyPoint
{
	Point2f pt; //坐标
	float angle;  //特征点的方向, 值为【0~360】
	float response;  
	int octave;   //特征点所在图像金字塔的组
	int class_id;  //用于聚类的id

2.1.6 实例:SURF特征点检测

这个程序涉及三方面:

  • 使用FeatureDetector接口发现感兴趣点;
  • 使用SiftFeatureDetector以及其函数detect来实现检测过程;
  • 使用函数drawKeypoints绘制检测出来的关键点;
    实例代码:
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 
#include 
using namespace std;
using namespace cv;

int main(int argc, char **argv)
{
    //[0]改变console字体颜色
    // system("color 2F");

    //[1]载入原图片并显示
    Mat srcImage1 = imread("../1.jpg", 1);
    Mat srcImage2 = imread("../2.jpg", 1);
    if(!srcImage1.data || !srcImage2.data) {
        printf("读取路径有错误!\n");
        return false;
    }
    imshow("原始图1", srcImage1);
    imshow("原始图2", srcImage2);

    //[2]定义需要用到的变量和类
    // int minHessian = 400;   //定义SURF中的hessian阈值特征点检测算子
    Ptr<FeatureDetector> detector = SIFT::create();  //定义一个特征检测类对象
    std::vector<KeyPoint> KeyPoints_1, KeyPoints_2;  //vector模板类是能够存放任意类型的动态数组,能够增加和收缩数据


    //[3]调用detect函数检测出SIFT特征关键点,保存在vector容器中
    detector->detect(srcImage1, KeyPoints_1);
    detector->detect(srcImage2, KeyPoints_2);


    //[4]绘制特征关键点
    Mat image_keypoints_1;
    Mat image_keypoints_2;
    drawKeypoints(srcImage1, KeyPoints_1, image_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
    drawKeypoints(srcImage2, KeyPoints_2, image_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    //[5]显示效果图
    imshow("特征检测效果图1", image_keypoints_1);
    imshow("特征检测效果图2", image_keypoints_2);

    while(char(waitKey(1) != 'q')) {}

    // waitKey(0);
    return 0;

}

CMakeLists.txt

cmake_minimum_required(VERSION 3.6)
project(vo1)
set(CMAKE_BUILD_TYPE "Release")

find_package(OpenCV 3 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(sift 1.cpp)
target_link_libraries(sift ${OpenCV_LIBS})

运行结果:
OpenCV角点检测—Harris,SIFT,ORB(7)_第2张图片

2.2 SURF特征提取

SURF算法为每个检测到的特征点定义了位置和尺寸,尺寸值可以用于定义围绕特征点的窗口的大小,不论物体的尺寸窗口是怎样的,都将包含相同的信息。这些信息用于表示特征点以使得他们不同。
在特征匹配中,描述子用N为向量,在光照不变的理想情况下很理想。优质的描述子可以通过简单的距离测量进行比较,比如欧式距离。
进行特征点的描述主要是drawMathesBruteForceMatche类的运用。

2.2.1 绘制匹配点:drawMatches()函数

drawMatches()用于绘制出相匹配的两个图像的关键点
原型:
void drawMatches(const Mat& img1, const vector& keypoints1, const Mat& img2, const vector& keypoints2, const vector& matches1to2, Mat& outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const vector&matchesMask=vector(), intflags=DrawMatchesFlags::DEFAULT)
其中const vector& matches1to2 参数还可以写成:const vector&matches1to2。
const vector&matchesMask=vector()可以写成:const vector& matchesMask = vector();

  • 参数一:第一幅原图像;
  • 参数二:根据第一幅原图像得到的特征点,输出参数;
  • 参数三:第二幅原图像;
  • 参数四:根据第二幅原图像得到的特征点,输出参数;
  • 参数五:matches1to2,第一幅图到第二幅图的匹配点,即表示每一个图1中的特征点在图2中有一个对应点;
  • 参数六:输出图像,取决于参数十标志;
  • 参数七:匹配的输出颜色,即线与关键点的颜色。默认是Scalar::all(-1),表示颜色是随即生成的;
  • 参数八:单一特征点的颜色,也是随机生成的;
  • 参数九:确定哪些匹配是会绘制出来掩模,如果掩模为空,表示所有的匹配都进行绘制;
  • 参数十:特征绘图标志,默认DEFAULT,值从DrawMatchesFlags结构体中选择
 struct  DrawMatchesFlags 
 {
 	enum
 	{
 		DEFAULT = 0,  //创建图像矩阵(使用Mat::create()),使用现存的输出图像来绘制关键点和匹配点。对每一个关键点只绘制中间点
 		DRAW_OVER_OUTIMG = 1, //不创建输出图像矩阵,而是在输出图像上绘制匹配对
 		NOT_DRAW_SINGLE_POINTS = 2, //单点特征点不被绘制
 		DRAW_PITCH_KEYPOINTS = 4  //对每一个关键点,绘制带大小和方向的关键点圆圈
 	};
 };

2.2.2 BruteForceMatcher类源码分析

接下来,我们通过BruteForceMatcher类的源码分析用于暴力匹配的操作。
~/Documents/test_code/opencv-3.4.15/modules/cudalegacy/include/opencv2$
路径下有features2d.hpp文件,可以找到匹配类的定义;
在这里插入图片描述
在这里插入图片描述
可以看到DescriptorMatcher类和我门之前看到的FeatureDetector类和DescriptorExtractor类一样,都继承自Algorithm类。
用多最多的匹配方法就是DescriptorMatcher 中的:
为各种描述子找到最佳的匹配:
在这里插入图片描述

2.2.3 实例:SURF特征点提取

OpenCV角点检测—Harris,SIFT,ORB(7)_第3张图片
OpenCV角点检测—Harris,SIFT,ORB(7)_第4张图片
可以看到我们用DescriptorExtractor类进行特征向量的相关计算。SIFT特征的描述方法FeatureDetector类中封装了detect函数可以检测SIFT特征的关键点,保存在vector中,第二步,利用DescriptorExtractor类进行特征向量的相关计算,将之前的vector变量变成矩阵保存在Mat中。最后强行匹配两幅图像的特征向量,利用BfMatch类中的match()函数。
图像特征点匹配流程:

  • 使用DescriptorExtractor接口来寻找关键点对应的特征向量
  • 使用DescriptorExtractor以及它的函数compute来完成特定的计算;
  • 使用Matcher来匹配特征向量
  • 使用drawMatches来绘制检测到的匹配点

OpenCV提供了一个通用的类,用于提取不同特征点的描述子,如下:

//计算描述子
DescriptorExtractor  extractor;
Mat descriptors1, descriptors2;
extractor.compute(srcImage1, keypoint1, descriptrors1);
extractor.compute(srcImage2, keypoint2, descriptrors2);

这里的结果是一个Mat 矩阵,它的函数和特征点的个数相同,每一行都是一个N维描述子的向量,比如SURF就是64维的,该向量描述了特征点周围的强度。例如,检测到两幅图像中的特征,然后对他们提取描述子,第一幅图中每个特征描述子向量与第二幅的比较,得到最高的一对描述子,被视为那个特征的最佳。对第一幅所有的特征点进行重复,就是暴力匹配的过程。

//使用BruteForce进行匹配
BFMatcher matcher;
std::vector<DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);

BFMatcher是由DescriptorMatcher派生出的一个类,而DescriptorMatcher定义了不同匹配策略的公共接口。调用match()后,第三个参数输出一个cv::DMatch向量。于是我们需要定义一个std::vector类型的matches.

调用match后,可以使用drawMatches方法对匹配到的点进行绘制,并最终显示出来。

//绘制从两个图中匹配出来的关键点
Mat imatgeMatches;
drawMatches(srcImage1, keyPoint1, srcImage2, keyPoint2, matches, imageMatches);  //进行绘制
//显示效果图
imshow("匹配图", imageMatches);

示例代码:

#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 

using namespace std;
using namespace cv;
int main()
{
    //[1]载入图像
    Mat srcImage1 = imread("../1.jpg", 1);
    Mat srcImage2 = imread("../2.jpg", 1);
    if(!srcImage1.data || !srcImage2.data) {
        printf("读取图片错误!\n");
        return false;
    }

    //[2]使用SIFT算法检测关键点
    Ptr<FeatureDetector> detector = ORB::create();//定义一个特征检测对象;
    std::vector<KeyPoint> keypoints1, keypoints2;

    //[3]调用detect函数来检测SIFT的特征点,保存在vector中
    detector->detect(srcImage1, keypoints1);
    detector->detect(srcImage2, keypoints2);

    //[4]计算描述符(特征向量)
    Ptr<DescriptorExtractor> extractor = ORB::create();
    Mat descriptors1, descriptors2;
    extractor->compute(srcImage1, keypoints1, descriptors1);
    extractor->compute(srcImage2,keypoints2, descriptors2);

    //[5]使用暴力匹配
    //实例化一个匹配器
    // Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming");
    Ptr<DescriptorMatcher>  matcher= DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE_HAMMINGLUT);
    std::vector<DMatch> matches;
    //匹配两幅图中的描述子
    matcher->match(descriptors1, descriptors2, matches);

    //[6]绘制从图像中匹配出的关键点
    Mat imageMatches;
    drawMatches(srcImage1, keypoints1, srcImage2, keypoints2, matches,imageMatches);//进行绘制

    //[7]显示效果
    imshow("匹配图", imageMatches);

    // waitKey(0);
    while(char(waitKey(1) != 'q')){}
    return 0;
    
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.6)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(open  1.cpp)
target_link_libraries(open ${OpenCV_LIBS})

运行出现错误:在这里插入图片描述
解决方法:将compute和detect的数据操作改成指针类型的;

实现效果:
OpenCV角点检测—Harris,SIFT,ORB(7)_第5张图片

你可能感兴趣的:(opencv学习,opencv,slam)