【OpenCV学习】计算两幅图像的重叠区域
问题描述:已知两幅图像Image1和Image2,计算出两幅图像的重叠区域,并在Image1和Image2标识出重叠区域。
算法思想:
若两幅图像存在重叠区域,则进行图像匹配后,会得到一张完整的全景图,因而可以转换成图像匹配问题。
图像匹配问题,可以融合两幅图像,得到全景图,但无法标识出在原图像的重叠区域。
将两幅图像都理解为多边形,则其重叠区域的计算,相当于求多边形的交集。
通过多边形求交,获取重叠区域的点集,然后利用单应矩阵还原在原始图像的点集信息,从而标识出重叠区域。
算法步骤:
1.图像匹配计算,获取单应矩阵。
2.根据单应矩阵,计算图像2的顶点转换后的点集。
3.由图像1的顶点集合和图像2的转换点集,计算多边形交集。
4.根据单应矩阵的逆,计算多边形的交集在图像2中的原始点集。
代码实现如下所示:
1 bool ImageOverlap(cv::Mat &img1,cv::Mat &img2,std::vector<cv::Point> &vPtsImg1,std::vector<cv::Point> &vPtsImg2)
2 {
3 cv::Mat g1(img1,Rect(0,0,img1.cols,img1.rows));
4 cv::Mat g2(img2,Rect(0,0,img2.cols,img2.rows));
5
6 cv::cvtColor(g1,g1,CV_BGR2GRAY);
7 cv::cvtColor(g2,g2,CV_BGR2GRAY);
8
9 std::vector<cv::KeyPoint> keypoints_roi, keypoints_img; /* keypoints found using SIFT */
10 cv::Mat descriptor_roi, descriptor_img; /* Descriptors for SIFT */
11 cv::FlannBasedMatcher matcher; /* FLANN based matcher to match keypoints */
12 std::vector<cv::DMatch> matches, good_matches;
13 cv::SIFT sift;
14 int i, dist=80;
15
16 sift(g1, Mat(), keypoints_roi, descriptor_roi); /* get keypoints of ROI image */
17 sift(g2, Mat(), keypoints_img, descriptor_img); /* get keypoints of the image */
18 matcher.match(descriptor_roi, descriptor_img, matches);
19
20 double max_dist = 0; double min_dist = 1000;
21
22 //-- Quick calculation of max and min distances between keypoints
23 for( int i = 0; i < descriptor_roi.rows; i++ )
24 {
25 double dist = matches[i].distance;
26 if( dist < min_dist ) min_dist = dist;
27 if( dist > max_dist ) max_dist = dist;
28 }
29
30 for (i=0; i < descriptor_roi.rows; i++)
31 {
32 if (matches[i].distance < 3*min_dist)
33 {
34 good_matches.push_back(matches[i]);
35 }
36 }
37
38 //printf("%ld no. of matched keypoints in right image\n", good_matches.size());
39 /* Draw matched keypoints */
40
41 //Mat img_matches;
42 //drawMatches(img1, keypoints_roi, img2, keypoints_img,
43 // good_matches, img_matches, Scalar::all(-1),
44 // Scalar::all(-1), vector<char>(),
45 // DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
46 //imshow("matches",img_matches);
47
48 vector<Point2f> keypoints1, keypoints2;
49 for (i=0; i<good_matches.size(); i++)
50 {
51 keypoints1.push_back(keypoints_img[good_matches[i].trainIdx].pt);
52 keypoints2.push_back(keypoints_roi[good_matches[i].queryIdx].pt);
53 }
54 //计算单应矩阵
55 Mat H = findHomography( keypoints1, keypoints2, CV_RANSAC );
56
57 //show stitchImage
58 // cv::Mat stitchedImage;
59 // int mRows = img2.rows;
60 // if (img1.rows> img2.rows)
61 // {
62 // mRows = img1.rows;
63 // }
64 // stitchedImage = Mat::zeros(img2.cols+img1.cols, mRows, CV_8UC3);
65 // warpPerspective(img2,stitchedImage,H,Size(img2.cols+img1.cols,mRows));
66 // Mat half(stitchedImage,Rect(0,0,img1.cols,img1.rows));
67 // img1.copyTo(half);
68 // imshow("stitchedImage",stitchedImage);
69
70 std::vector<cv::Point> vSrcPtsImg1;
71 std::vector<cv::Point> vSrcPtsImg2;
72
73 vSrcPtsImg1.push_back(cv::Point(0,0));
74 vSrcPtsImg1.push_back(cv::Point(0,img1.rows));
75 vSrcPtsImg1.push_back(cv::Point(img1.cols,img1.rows));
76 vSrcPtsImg1.push_back(cv::Point(img1.cols,0));
77
78 vSrcPtsImg2.push_back(cv::Point(0,0));
79 vSrcPtsImg2.push_back(cv::Point(0,img2.rows));
80 vSrcPtsImg2.push_back(cv::Point(img2.cols,img2.rows));
81 vSrcPtsImg2.push_back(cv::Point(img2.cols,0));
82
83 //计算图像2在图像1中对应坐标信息
84 std::vector<cv::Point> vWarpPtsImg2;
85 for(int i = 0;i < vSrcPtsImg2.size();i++ )
86 {
87 cv::Mat srcMat = Mat::zeros(3,1,CV_64FC1);
88 srcMat.at<double>(0,0) = vSrcPtsImg2[i].x;
89 srcMat.at<double>(1,0) = vSrcPtsImg2[i].y;
90 srcMat.at<double>(2,0) = 1.0;
91
92 cv::Mat warpMat = H * srcMat;
93 cv::Point warpPt;
94 warpPt.x = cvRound(warpMat.at<double>(0,0)/warpMat.at<double>(2,0));
95 warpPt.y = cvRound(warpMat.at<double>(1,0)/warpMat.at<double>(2,0));
96
97 vWarpPtsImg2.push_back(warpPt);
98 }
99 //计算图像1和转换后的图像2的交点
100 if(!PolygonClip(vSrcPtsImg1,vWarpPtsImg2,vPtsImg1))
101 return false;
102
103 for (int i = 0;i < vPtsImg1.size();i++)
104 {
105 cv::Mat srcMat = Mat::zeros(3,1,CV_64FC1);
106 srcMat.at<double>(0,0) = vPtsImg1[i].x;
107 srcMat.at<double>(1,0) = vPtsImg1[i].y;
108 srcMat.at<double>(2,0) = 1.0;
109
110 cv::Mat warpMat = H.inv() * srcMat;
111 cv::Point warpPt;
112 warpPt.x = cvRound(warpMat.at<double>(0,0)/warpMat.at<double>(2,0));
113 warpPt.y = cvRound(warpMat.at<double>(1,0)/warpMat.at<double>(2,0));
114 vPtsImg2.push_back(warpPt);
115 }
116 return true;
117 }
其中,多边形求交集可参考:http://www.cnblogs.com/dwdxdy/p/3232110.html
最终,程序运行的示意图如下:
【OpenCV学习】计算两幅图像的重叠区域的更多相关文章
- OpenCV,计算两幅图像的单应矩阵
平面射影变换是关于其次3维矢量的一种线性变换,可以使用一个非奇异的$3 \times 3$矩阵H表示,$X' = HX$,射影变换也叫做单应(Homography).计算出两幅图像之间的单应矩阵H,那 ...
- 【opencv学习笔记六】图像的ROI区域选择与复制
图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...
- Halcon学习之两幅图像处理
sub_image ( ImageMinuend, ImageSubtrahend : ImageSub : Mult, Add : ) 对两幅图像做减法 g' := (g1 - g2) * Mu ...
- Opencv实现两幅图像融合
实现两幅图像线性(不同系数下)的融合涉及到Opencv中两个关键的方法,addWeighted()和createTrackbar() addWeighted方法: 函数原型: void addWeig ...
- OpenCv实现两幅图像的拼接
直接贴上源码 来源:http://www.myexception.cn/image/1498389.html 实验效果 Left.jpg right.jpg ImageMatch.jpg #inclu ...
- CV 两幅图像配准
http://www.cnblogs.com/Lemon-Li/p/3504717.html 图像配准算法一般可分为: 一.基于图像灰度统计特性配准算法:二.基于图像特征配准算法:三.基于图像理解的配 ...
- 第十三节,OPenCV学习(二)图像的简单几何变换
图像的简单几何变换 几何变换不改变图像的像素值,只是在图像平面上进行像素的重新安排 适当的几何变换可以最大程度地消除由于成像角度.透视关系乃至镜头自身原因所造成的几何失真所产生的的负面影响. 一.图像 ...
- OpenCV 学习笔记(0)两幅图像标定配准
参考教程 依赖opencv扩展库,使用sifi匹配 保存配准信息 "./config/calibratedPara.yaml" #include <iostream> ...
- opencv::将两幅图像合并后,在同一个窗口显示;并将合并的图像流保存成视频文件
/** * @file main-opencv.cpp * @date July 2014 * @brief An exemplative main file for the use of ViBe ...
随机推荐
- Laravel框架中的event事件操作
有时候当我们单纯的看 Laravel 手册的时候会有一些疑惑,比如说系统服务下的授权和事件,这些功能服务的应用场景是什么,其实如果没有经历过一定的开发经验有这些疑惑是很正常的事情,但是当我们在工作中多 ...
- Python进行MySQL数据库操作
最近开始玩Python,慢慢开始喜欢上它了,以前都是用shell来实现一些自动化或者监控的操作,现在用Python来实现,感觉更棒,Python是一门很强大的面向对象语言,所以作为一个运维DBA或者运 ...
- IntelliJ IDEA 下的SVN使用
最近公司的很多同事开始使用IntelliJ Idea,便尝试了一下,虽然快捷键与eclipse 有些不同,但是强大的搜索功能与“漂亮的界面”(个人认为没有eclipse好看 ),还是值得我们去使用的. ...
- python 全栈开发,Day117(popup,Model类的继承,crm业务开发)
昨日内容回顾 第一部分:权限相关 1. 权限基本流程 用户登录成功后获取权限信息,将[权限和菜单]信息写入到session. 以后用户在来访问,在中间件中进行权限校验. 为了提升用户体验友好度,在后台 ...
- python 全栈开发,Day86(上传文件,上传头像,CBV,python读写Excel,虚拟环境virtualenv)
一.上传文件 上传一个图片 使用input type="file",来上传一个文件.注意:form表单必须添加属性enctype="multipart/form-data ...
- 《转》Java与Http协议
引言 http(超文本传输协议)是一个基于请求与响应模式的.无状态的.应用层的协议,常基于TCP的连接方式.HTTP协议的主要特点是: 1.支持客户/服务器模式. 2.简单快速:客户向 ...
- POJ 3187【permutation】
POJ 3187 给定N值,从而确定了数据的范围及长度,暴力枚举数列,接下来类似杨辉三角的递推计算.注permutation从递增有序数列开始枚举,枚举到符合sum值时退出即可 #include &l ...
- zjoi2017 仙人掌
题解: 好难的dp啊...看题解看了好久才看懂 http://blog.csdn.net/akak__ii/article/details/65935711 如果一开始的图就不是仙人掌,答案显然为0, ...
- 085 HBase的二级索引,以及phoenix的安装(需再做一次)
一:问题由来 1.举例 有A列与B列,分别是年龄与姓名. 如果想通过年龄查询姓名. 正常的检索是通过rowkey进行检索. 根据年龄查询rowkey,然后根据rowkey进行查找姓名. 这样的效率不高 ...
- QMessageBox的用法
QMessageBox的用法 先来看一下最熟悉的QMessageBox::information.我们在以前的代码中这样使用过: QMessageBox::information(NULL, ...