最终效果:


其实这个小功能非常有用,甚至加上只有给人感觉好像人脸检测,目标检测直接成了demo了,主要代码如下:
// localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene; for (size_t i = 0; i < good_matches.size(); ++i)
{
// get the keypoints from the good matches
obj.push_back(keyPoints_1[ good_matches[i].queryIdx ].pt);
scene.push_back(keyPoints_2[ good_matches[i].trainIdx ].pt);
}
Mat H = findHomography( obj, scene, CV_RANSAC ); // get the corners from the image_1
std::vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0);
obj_corners[1] = cvPoint( img_1.cols, 0);
obj_corners[2] = cvPoint( img_1.cols, img_1.rows);
obj_corners[3] = cvPoint( 0, img_1.rows);
std::vector<Point2f> scene_corners(4); perspectiveTransform( obj_corners, scene_corners, H); // draw lines between the corners (the mapped object in the scene - image_2)
line( img_matches, scene_corners[0] + Point2f( img_1.cols, 0), scene_corners[1] + Point2f( img_1.cols, 0),Scalar(0,255,0));
line( img_matches, scene_corners[1] + Point2f( img_1.cols, 0), scene_corners[2] + Point2f( img_1.cols, 0),Scalar(0,255,0));
line( img_matches, scene_corners[2] + Point2f( img_1.cols, 0), scene_corners[3] + Point2f( img_1.cols, 0),Scalar(0,255,0));
line( img_matches, scene_corners[3] + Point2f( img_1.cols, 0), scene_corners[0] + Point2f( img_1.cols, 0),Scalar(0,255,0));


基本原理是利用函数:findHomography,该 函数是求两幅图像的单应性矩阵或者叫(单映射矩阵),它是一个3*3的矩阵。findHomography: 计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列) ,使用最小均方误差或者RANSAC方法 。

    单应性矩阵算过后的投影点的偏移量 scene_corners[0],就是在匹配图像中的点的位置,因为效果图像相当于增加了一个待匹配图像的宽度,所以每一个点都要加上Point2f( img_1.cols, 0)

两个重要函数的介绍:

findHomography

功能:在两个平面之间寻找单映射变换矩阵 结构:
Mat findHomography(InputArray srcPoints, InputArray dstPoints, int method=0, double ransacReprojThreshold=3, OutputArray mask=noArray() )

srcPoints :在原平面上点的坐标,CV_32FC2 的矩阵或者vector<Point2f> 
dstPoints :在目标平面上点的坐标,CV_32FC2 的矩阵或者 vector<Point2f> . 
method – 
用于计算单映射矩阵的方法.  
0 - 使用所有的点的常规方法 
CV_RANSAC - 基于 RANSAC 的方法

CV_LMEDS - 基于Least-Median 的方法

ransacReprojThreshold: 处理一组点对为内部点的最大容忍重投影误差(只在RANSAC方法中使用),其形式为:

如果     

那么点i则被考虑为内部点,如果srcPoints和dstPoints是以像素为单位,通常把参数设置为1-10范围内

这个函数的作用是在原平面和目标平面之间返回一个单映射矩阵

因此反投影误差 是最小的。

如果参数被设置为0,那么这个函数使用所有的点和一个简单的最小二乘算法来计算最初的单应性估计,但是,如果不是所有的点对都完全符合透视变换,那么这个初始的估计会很差,在这种情况下,你可以使用两个robust算法中的一个。 RANSAC 和LMeDS , 使用坐标点对生成了很多不同的随机组合子集(每四对一组),使用这些子集和一个简单的最小二乘法来估计变换矩阵,然后计算出单应性的质量,最好的子集被用来产生初始单应性的估计和掩码。 
RANSAC方法几乎可以处理任何异常,但是需要一个阈值, LMeDS 方法不需要任何阈值,但是只有在inliers大于50%时才能计算正确,最后,如果没有outliers和噪音非常小,则可以使用默认的方法。

PerspectiveTransform

功能:向量数组的透视变换

结构:

void perspectiveTransform(InputArray src, OutputArray dst, InputArray m)

src :输入两通道或三通道的浮点数组,每一个元素是一个2D/3D 的矢量转换

dst :输出和src同样的size和type 
m :3x3 或者4x4浮点转换矩阵 
转换方法为:

 

文档官方介绍:

实现代码:


