在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序

在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序
背景:

在学习高翔视觉SLAM十四讲的时候,学到视觉里程计方面,主要是学习特征检测与匹配,视觉SLAM方面介绍这块比较少,推荐学习opencv.推荐《opencv3编程入门》毛星云写的,学习opencv入门比较好的书籍。当然你的英文水平好的话可以学习官方文档教程。

注意:由于目前发行的opencv3关于特征检测算子(SURF、SIFT、ORB)已经从官方行的opencv3中移除,转移到第三方库xfeatures2d.所以想要在opencv3运行这些程序的话需要遵照下面的步骤。

一.配置opencv3.4.3(含contrib3.4.3)(按照对应版本下载)
1.下载

https://github.com/opencv/opencv/releases 请下载opencv3.4.3 Source code(zip);

https://github.com/opencv/opencv_contrib/releases/tag/3.4.3 请下载opencv_contrib3.4.3 Source code(zip);

编译contrib主要是为了使用xfeatures2d中的API,角点检测、特征提取与匹配。
2.安装

2.1安装依赖(ubuntu一般已经安装好,只是为了检查一下)

sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev

2.2解压
在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序_第1张图片
我这里并没有用命令解压,直接手动解压到 Downloads

1.将opencv-3.4.3文件夹复制到home,重命名为opencv;

2.再将opencv_contrib-3.4.3文件夹复制到opencv文件夹,重命名为opencv_contrib;

3.在opencv中新建一个build文件夹,作为编译目的路径,到此准备工作ok~如下图所示。
在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序_第2张图片

3.编译

3.1安装cmake-gui(用图形界面编译安装不易出错,简介方便)

sudo apt-get install cmake-gui

安装好了之后,进入opencv文件打开终端进入cmake-gui图形界面

cmake-gui
在这里插入图片描述

3.2使用cmake-gui编译
在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序_第3张图片

1.设置好源路径和目的路径后,点击Configure(选择Unix Makefiles),然后点击finish。

2.Configure之后我们更改两个地方:
在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序_第4张图片

    1)在CMAKE_BUILD_TYPE 值处输入RELEASE(若本身为Release则不用更改;这里说明一下,CMAKE_INSTALL_PREFIX为安装路径,系统默认为/usr/local,如若对ubuntu不熟悉,则不要更改,默认就好)。

    2)在OPENCV_EXTRA_MODULES_PATH处加入opencv_contrib路径。

注意,不是选opencv_contrib文件夹,而是需要选中opencv_contrib里面的modules文件夹!
在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序_第5张图片

3.确认无误后,点击Configure;显示Configuring done后,点击Generate生成文件;这时资源文件就出现在build文件夹中,我们可以关闭cmake了。

3.3make并install

1.在opencv/build文件夹中打开终端,输入指令编译(此次时间漫长20分钟左右)。

sudo make

2.100%后,继续输入指令安装。

sudo make install

3.sudo make install 执行完毕后OpenCV编译过程就结束了,接下来就需要配置一些OpenCV的编译环境首先将OpenCV的库添加到路径,从而可以让系统找到。

sudo gedit /etc/ld.so.conf.d/opencv.conf

4.在文件中添加,然后保存关闭,提示的错误不用管它。

/usr/local/lib

5.执行命令,使配置路径生效

sudo ldconfig

6.配置bash

sudo gedit /etc/bash.bashrc

7.在文件最后加入两行,然后保存。

PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig 
export PKG_CONFIG_PATH

8.执行命令,使配置路径生效

source /etc/bash.bashrc

9.更新系统路径

sudo updatedb

10.到此位置,我们的opencv+opencv_contrib配置完成,已经可以调用opencv库函数啦。

Clion中配置cmake-gui
在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序_第6张图片

实际操作演示

