问题描述:已知两幅图像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学习】计算两幅图像的重叠区域的更多相关文章

  1. OpenCV,计算两幅图像的单应矩阵

    平面射影变换是关于其次3维矢量的一种线性变换,可以使用一个非奇异的$3 \times 3$矩阵H表示,$X' = HX$,射影变换也叫做单应(Homography).计算出两幅图像之间的单应矩阵H,那 ...

  2. 【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

  3. Halcon学习之两幅图像处理

    sub_image ( ImageMinuend, ImageSubtrahend : ImageSub : Mult, Add : ) 对两幅图像做减法   g' := (g1 - g2) * Mu ...

  4. Opencv实现两幅图像融合

    实现两幅图像线性(不同系数下)的融合涉及到Opencv中两个关键的方法,addWeighted()和createTrackbar() addWeighted方法: 函数原型: void addWeig ...

  5. OpenCv实现两幅图像的拼接

    直接贴上源码 来源:http://www.myexception.cn/image/1498389.html 实验效果 Left.jpg right.jpg ImageMatch.jpg #inclu ...

  6. CV 两幅图像配准

    http://www.cnblogs.com/Lemon-Li/p/3504717.html 图像配准算法一般可分为: 一.基于图像灰度统计特性配准算法:二.基于图像特征配准算法:三.基于图像理解的配 ...

  7. 第十三节,OPenCV学习(二)图像的简单几何变换

    图像的简单几何变换 几何变换不改变图像的像素值,只是在图像平面上进行像素的重新安排 适当的几何变换可以最大程度地消除由于成像角度.透视关系乃至镜头自身原因所造成的几何失真所产生的的负面影响. 一.图像 ...

  8. OpenCV 学习笔记(0)两幅图像标定配准

    参考教程 依赖opencv扩展库,使用sifi匹配 保存配准信息 "./config/calibratedPara.yaml" #include <iostream> ...

  9. opencv::将两幅图像合并后,在同一个窗口显示;并将合并的图像流保存成视频文件

    /** * @file main-opencv.cpp * @date July 2014 * @brief An exemplative main file for the use of ViBe ...

随机推荐

  1. python+selenium十:基于原生selenium的二次封装

    from selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium ...

  2. SpringMVC MongoDB之“基本文档查询(Query、BasicQuery)”

    一.简介 spring Data  MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate对MongoDB的CRUD的操作,上一篇我 ...

  3. POJ 2752 Seek the Name, Seek the Fame(next数组运用)

    Seek the Name, Seek the Fame Time Limit: 2000MS        Memory Limit: 65536K Total Submissions: 24000 ...

  4. wmiprvse.exe cpu占用高怎么解决

    可以通过在注册表中设置,来禁用该服务,具体步骤如下:         (1)按下“Win+R”组合键呼出运行,在框中输入“CMD”按下回车打开“命令提示符”:       (2)在命令提示符中输入:r ...

  5. 如何批量的在django中对url进行用户登陆限制

    参考URL: https://blog.csdn.net/hanshengzhao/article/details/79540306?utm_source=blogxgwz0 1,首先定义一个内部有装 ...

  6. BZOJ 3771 Triple FFT+容斥原理

    解析: 这东西其实就是指数型母函数? 所以刚开始读入的值我们都把它前面的系数置为1. 然后其实就是个多项式乘法了. 最大范围显然是读入的值中的最大值乘三,对于本题的话是12W? 用FFT优化的话,达到 ...

  7. User Agent 设置

    感谢版主回复,版主贴的方法网上到处都是,我试了很多次都是不行的,有用的方法都几乎这个到处转贴的信息淹没了. 今天我总算在一个博客找了到可行的方法,转过来和大家分享 Windows Registry E ...

  8. BZOJ3198 [Sdoi2013]spring 哈希 容斥原理

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3198 题意概括 有n(1<=n<=100000)组数据,每组数据6个数. 现在问有几对 ...

  9. Environment error: “CodeBloks can't find compiler executable in your configured search path's for GNU GCC compiler”

    codeblock安装后,提示cant find compiler executable in your configured search paths for GNU GCC Compiler 可能 ...

  10. js类型判断-丰富加好用

    一, 自己有时候写一些东西,要做类型判断,还有测试的时候,对于原生的和jQuery中的类型判断,实在不敢恭维,所以就写了一个好用的类型判断,一般情况都够用的. function test(type) ...