// OpenCV_sift.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream> #include <vector>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/legacy/legacy.hpp"
#include "opencv2/calib3d/calib3d.hpp" using namespace cv;
using namespace std; #pragma comment(lib,"opencv_core2410d.lib")
#pragma comment(lib,"opencv_highgui2410d.lib")
#pragma comment(lib,"opencv_objdetect2410d.lib")
#pragma comment(lib,"opencv_imgproc2410d.lib")
#pragma comment(lib,"opencv_features2d2410d.lib")
#pragma comment(lib,"opencv_legacy2410d.lib")
#pragma comment(lib,"opencv_calib3d2410d.lib") int main()
{
Mat img_1 = imread("1.jpg");
Mat img_2 = imread("2.jpg");
if (!img_1.data || !img_2.data)
{
cout << "error reading images " << endl;
return -1;
} ORB orb;
vector<KeyPoint> keyPoints_1, keyPoints_2;
Mat descriptors_1, descriptors_2; orb(img_1, Mat(), keyPoints_1, descriptors_1);
orb(img_2, Mat(), keyPoints_2, descriptors_2); BruteForceMatcher<HammingLUT> matcher;
vector<DMatch> matches;
matcher.match(descriptors_1, descriptors_2, matches); double max_dist = 0; double min_dist = 100;
//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_1.rows; i++ )
{
double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );
//-- Draw only "good" matches (i.e. whose distance is less than 0.6*max_dist )
//-- PS.- radiusMatch can also be used here.
std::vector< DMatch > good_matches;
for( int i = 0; i < descriptors_1.rows; i++ )
{
if( matches[i].distance < 0.6*max_dist )
{
good_matches.push_back( matches[i]);
}
} Mat img_matches;
drawMatches(img_1, keyPoints_1, img_2, keyPoints_2,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); // localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene; for (size_t i = 0; i < good_matches.size(); ++i)
{
// get the keypoints from the good matches
obj.push_back(keyPoints_1[ good_matches[i].queryIdx ].pt);
scene.push_back(keyPoints_2[ good_matches[i].trainIdx ].pt);
}
Mat H = findHomography( obj, scene, CV_RANSAC ); // get the corners from the image_1
std::vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0);
obj_corners[1] = cvPoint( img_1.cols, 0);
obj_corners[2] = cvPoint( img_1.cols, img_1.rows);
obj_corners[3] = cvPoint( 0, img_1.rows);
std::vector<Point2f> scene_corners(4); perspectiveTransform( obj_corners, scene_corners, H); // draw lines between the corners (the mapped object in the scene - image_2)
line( img_matches, scene_corners[0] + Point2f( img_1.cols, 0), scene_corners[1] + Point2f( img_1.cols, 0),Scalar(0,255,0));
line( img_matches, scene_corners[1] + Point2f( img_1.cols, 0), scene_corners[2] + Point2f( img_1.cols, 0),Scalar(0,255,0));
line( img_matches, scene_corners[2] + Point2f( img_1.cols, 0), scene_corners[3] + Point2f( img_1.cols, 0),Scalar(0,255,0));
line( img_matches, scene_corners[3] + Point2f( img_1.cols, 0), scene_corners[0] + Point2f( img_1.cols, 0),Scalar(0,255,0)); imshow( "Match", img_matches);
cvWaitKey();
return 0;
}


当然也可以用其他特征点检测的算法来做:
/*
SIFT sift;
sift(img_1, Mat(), keyPoints_1, descriptors_1);
sift(img_2, Mat(), keyPoints_2, descriptors_2);
BruteForceMatcher<L2<float> > matcher;
*/ /*
SURF surf;
surf(img_1, Mat(), keyPoints_1);
surf(img_2, Mat(), keyPoints_2);
SurfDescriptorExtractor extrator;
extrator.compute(img_1, keyPoints_1, descriptors_1);
extrator.compute(img_2, keyPoints_2, descriptors_2);
BruteForceMatcher<L2<float> > matcher;
*/



图片:












参考文献:
ORB特征
早在,OpenCV2.3RC中已经有了实现
OpenCV中ORB特征这个是之前系列中转载整理的文章
5.http://blog.csdn.net/merlin_q/article/details/7026375

