要点初见:OpenCV3中ORB特征提取算法的实现与分析

2023-05-16

ORB特征提取算法是一种通过检测提取待测图片与模板图片中的灰度特征,实现模板图片与待测图片匹配的一种特征提取算法。相比于模板匹配matchTemple,ORB更集中于图像的灰度细节,速度也更快。

ORB的全称是ORiented Brief,也被称为rBrief。该算法在ICCV2011上由《ORB: an efficient alternative to SIFT or SURF》一文提出,并很快被收录于OpenCV2版本中。在OpenCV3.0中曾被放到OpenCV-contrib第三方扩展包中(当时可能因为版权),后来又被集成回OpenCV3本体中。ORB在OpenCV中分为CPU、GPU(CUDA)两种实现途径,ORB本身是为无法用GPU加速的CPU运算处理器设计的,网上能查到的CPU版ORB算法程序也占大多数,此文也暂时先介绍CPU版的ORB程序。

相比于先前的surf、sift特征提取算法,ORB的运行效率都更快(超过10倍),且具有surf和sift都不具备的旋转不变性。ORB本身不具备尺度不变性,但OpenCV里通过图像金字塔使ORB算法仍能检测出发生了一定程度尺度变换的目标,并通过透视变换等方法校正目标。(详情可参考毛星云的《OpenCV3编程入门》)

博主此文中的ORB代码在OpenCV3.1与3.3上都进行了实现,运行环境为Ubuntu14.04与16.04,代码复制后修改待测图像、模板图像的文件名,在编译中加入OpenCV的动态库,可直接使用。

博主用的模板是


分辨率为170*209,命名为model.jpg;

用的目标检测图片是


分辨率为1200*668,命名为ORB_test.jpg;

在IDE中创建C++项目,用C++11的规则运行如下程序:

#include <iostream>
#include <signal.h>
#include <vector>

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;


int main()
{
	Mat img_1 = imread("model.jpg");
	Mat img_2 = imread("ORB_test.jpg");

	if (!img_1.data || !img_2.data)
	{
		cout << "error reading images " << endl;
		return -1;
	}

	vector<Point2f> recognized;
	vector<Point2f> scene;

	recognized.resize(500);
	scene.resize(500);

	Mat d_srcL, d_srcR;

	Mat img_matches, des_L, des_R;
	//ORB算法的目标必须是灰度图像
	cvtColor(img_1, d_srcL, COLOR_BGR2GRAY);//CPU版的ORB算法源码中自带对输入图像灰度化,此步可省略
	cvtColor(img_2, d_srcR, COLOR_BGR2GRAY);

	Ptr<ORB> d_orb = ORB::create();

	Mat d_descriptorsL, d_descriptorsR, d_descriptorsL_32F, d_descriptorsR_32F;

	vector<KeyPoint> keyPoints_1, keyPoints_2;

	//设置关键点间的匹配方式为NORM_L2,更建议使用 FLANNBASED = 1, BRUTEFORCE = 2, BRUTEFORCE_L1 = 3, BRUTEFORCE_HAMMING = 4, BRUTEFORCE_HAMMINGLUT = 5, BRUTEFORCE_SL2 = 6 
	Ptr<DescriptorMatcher> d_matcher = DescriptorMatcher::create(NORM_L2);

	std::vector<DMatch> matches;//普通匹配
	std::vector<DMatch> good_matches;//通过keyPoint之间距离筛选匹配度高的匹配结果

	d_orb -> detectAndCompute(d_srcL, Mat(), keyPoints_1, d_descriptorsL);

	d_orb -> detectAndCompute(d_srcR, Mat(), keyPoints_2, d_descriptorsR);

	d_matcher -> match(d_descriptorsL, d_descriptorsR, matches);

	int sz = matches.size();
	double max_dist = 0; double min_dist = 100;

	for (int i = 0; i < sz; i++)
	{
		double dist = matches[i].distance;
		if (dist < min_dist) min_dist = dist;
		if (dist > max_dist) max_dist = dist;
	}

	cout << "\n-- Max dist : " << max_dist << endl;
	cout << "\n-- Min dist : " << min_dist << endl;

	for (int i = 0; i < sz; i++)
	{
		if (matches[i].distance < 0.6*max_dist)
		{
			good_matches.push_back(matches[i]);
		}
	}
	//提取良好匹配结果中在待测图片上的点集,确定匹配的大概位置
	for (size_t i = 0; i < good_matches.size(); ++i)
	{
		scene.push_back(keyPoints_2[ good_matches[i].trainIdx ].pt);
	}

	for(unsigned int j = 0; j < scene.size(); j++)
		cv::circle(img_2, scene[j], 2, cv::Scalar(0, 255, 0), 2);
	//画出普通匹配结果
	Mat ShowMatches;
	drawMatches(img_1,keyPoints_1,img_2,keyPoints_2,matches,ShowMatches);
	imshow("matches", ShowMatches);
	imwrite("matches.png", ShowMatches);
	//画出良好匹配结果
	Mat ShowGoodMatches;
	drawMatches(img_1,keyPoints_1,img_2,keyPoints_2,good_matches,ShowGoodMatches);
	imshow("good_matches", ShowGoodMatches);
	imwrite("good_matches.png", ShowGoodMatches);
	//画出良好匹配结果中在待测图片上的点集
	imshow("MatchPoints_in_img_2", img_2);
	imwrite("MatchPoints_in_img_2.png", img_2);
	waitKey(0);

	return 0;
}