【特征点的检测与匹配】是计算机视觉中非常重要的技术之一。在物体检测、视觉跟踪、三维重建等领域都有很广泛的应用。
opencv提供了10种特征检测方法:
【FAST】
【STAR】
【SIFT】
【SURF】
【ORB】
【MSER】
【GFTT】
【HARRIS】
【Dense】
【SimpleBlob】
1【SURF特征点检测】

SURF—加速版的具有鲁棒性的特征算法(SIFT—尺寸不变特征变换算法的加速版),SURF最大特征在于采用harr特征以及积分图像的概念,
大大加速了程序的运行时间。应用于计算机视觉的物体识别、3D重建中。
缺点:严重依赖局部像素的梯度方向,容易出现方向不准等问题。
算法原理----①:选用二阶标准高斯函数作为滤波器(Hessian矩阵构造高斯金字塔尺度空间)
②:利用非极大值抑制初步确定特征点
③:精确定位极值点(采用三维线性插值法得到亚像素级的特征点)
④:选取特征点的主方向(梯度直方图,选大于等于bin值的那些方向)
⑤:构造surf特征点描述算子

绘制关键点:drawKeypoints()函数

void drawKeypoints(
const Mat&image,                       //输入图像
const vector&keypoints,      //根据原图像得到的特征点
Mat& outImage,                         //输出图像
const Scalar& color=Scalar::all(-1),  //关键点颜色(默认Scalar::all(-1))
int flags=DrawMatchesFlags::DEFAULT   //绘制关键点的特征标识符(默认DrawMatchesFlags::DEFAULT)
);

KeyPoint类-----一个为特征点检测而生的数据结构,用于表示特征点。
class KeyPoint{
Point2f pt;//坐标
float size;//特征点邻域直径
float angle;//特征点的方向,值为[0,360],负值表示不使用
float response;
int octave;//特征点所在的图像金字塔的组
int class_id;//用于聚类的id
}

综合示例:SURF特征点检测

CMakeLists.txt

cmake_minimum_required(VERSION 3.13)
project(SURF)


set(CMAKE_CXX_STANDARD 11)

find_package( OpenCV REQUIRED )