OpenCV特征点检测匹配图像-----添加包围盒的更多相关文章

  1. OpenCV特征点检测------ORB特征

    OpenCV特征点检测------ORB特征 ORB是是ORiented Brief的简称.ORB的描述在下面文章中: Ethan Rublee and Vincent Rabaud and Kurt ...

  2. python+OpenCV 特征点检测

    1.Harris角点检测 Harris角点检测算法是一个极为简单的角点检测算法,该算法在1988年就被发明了,算法的主要思想是如果像素周围显示存在多于一个方向的边,我们认为该点为兴趣点.基本原理是根据 ...

  3. OpenCV特征点检测------Surf(特征点篇)

    Surf(Speed Up Robust Feature) Surf算法的原理                                                              ...

  4. OpenCV特征点检测——Surf(特征点篇)&flann

    学习OpenCV--Surf(特征点篇)&flann 分类: OpenCV特征篇计算机视觉 2012-04-20 21:55 19887人阅读评论(20)收藏举报 检测特征 Surf(Spee ...

  5. OpenCV特征点检测——ORB特征

            ORB算法 目录(?)[+] 什么是ORB 如何解决旋转不变性 如何解决对噪声敏感的问题 关于尺度不变性 关于计算速度 关于性能 Related posts 什么是ORB 七 4 Ye ...

  6. OpenCV特征点检测

    特征点检测 目标 在本教程中,我们将涉及: 使用 FeatureDetector 接口来发现感兴趣点.特别地: 使用 SurfFeatureDetector 以及它的函数 detect 来实现检测过程 ...

  7. OpenCV特征点检测算法对比

    识别算法概述: SIFT/SURF基于灰度图, 一.首先建立图像金字塔,形成三维的图像空间,通过Hessian矩阵获取每一层的局部极大值,然后进行在极值点周围26个点进行NMS,从而得到粗略的特征点, ...

  8. OpenCV 特征点检测

    #include <stdio.h> #include <iostream> #include "opencv2/core/core.hpp" #inclu ...

  9. OPENCV图像特征点检测与FAST检测算法

    前面描述角点检测的时候说到,角点其实也是一种图像特征点,对于一张图像来说,特征点分为三种形式包括边缘,焦点和斑点,在OPENCV中,加上角点检测,总共提供了以下的图像特征点检测方法 FAST SURF ...

随机推荐

  1. 5分钟快速打造WebRTC视频聊天

    百度一下WebRTC,我想也是一堆.本以为用这位朋友( 搭建WebRtc环境 )的SkyRTC-demo 就可以一马平川的实现聊天,结果折腾了半天,文本信息都发不出去,更别说视频了.于是自己动手. 想 ...

  2. Django Class Views

    一.Base views View class django.views.generic.base.View 主要的基于类的基本视图.所有其他基于类的视图都从这个基类继承而来.它不是一个通用的视图,因 ...

  3. (转)Ensemble2015安装

    1 IIS安装和windows系统配置 1.1 IIS安装 检查是否安装好了IIS,可在[管理工具]的[服务管理器]中查看,如下图所示表示安装了IIS.   确认IIS已完全安装,点击上图中的Web服 ...

  4. 数组中存放对象之java中定义类数组存放类

    public class ClassArrayDemo { int age; String name; ClassArrayDemo(int age, String name) { this.age ...

  5. expect IDENTIFIER, actual IDENTIFIER 处理

    涉及到注入数据库的报错,这是很常见的了. 但是期望IDENTIFIER,实际IDENTIFIER 的报错,你们知道是什么意思吗? 我已开始看到的时候,是mybatis报错发神经了,报错了报错.再跑一次 ...

  6. 跨域资源共享CORS与JSONP

    同源策略限制: 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果没有同源策略,攻击者可以通过JavaScript获取你的邮件以及其他敏感信息,比如说 ...

  7. Mybatis自动生成实体类和实体映射工具

    Mybatis Mysql生成实体类 用到的Lib包: mybatis-generator-core-1.3.2.jarmysql-connector-java-5.1.30.jar 1. 创建一个文 ...

  8. linkList hashSet ArrayList IO 序列化 1.1.瞬态transient .字符编码表 Properties

      Day12 IO  序列化 .递归_递归的概念_注意事项 1.递归:方法的递归调用--它是一种方法调用的方式--方法可以调用其本身 2.注意事项: 1).递归必须要有一个"出口(结束的条 ...

  9. MS SQL Server 2008 R2 常规操作

    列出当前数据库使用的所有文件 DBCC showfilestats 转移当前文件组中某个文件的数据到同文件组中的其他文件中 DBCC SHRINKFILE ('file', EMPTYFILE); 移 ...

  10. python笔记二(数据类型和变量、编码方式、字符串的编码、字符串的格式化)

    一.数据类型 python可以直接处理的数据类型有:整数.浮点数.字符串.布尔值.空值. 整数 浮点数 字符串:双引号内嵌套单引号,可以输出 i'm ok. 也可以用\来实现,\n 换行 \t tab ...