程序运行结果如下:

1、显示模板、待测图间keyPoint之间的最大、最小距离,用于筛选良好的匹配结果:


2、显示良好的匹配结果,程序中设置模板与待测图间keyPoint的距离在最大keyPoint距离的0.6倍以内。从显示的图像上可见,drawMatches将模板与待测图连接并放在一张图上,keyPoint一般是选择图形的边缘、灰度变化较大的地方,这也意味着图像中若图形边缘较多,灰度变化的地方较多,则关键点也较多,匹配的效果也更好


博主也试过将待测图片换成摄像头输入(将OpenCV读入的摄像头图像>>img_2,核心程序用for循环即可),在drawMatches的显示中效果极佳,模板与摄像头图像中的目标匹配良好,说明ORB算法完全可用于摄像头的目标检测。但根据博主的测试经验,将ORB用于摄像头目标检测需注意两点:

(1)模板的灰度变换一定要较多且明显(否则在复杂环境下匹配集中度不高),建议使用相同摄像头在相同分辨率下获取模板(OpenCV获取模板的程序博主下几篇文章中将给出);

(2)一旦摄像头全黑,程序无法匹配到任何图像时ORB程序将崩溃,可能需要用try或守护进程等解决方法(一定时间间隔检查程序是否在运行,不在运行则启动程序)。

3、显示普通匹配结果,以示良好匹配与普通匹配间的差别。该匹配结果和match选择方法也有很大关系,在合适的match方法作用下,良好匹配结果的匹配线应尽可能相互平行,或呈扇形(和旋转目标进行匹配):


4、显示良好匹配结果中在待测图片上的点集,可见大多数在灰度变化较大、较密集的地方,匹配程度较高,但附近也存在误差点。既然已将这些点集提取出,之后就可用概率统计分布的方式排除误差,框出目标的大概位置。


得到目标的大概位置后,一般要用OpenCV中的透视变换perspectiveTransform或warpPerspective来确定、框出物体的实际位置,确认其中心坐标。博主也在研究这一方面的内容,可能需要和matchTemple模板匹配结合,欢迎讨论!

附上相关博文:

OpenCV实用程序:“OpenCV相机”——获取、保存选定时刻的摄像头图像(待测图片换为摄像头输入时,用此方法获取特征提取的模板)
http://blog.csdn.net/m0_37857300/article/details/79038894

要点初见:OpenCV3中CUDA ORB特征提取算法的实现(GPU加速的ORB算法)
http://blog.csdn.net/m0_37857300/article/details/79039214

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