include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(SURF main.cpp)
target_link_libraries( SURF ${OpenCV_LIBS} )
//------------------------【SURF特征点检测】-----------------------------
//描述:使用FeatureDetector接口来发现感兴趣点
//      使用SurfFeatureDetector以及其函数detect来实现检测过程
//      使用函数drawKeypoints绘制检测到的关键点
//-----------------------------------------------------------------------
#include   
#include 
#include 
#include 
 
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
int main()
{
    Mat srcImage1 = imread("1.jpg", 1);
	Mat srcImage2 = imread("2.jpg", 1);
	if (!srcImage1.data || !srcImage2.data){cout << "读取图片出错" << endl;return false;}
	
	imshow("原始图1", srcImage1);
	imshow("原始图2", srcImage2);
		
	int minHessian = 100;//SURF算子检测关键点
 
    //定义一个SurfFeatureDetector(SURF)特征检测类对象
	Ptr detector = SurfFeatureDetector::create(minHessian);
	vector key_points_1, key_points_2;//vector模板类,存放任意的动态数组
	
	Mat dstImage1, dstImage2;
	
	//调用detect函数检测出SURF特征关键点,保存在vector容器中
    detector->detectAndCompute(srcImage1, Mat(), key_points_1, dstImage1);
	detector->detectAndCompute(srcImage2, Mat(), key_points_2, dstImage2);//可以分成detect和compute
	Mat img_keypoints_1, img_keypoints_2;
	
	//绘制特征关键点
	drawKeypoints(srcImage1, key_points_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
	drawKeypoints(srcImage2, key_points_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
 
	Ptr matcher = DescriptorMatcher::create("FlannBased");
	vectormach;
	matcher->match(dstImage1, dstImage2, mach);
	double Max_dist = 0;
	double Min_dist = 100;
	for (int i = 0; i < dstImage1.rows; i++)
	{
		 double dist = mach[i].distance;
		 if (dist < Min_dist)Min_dist = dist;
		 if (dist > Max_dist)Max_dist = dist;
	}
	cout << "最短距离" << Min_dist << endl;
	cout << "最长距离" << Max_dist << endl;
 
	vectorgoodmaches;
	for (int i = 0; i < dstImage1.rows; i++)
	{
	    if (mach[i].distance < 2 * Min_dist)goodmaches.push_back(mach[i]);
	}
	Mat img_maches;
    drawMatches(srcImage1, key_points_1, srcImage2, key_points_2, goodmaches, img_maches);
	
	for (int i = 0; i < goodmaches.size(); i++)
	{
		cout << "符合条件的匹配:" << goodmaches[i].queryIdx << "--" << goodmaches[i].trainIdx << endl;
	}
    imshow("效果图1", img_keypoints_1);
	imshow("效果图2", img_keypoints_2);
	imshow("匹配效果", img_maches);
	
	waitKey(0);
	return 0;
 }

运行结果如下图所示
输入图像从参考下边那张图 ./1.jpg ./2.jpg 然后输入自己的工作目录
在ubuntu+clion+opencv3.1.0中运行opencv中第三方库的程序_第7张图片

2 【FLANN特征检测与匹配】

检测关键点并计算描述符:detectAndCompute()

void detectAndCompute(
    InputArray image, //图像
    InputArray mask, //掩模
    CV_OUT std::vector& keypoints,//输出关键点的集合
    OutputArray descriptors,//计算描述符(descriptors[i]是为keypoints[i]的计算描述符)
    bool useProvidedKeypoints=false //使用提供的关键点
);

从查询集中查找每个描述符的最佳匹配:DescriptorMatcher::match()方法。

void DescriptorMatcher::match(
    const Mat& queryDescriptors, //查询描述符集
    const Mat&  trainDescriptors, //训练描述符集合
    CV_OUT std::vector& matches, //匹配
    InputArray mask=noArray() //指定输入查询和描述符的列表矩阵之间的允许匹配的掩码
);

综合示例:FLANN特征点检测

#include
#include
using namespace cv;
using namespace cv::xfeatures2d;
 
//FLANN对高维数据较快
int main()
{
	Mat src1, src2;
	src1 = imread("1.jpg");
	src2 = imread("2.jpg");
	if (src1.empty() || src2.empty()){printf("can ont load images....\n");return -1;}
	imshow("image1", src1);
	imshow("image2", src2);
 
	int minHessian = 400;
 
	//选择SURF特征
	Ptrdetector = SURF::create(minHessian);
	std::vectorkeypoints1;
	std::vectorkeypoints2;
	Mat descriptor1, descriptor2;
	//检测关键点并计算描述符
	detector->detectAndCompute(src1, Mat(), keypoints1, descriptor1);
	detector->detectAndCompute(src2, Mat(), keypoints2, descriptor2);
 
	//基于Flann的描述符匹配器
	FlannBasedMatcher matcher;
	std::vectormatches;
	//从查询集中查找每个描述符的最佳匹配
	matcher.match(descriptor1, descriptor2, matches);
	double minDist = 1000;
	double maxDist = 0;
	for (int i = 0; i < descriptor1.rows; i++)
	{
		double dist = matches[i].distance;
		printf("%f \n", dist);
		if (dist > maxDist)
		{
			maxDist = dist;
		}
		if (dist < minDist)
		{
			minDist = dist;
		}
 
	}
	//DMatch类用于匹配关键点描述符的
	std::vectorgoodMatches;
	for (int i = 0; i < descriptor1.rows; i++)
	{
		double dist = matches[i].distance;
		if (dist < max(2.5*minDist, 0.02))
		{
			goodMatches.push_back(matches[i]);
		}
	}
	Mat matchesImg;
	drawMatches(src1, keypoints1, src2, keypoints2, goodMatches, matchesImg, Scalar::all(-1), Scalar::all(-1), std::vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
	imshow("output", matchesImg);
 
	waitKey();
	return 0;
}

【FLANN结合SURF进行关键点的描述和匹配】 :

//------------------【FLANN结合SURF进行关键点的描述和匹配】----------------------
 
#include
#include
#include
#include
#include
using namespace cv::xfeatures2d;
using namespace cv;
using namespace std;
 
int main()
{
	//【1】载入原图
	Mat srcImage = imread("1.jpg");
	imshow("【原图】", srcImage);
 
	//【2】对BGR空间的图像直接进行计算很费时间,所以,需要转换为灰度图
	Mat srcGrayImage;
	cvtColor(srcImage, srcGrayImage, CV_BGR2GRAY);
 
	//【3】首先对两幅图像检测SURF关键点、提取测试图像描述符
	vector keyPoint1;
	Mat dstImage1, dstImage2;
	Ptr surf = SURF::create(80);
	surf->detect(srcGrayImage, keyPoint1);
	Mat descriImage1;
	surf->compute(srcGrayImage, keyPoint1, descriImage1);
 
	//【4】先对原图的描述子进行保留-------邻近匹配
	//FlannBasedMatcher FLMatcher;
	//因为FlannBasedMatcher类的成员函数add()的参数是一个vector的容器,所以先定义一个这样的变量,并将原图的描述子放入容器中
	//vector g_vdescriImage1(1, descriImage1);
	//调用FlannBasedMatcher类的成员函数add,将原图的描述子放在FlannBasedMatcher的对象FLMatcher中
	//FLMatcher.add(g_vdescriImage1);
	//FLMatcher.train();
 
	//【4】进行基于描述符的-------暴力匹配
	BFMatcher matcher;
	//因为FlannBasedMatcher类的成员函数add()的参数是一个vector的容器,所以先定义一个这样的变量,并将原图的描述子放入容器中
	vector g_vdescriImage1(1, descriImage1);
	//调用FlannBasedMatcher类的成员函数add,将原图的描述子放在FlannBasedMatcher的对象FLMatcher中
	matcher.add(g_vdescriImage1);
	matcher.train();
 
	VideoCapture capture;
	capture.open(0);
 
	Mat frameImage, frameGrayImage;
	while (waitKey(1) != 27)
	{
		capture >> frameImage;
 
		//<1>为了提高计算效率,将图像转换为灰度图像
		cvtColor(frameImage, frameGrayImage, CV_BGR2GRAY);
 
		//<2>检测S关键点、提取测试图像描述符
		vector keyPoints2;
		surf->detect(frameGrayImage, keyPoints2);
		Mat descriImage2;
		surf->compute(frameGrayImage, keyPoints2, descriImage2);
 
		//<3>将之前得到的原图的描述子和现在得到的描述子进行匹配(匹配训练和测试描述符)
		//成员函数knnMatch的参数是二维的DMatch向量,所以首先定义一个该容器的向量
		vector> knnDMatches;
		
		//<4>用之前已经存放原图描述子的对象来计算------邻近匹配
		//FLMatcher.knnMatch(descriImage2, knnDMatches, 2);
 
		//<4>用之前已经存放原图描述子的对象来计算------暴力匹配
		matcher.knnMatch(descriImage2, knnDMatches, 2);
		//<5>根据劳氏算法,采集优秀的匹配点
		vector goodMatches;
		for (size_t i = 0; i < knnDMatches.size(); i++)
		{
			if (knnDMatches[i][0].distance < 0.6 * knnDMatches[i][1].distance)
			{
				goodMatches.push_back(knnDMatches[i][0]);
			}
		}
		//<6>绘制匹配点并显示窗口
		Mat dstImage;
		drawMatches(frameImage, keyPoints2, srcImage, keyPoint1, goodMatches, dstImage);
 
		imshow("【结果图】", dstImage);
	}
 
	return 0;
}

3、【寻找已知物体】

寻找已知物体:在Flann特征匹配的基础上,还可以进一步利用Homography映射找出已知物体。
集体来说就是利用findHomography函数通过匹配的关键点找出相应的变量,在利用perspectiveTransform函数映射点群。

寻找透视变换:findHomography()函数----找到并返回原图像和目标图像之间的透视变换H

Mat findHomography(
    InputArray srcPoints,   //原平面上的对应点
    InputArray dstPoints,   //目标平面上的对应点
    int method=0,//用于计算单应矩阵的方法(默认0;CV_RANSAC---基于RANSAC的鲁棒性方法;CV_LMEDS---最小中值鲁棒性方法)
    double ransacReprojThreshold=3,//(默认3)处理点对为内围层时,允许重投影误差的最大值
    OutputArray mask=noArray()//可选参数
);

进行透视矩阵变换:perspectiveTransform()函数—进行向量透视矩阵变换

void perspectiveTransform(
    InputArray src,   //输入图像
    OutputArray dst,  //目标图像
    InputArray m     //变换矩阵
);

综合示例:寻找已知物体

//-------------------【寻找已知物体】---------------
#include
#include
#include 
#include 
#include 
 
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
 
int main()
{
	Mat srcImage1 = imread("1.jpg");
	Mat srcImage2 = imread("2.jpg");
	imshow("【原图1】", srcImage1);
	imshow("【原图2】", srcImage2);
 
	Mat grayImage1, grayImage2;
	cvtColor(srcImage1, grayImage1, CV_BGR2GRAY);
	cvtColor(srcImage2, grayImage2, CV_BGR2GRAY);
 
	//首先对两幅图像进行特征点的检测
	//先准备参数
	vector g_vKeyPoint1;
	vector g_vKeyPoint2;
	Ptr surf = SURF::create(400);
	surf->detect(grayImage1, g_vKeyPoint1);
	surf->detect(grayImage2, g_vKeyPoint2);
 
	//利用得到的特征点计算特征描述子
	//目的:对得到的每个特征点进行特征描述,整合到Mat类型的矩阵中(计算结果是Mat类型的)
	//该得到的结果矩阵的行数就是特征点的个数,因为是对每个点进行描述,所以每行都会有一个描述的字子向量,共同构成Mat矩阵
	Mat descriImage1, descriImage2;
	surf->compute(grayImage1, g_vKeyPoint1, descriImage1);
	surf->compute(grayImage2, g_vKeyPoint2, descriImage2);
 
	//正式开始在两幅图像中进行匹配
	//先得到一个匹配向量
	FlannBasedMatcher FLMatcher;
	vector g_vMatches;
	//g_vMatches就是得到的匹配向量
	FLMatcher.match(descriImage1, descriImage2, g_vMatches);
 
	//用找最大最小值的方式找到 两幅图像中匹配的点的距离的最大值和最小值
	//这里的 keyPoint1.size() 和 descriImage1.rows是一样的值,因为descriImage1的行数就是检测到的特征点的个数
	double minDistance = g_vMatches[0].distance, maxDistance = g_vMatches[0].distance;
	for (size_t i = 0; i < g_vKeyPoint1.size(); i++)
	{
		double currDistance = g_vMatches[i].distance;
		if (currDistance < minDistance)
			minDistance = currDistance;
		if (currDistance > maxDistance)
			maxDistance = currDistance;
	}
 
	//定义一个新的变量,用来存储 通过距离检测后  通过阀值的点
	vector newMatches;
	for (size_t i = 0; i < g_vKeyPoint1.size(); i++)
	{
		if (g_vMatches[i].distance < 2 * minDistance)
			newMatches.push_back(g_vMatches[i]);
	}
 
	//用绘制函数对匹配向量进行绘制
	Mat dstImage;
	drawMatches(srcImage1, g_vKeyPoint1, srcImage2, g_vKeyPoint2, newMatches, dstImage
		, Scalar(theRNG().uniform(0, 255), theRNG().uniform(0, 255), theRNG().uniform(0, 255))
		, Scalar(theRNG().uniform(0, 255), theRNG().uniform(0, 255), theRNG().uniform(0, 255)), Mat(), 2);
 
	imshow("【特征提取后的图像】", dstImage);
 
	//=================================正式开始寻找已知物体============================
	//为了调用 得到H矩阵findHomography函数,所以需要得到 匹配点所对应的特征点   然后作为参数传递给计算H矩阵的函数
	//所以首先是进行 匹配点和对应的特征点的转换步骤
	//将得到的点放入新的容器中,所以需要定义新的容器
	vector g_vSrcPoint2f1;
	vector g_vSrcPoint2f2;
	for (size_t i = 0; i < newMatches.size(); i++)
	{
		g_vSrcPoint2f1.push_back(g_vKeyPoint1[newMatches[i].queryIdx].pt);
		g_vSrcPoint2f2.push_back(g_vKeyPoint2[newMatches[i].trainIdx].pt);
	}
 
	//将得到的对应的特征点  计算H矩阵
	Mat H = findHomography(g_vSrcPoint2f1, g_vSrcPoint2f2, 0);
 
	////用得到的H矩阵  来进行透视矩阵变换  用到的是perspectiveTransform函数
	//vector g_vCorners1(4);
	//vector g_vCorners2(4);
	//g_vCorners1[0] = Point2f(0, 0);
	//g_vCorners1[1] = Point2f((float)srcImage1.cols, 0);
	//g_vCorners1[2] = Point2f((float)srcImage1.cols, (float)srcImage1.rows);
	//g_vCorners1[3] = Point2f(0, (float)srcImage1.rows);
 
	//perspectiveTransform(g_vCorners1, g_vCorners2, H);
 
	////在得到的两幅图像的合成图中绘制检测到的物体的直线
	//line(dstImage, (Point)g_vCorners2[0] + Point(srcImage1.cols, 0), (Point)g_vCorners2[1] + Point(srcImage1.cols, 0)
	//	, Scalar(theRNG().uniform(0, 255), theRNG().uniform(0, 255), theRNG().uniform(0, 255)), 2);
	//line(dstImage, (Point)g_vCorners2[1] + Point(srcImage1.cols, 0), (Point)g_vCorners2[2] + Point(srcImage1.cols, 0)
	//	, Scalar(theRNG().uniform(0, 255), theRNG().uniform(0, 255), theRNG().uniform(0, 255)), 2);
	//line(dstImage, (Point)g_vCorners2[2] + Point(srcImage1.cols, 0), (Point)g_vCorners2[3] + Point(srcImage1.cols, 0)
	//	, Scalar(theRNG().uniform(0, 255), theRNG().uniform(0, 255), theRNG().uniform(0, 255)), 2);
	//line(dstImage, (Point)g_vCorners2[3] + Point(srcImage1.cols, 0), (Point)g_vCorners2[0] + Point(srcImage1.cols, 0)
	//	, Scalar(theRNG().uniform(0, 255), theRNG().uniform(0, 255), theRNG().uniform(0, 255)), 2);
 
	//imshow("【检测物体后的图像】", dstImage);
 
	//进行角点检测
	////开始进行强角点检测
	////先配置需要的函数参数
	vector dstPoint2f1;
	goodFeaturesToTrack(grayImage1, dstPoint2f1, 200, 0.01, 10, Mat(), 3);
	vector dstPoint2f2(dstPoint2f1.size());
	//进行透视变换
	perspectiveTransform(dstPoint2f1, dstPoint2f2, H);
 
	//在计算得到的点中寻找最小包围矩形
	//rectPoint变量中得到了矩形的四个顶点坐标
	RotatedRect rectPoint = minAreaRect(dstPoint2f2);
	//定义一个存储以上四个点的坐标的变量
	Point2f fourPoint2f[4];
	//将rectPoint变量中存储的坐标值放到 fourPoint的数组中
	rectPoint.points(fourPoint2f);
 
	//根据得到的四个点的坐标  绘制矩形
	for (int i = 0; i < 3; i++)
	{
		line(srcImage2, fourPoint2f[i], fourPoint2f[i + 1]
			, Scalar(theRNG().uniform(0, 255), theRNG().uniform(0, 255), theRNG().uniform(0, 255)), 3);
	}
	line(srcImage2, fourPoint2f[0], fourPoint2f[3]
		, Scalar(theRNG().uniform(0, 255), theRNG().uniform(0, 255), theRNG().uniform(0, 255)), 3);
 
	imshow("【检测到的物体】", srcImage2);
 
	waitKey(0);
 
	return 0;
}

4、【ORB特征提取】

优于其他两种方法。

//------------------【ORB】--------------------------
 
#include
#include
#include
 
using namespace cv;
using namespace std;
 
int main()
{
	Mat srcImage = imread("1.jpg");
	imshow("【原图】", srcImage);
 
	//对BGR空间的图像直接进行计算很费时间,所以,需要转换为灰度图
	Mat srcGrayImage;
	cvtColor(srcImage, srcGrayImage, CV_BGR2GRAY);
 
	//首先对两幅图像进行特征点的检测和描述子的计算
	vector keyPoint1;
	Ptr orb = ORB::create(400);
	//调用detect函数检测出特征关键点,保存在vector中
	orb->detect(srcGrayImage, keyPoint1);
	Mat descriImage1;
	//计算描述符(特征向量)
	orb->compute(srcGrayImage, keyPoint1, descriImage1);
 
	//基于FLANN的描述符对象匹配
	flann::Index flannIndex(descriImage1, flann::LshIndexParams(12, 20, 2), cvflann::FLANN_DIST_HAMMING);
	
	//初始化视屏采集对象
	VideoCapture capture;
	capture.open(0);
	capture.set(CV_CAP_PROP_FRAME_WIDTH, 360);//设置采集视频的宽度
	capture.set(CV_CAP_PROP_FRAME_HEIGHT, 900);//设置采集视频的高度
 
	Mat frameImage, frameGrayImage;
 
	while (waitKey(1) != 27)
	{
		capture >> frameImage;
 
		//为了提高计算效率,将图像转换为灰度图像
		cvtColor(frameImage, frameGrayImage, CV_BGR2GRAY);
 
		//计算特征点和描述子
		vector keyPoints2;
		orb->detect(frameGrayImage, keyPoints2);
		Mat descriImage2;
		orb->compute(frameGrayImage, keyPoints2, descriImage2);
 
		//匹配和测试描述符,获取两个最临近的描述符
		Mat matchIndex(descriImage2.rows, 2, CV_32SC1);
		Mat matchDistance(descriImage2.rows, 2, CV_32SC1);
 
		//调用k邻近算法
		flannIndex.knnSearch(descriImage2, matchIndex, matchDistance, 2, flann::SearchParams());
 
 
		//采集优秀的匹配点(根据劳氏算法)
		vector goodMatches;
		for (int i = 0; i < matchDistance.rows; i++)
		{
			//........................................................................
			if (matchDistance.at(i, 0) < 0.6 * matchDistance.at(i, 1))
			{
				DMatch midDMatch(i, matchIndex.at(i, 0), matchDistance.at(i, 0));
				goodMatches.push_back(midDMatch);
			}
		}
 
		Mat dstImage;
		drawMatches(frameImage, keyPoints2, srcImage, keyPoint1, goodMatches, dstImage);
 
		imshow("【结果图】", dstImage);
	}
 
	return 0;
}

作者:qq_37894023
来源:CSDN
原文:https://blog.csdn.net/qq_37894023/article/details/85060047
版权声明:本文为博主原创文章,转载请附上博文链接!


作者:最疯狂
来源:CSDN
原文:https://blog.csdn.net/weixin_42714444/article/details/85243509
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(OpenCV)