要点初见:OpenCV3中ORB特征提取算法的实现与分析 的相关文章

  • 【Windows版】CMake安装教程

    一 参考资料 windows 43 cmake 43 mingw 搭建c c 43 43 开发环境 二 步骤 1 官网下载CMake安装包 CMake官网 2 解压安装包 D 360Downloads Software CMake cmak
  • GNSS入门2-RTD, RTK,精度

    2 1 RTD vs RTK RTD xff08 Real Time Differential xff09 xff1a 实时码 xff08 C A码 P码 xff09 相位差分技术 xff0c 流动站与基站距离需小于100km xff0c
  • 关于嵌入式开发的C语言基础总结

    一 位操作 C语言支持的6种位操作符如下 xff1a 1 不改变其他位的值的状况下 xff0c 对某几个位进行设值 方法 xff1a 先对需要设置的位用 amp 操作符 xff08 对应位 amp 0 xff09 进行清零操作 xff0c
  • STM32 ASSERT断言机制

    调试代码经常会有跑崩的时候 xff0c 当整机调试是出问题特别让人崩溃 xff0c 断言机制能很好的定位由于参数错误导致的系统异常的情况 在代码重要的代码区 xff0c 添加断言 xff0c 相当于对出入参数做了预判操作 xff0c 当参数
  • 舵机抖动的原因分析

    舵机抖动 舵机在很多场合都会用到 xff0c 比如航模 云台等 但有时候舵机会莫名的出现抖动 xff0c 最近我也遇到了这个问题 xff0c 花了两天的时间终于解决了 舵机抖动的原因主要有以下几点 xff1a 1 电源电压不足 xff1a
  • ubuntu系统python实现串口通信

    我使用的是USB TTL串口 xff0c 下面是测试之前的一些准备工作 span class token function ls span dev span class token comment 查看设备 xff0c 插拔串口设备注意有没
  • __FILE__,__func__,__LINE__用法举例

    C语言中 xff0c FILE func LINE 常用于logout xff0c 打trace xff0c debug调试 注意 xff1a 其使用不需要定义 xff0c FILE 指示当前文件名 func 指示当前函数名 LINE 指示
  • STM32 串口超时中断+DMA接收不定长数据 比 空闲中断(IDLE)更加灵活、稳定(一)

    前言 xff1a 最近项目有使用串口接收大段不定长GPS数据的需求 xff0c 调试了很久 xff0c 终于找到一个比较好的解决办法 我觉得这个项目需求 xff08 高波特率 大段数据 不定长 xff09 十分典型 xff0c 所以在这里记
  • STM32串口通信(基于缓冲区)

    一 串口的初始化和中断设置 1 初始化GPIO xff1a 根据手册的8 1 11节 xff0c 我们可以找到下表 xff1a 在全双工的模式下 xff0c 发送引脚需要设置为推挽复用输出 xff0c 接收引脚则设置为浮空输入或带上拉的输入
  • STM32与C#上位机串口通信示例

    1 概述 串口通信是一种非常常用的通信方式 xff0c 本文首先介绍了串口硬件和协议的相关内容 xff0c 然后给出一个STM32与C 上位机通过串口通信的示例 2 串口介绍 参考这份文档 3 通信协议 为了方便数据传输 xff0c 定义了
  • 【转】23个常用的VSCode快捷键(动图演示)

    尽管我们经常使用 VS Code中的许多快捷方式 xff0c 但是我们有可能会忘记它们 这里用可视化制作了一些GIF xff0c 以便更好地记住它们 xff0c 希望对你有所帮助 VSCode中的每个命令也可以通过使用CTRL 43 SHI
  • HI3531编码h.264文件播放偏慢分析随笔

    现象 xff1a 编码h 264文件播放时 xff0c 无论帧率是30fps还是60fps xff0c 播放器显示帧率为25 fps 探索过程 xff1a cat proc umap venc 显示得知 xff0c 编码的的确是30fps和
  • C++ const用法详解

    const 是C 43 43 中常用的类型修饰符 常类型是指使用类型修饰符const说明的类型 xff0c 常类型的变量或对象的值是不能被更新的 目录 一 const的作用 二 const修饰普通类型的变量 三 const修饰指针变量 四
  • Source Insight 4.0打开一会就闪退 解决方法

    遇到Source Insight 4 0打开直接闪退 xff0c 请不要着急卸载 xff0c 在Source Insight 4 0快捷键上 xff0c 点击属性 xff0c 选择兼容性如下 xff1a
  • secureCRT连接ubuntu18.04

    1 安装ssh服务器 sudo apt get install openssh server 2 ssh服务器安装失败 错误提示 xff1a 下列软件包有未满足的依赖关系 xff1a openssh server 原因 xff1a 系统预置
  • STM32——USART串口通信与串口重定向

    简介 UART 通用异步收发传输器 xff08 Universal Asynchronous Receiver Transmitter xff0c 通常称 作 UART 它将要传输的资料在串行通信与并行通信之间加以转换 作为把并行输入信 号
  • 海思文件系统缺少文件himm 、i2c_read 、i2c_write 、ssp_read 、ssp_write

    原因 xff1a 海思根文件默认没有把himm i2c read i2c write ssp read ssp write工具集成在bin里 xff0c 但是在sdk中 解决办法 xff1a cd osdrv tools board reg
  • Ubuntu 18.04 Samba服务器的安装和配置(详解)

    具体步骤 xff1a 1 设置为静态IP xff1a 点击静态IP设置链接 2 更新当前软件 sudo apt get upgrade sudo apt get update sudo apt get dist upgrade 3 安装sa
  • C52单片机(AT89C52)—流水灯

    本文重点 xff1a C52流水灯代码编写 xff0c keil如何生存hex文件和proteus如何导入hex文件 1 打开keil xff0c 建立工程 xff0c 编写如下代码 include lt reg52 h gt includ
  • Hi3516EV200图像调优

    一 平台搭建 1 将Hi3516EV200 PQ V1 0 0 3 tgz放到nfs挂载目录下解压 xff0c 进入Hi3516EV200 PQ V1 0 0 3 执行StartControl sh 2 执行HiPQTools exe xf

随机推荐