参考教程

依赖opencv扩展库,使用sifi匹配

保存配准信息

 "./config/calibratedPara.yaml" 
#include <iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include<opencv2/xfeatures2d.hpp>
#include<opencv2/core/core.hpp> #define PATH_XMAL "./config/calibratedPara.yaml"
#define IMG_WIDTH 2592//2592
#define IMG_HEIGHT 1944//2048 using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;//只有加上这句命名空间,SiftFeatureDetector and SiftFeatureExtractor才可以使用 /******************************************************
*name :Rect CalcCorners(const Mat& H, const Mat& src)
*function :通过H计算图片角点位置,返回左上和宽高
*time :2019-4-28
********************************************************/
Rect CalcCorners(const Mat& H, const Mat& src)
{
double v1[3];
Mat _V1 = Mat(3, 1, CV_64FC1, v1);
//左上角(0,0,1)
Mat _V2 = (Mat_<double>(3, 1) << 0, 0, 1);
_V1 = H * _V2;
Point _left_top;
_left_top.x = v1[0] / v1[2];
_left_top.y = v1[1] / v1[2];
//左下角(0,src.rows,1)
_V2 = (Mat_<double>(3, 1) << 0, src.rows, 1);
_V1 = H * _V2;
Point _left_bottom;
_left_bottom.x = v1[0] / v1[2];
_left_bottom.y = v1[1] / v1[2];
//右上角(src.cols,0,1)
_V2 = (Mat_<double>(3, 1) << src.cols, 0, 1);
_V1 = H * _V2;
Point _right_top;
_right_top.x = v1[0] / v1[2];
_right_top.y = v1[1] / v1[2];
//右下角(src.cols,src.rows,1)
_V2 = (Mat_<double>(3, 1) << src.cols, src.rows, 1);
_V1 = H * _V2;
Point _right_bottom;
_right_bottom.x = v1[0] / v1[2];
_right_bottom.y = v1[1] / v1[2];
int _x1 = (int)max(_left_bottom.x, _left_top.x);
int _y1 = (int)max(_left_top.y, _right_top.y);
int _x2 = (int)min(_right_top.x, _right_bottom.x);
int _y2 = (int)min(_left_bottom.y, _right_bottom.y); cout << "point is " << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl;
if (_x2 > IMG_WIDTH) _x2 = IMG_WIDTH - 1;
if (_y2 > IMG_HEIGHT) _y2 = IMG_HEIGHT - 1;
if (_x1 < 0) _x1 = 0;
if (_y1 < 0) _y1 = 0; cout << "point is " << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl; return Rect(Point(_x1, _y1), Point(_x2, _y2)); //表示左上点和右下点
} Rect inscrRect;
cv::Mat warpedPic;
cv::Mat Homography;
Mat compicCalibrate; int main()
{
//Create SIFT class pointer
Ptr<Feature2D> f2d = xfeatures2d::SIFT::create();
//SiftFeatureDetector siftDetector;
//Loading images
Mat img_1 = imread("1.bmp");
Mat img_2 = imread("2.bmp");
if (!img_1.data || !img_2.data)
{
cout << "Reading picture error!" << endl;
return false;
}
//Detect the keypoints
double t0 = getTickCount();//当前
vector<KeyPoint> keypoints_1, keypoints_2;
f2d->detect(img_1, keypoints_1);
f2d->detect(img_2, keypoints_2);
cout << "The keypoints number of img1 is:" << keypoints_1.size() << endl;
cout << "The keypoints number of img2 is:" << keypoints_2.size() << endl;
//Calculate descriptors (feature vectors)
Mat descriptors_1, descriptors_2;
f2d->compute(img_1, keypoints_1, descriptors_1);
f2d->compute(img_2, keypoints_2, descriptors_2);
double freq = getTickFrequency();
double tt = ((double)getTickCount() - t0) / freq;
cout << "Extract SIFT Time:" << tt << "ms" << endl;
//画关键点
Mat img_keypoints_1, img_keypoints_2;
drawKeypoints(img_1, keypoints_1, img_keypoints_1, Scalar::all(-1), 0);
drawKeypoints(img_2, keypoints_2, img_keypoints_2, Scalar::all(-1), 0);
//imshow("img_keypoints_1",img_keypoints_1);
//imshow("img_keypoints_2",img_keypoints_2); //Matching descriptor vector using BFMatcher
BFMatcher matcher;
vector<DMatch> matches;
matcher.match(descriptors_1, descriptors_2, matches);
cout << "The number of match:" << matches.size() << endl;
//绘制匹配出的关键点
Mat img_matches;
drawMatches(img_1, keypoints_1, img_2, keypoints_2, matches, img_matches);
//imshow("Match image",img_matches);
//计算匹配结果中距离最大和距离最小值
double min_dist = matches[0].distance, max_dist = matches[0].distance;
for (int m = 0; m < matches.size(); m++)
{
if (matches[m].distance<min_dist)
{
min_dist = matches[m].distance;
}
if (matches[m].distance>max_dist)
{
max_dist = matches[m].distance;
}
}
cout << "min dist=" << min_dist << endl;
cout << "max dist=" << max_dist << endl;
//筛选出较好的匹配点
vector<DMatch> goodMatches;
for (int m = 0; m < matches.size(); m++)
{
if (matches[m].distance < 0.6*max_dist)
{
goodMatches.push_back(matches[m]);
}
}
cout << "The number of good matches:" << goodMatches.size() << endl;
//画出匹配结果
Mat img_out;
//红色连接的是匹配的特征点数,绿色连接的是未匹配的特征点数
//matchColor – Color of matches (lines and connected keypoints). If matchColor==Scalar::all(-1) , the color is generated randomly.
//singlePointColor – Color of single keypoints(circles), which means that keypoints do not have the matches.If singlePointColor == Scalar::all(-1), the color is generated randomly.
//CV_RGB(0, 255, 0)存储顺序为R-G-B,表示绿色
drawMatches(img_1, keypoints_1, img_2, keypoints_2, goodMatches, img_out, Scalar::all(-1), CV_RGB(0, 0, 255), Mat(), 2);
namedWindow("good Matches", 0);
imshow("good Matches", img_out);
//RANSAC匹配过程
vector<DMatch> m_Matches;
m_Matches = goodMatches;
int ptCount = goodMatches.size();
if (ptCount < 100)
{
cout << "Don't find enough match points" << endl;
return 0;
} //坐标转换为float类型
vector <KeyPoint> RAN_KP1, RAN_KP2;
//size_t是标准C库中定义的,应为unsigned int,在64位系统中为long unsigned int,在C++中为了适应不同的平台,增加可移植性。
for (size_t i = 0; i < m_Matches.size(); i++)
{
RAN_KP1.push_back(keypoints_1[goodMatches[i].queryIdx]);
RAN_KP2.push_back(keypoints_2[goodMatches[i].trainIdx]);
//RAN_KP1是要存储img01中能与img02匹配的点
//goodMatches存储了这些匹配点对的img01和img02的索引值
}
//坐标变换
vector <Point2f> p01, p02;
for (size_t i = 0; i < m_Matches.size(); i++)
{
p01.push_back(RAN_KP1[i].pt);
p02.push_back(RAN_KP2[i].pt);
}
/*vector <Point2f> img1_corners(4);
img1_corners[0] = Point(0,0);
img1_corners[1] = Point(img_1.cols,0);
img1_corners[2] = Point(img_1.cols, img_1.rows);
img1_corners[3] = Point(0, img_1.rows);
vector <Point2f> img2_corners(4);*/
////求转换矩阵
//Mat m_homography;
//vector<uchar> m;
//m_homography = findHomography(p01, p02, RANSAC);//寻找匹配图像
//求基础矩阵 Fundamental,3*3的基础矩阵
vector<uchar> RansacStatus;
Mat Fundamental = findFundamentalMat(p01, p02, RansacStatus, FM_RANSAC);
//重新定义关键点RR_KP和RR_matches来存储新的关键点和基础矩阵,通过RansacStatus来删除误匹配点
vector <KeyPoint> RR_KP1, RR_KP2;
vector <DMatch> RR_matches;
int index = 0;
for (size_t i = 0; i < m_Matches.size(); i++)
{
if (RansacStatus[i] != 0)
{
RR_KP1.push_back(RAN_KP1[i]);
RR_KP2.push_back(RAN_KP2[i]);
m_Matches[i].queryIdx = index;
m_Matches[i].trainIdx = index;
RR_matches.push_back(m_Matches[i]);
index++;
}
}
cout << "RANSAC后匹配点数" << RR_matches.size() << endl;
Mat img_RR_matches;
drawMatches(img_1, RR_KP1, img_2, RR_KP2, RR_matches, img_RR_matches);
namedWindow("After RANSAC", 0);
imshow("After RANSAC", img_RR_matches);
//等待任意按键按下
waitKey(1); vector<cv::Point2f> Pic1Point, Pic2Point;
for (int i = 0; i < RR_matches.size(); i++)
{
Pic1Point.push_back(RR_KP1[RR_matches[i].queryIdx].pt);
Pic2Point.push_back(RR_KP2[RR_matches[i].trainIdx].pt);
} Homography = cv::findHomography(Pic1Point, Pic2Point, CV_RANSAC); //计算将p2投影到p1上的单映性矩阵 FileStorage fs(PATH_XMAL, FileStorage::WRITE); //单应矩阵保存
fs << "Homography" << Homography; warpPerspective(img_1, warpedPic, Homography, cv::Size(img_2.cols, img_2.rows));//第一路图像根据参数Homography变换映射到warpedPic图
inscrRect = CalcCorners(Homography, img_1);// 第一路图像根据参数Homography计算本土映射区域的起始点和宽高
fs << "inscrRect" << inscrRect;//保存在xml
fs.release(); Rect cutRoi(inscrRect.x, inscrRect.y, inscrRect.width, inscrRect.height);// 定义一个抠图区域
Mat Pic1Roi = warpedPic(cutRoi).clone();//第一张变换图扣出对应区域 compicCalibrate.create(inscrRect.height, inscrRect.width * 2, CV_8UC3); // Mat Pic1Roi = warpedPic(inscrRect);
Mat Pic2Roi = img_2(inscrRect);
Pic1Roi.copyTo(compicCalibrate(Rect(0, 0, Pic1Roi.cols, Pic1Roi.rows)));
Pic2Roi.copyTo(compicCalibrate(Rect(Pic1Roi.cols, 0, Pic2Roi.cols, Pic2Roi.rows)));
namedWindow("martch", 0);
imshow("martch", compicCalibrate);
waitKey(0);
}

  

OpenCV 学习笔记(0)两幅图像标定配准的更多相关文章

  1. 【OpenCV学习】计算两幅图像的重叠区域

    问题描述:已知两幅图像Image1和Image2,计算出两幅图像的重叠区域,并在Image1和Image2标识出重叠区域. 算法思想: 若两幅图像存在重叠区域,则进行图像匹配后,会得到一张完整的全景图 ...

  2. 【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整

    今天我们来看一下如何访问图像的像素,以及如何改变图像的亮度与对比度. 在之前我们先来看一下图像矩阵数据的排列方式.我们以一个简单的矩阵来说明: 对单通道图像排列如下: 对于双通道图像排列如下: 那么对 ...

  3. (转) OpenCV学习笔记大集锦 与 图像视觉博客资源2之MIT斯坦福CMU

          首页 视界智尚 算法技术 每日技术 来打我呀 注册     OpenCV学习笔记大集锦 整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的 ...

  4. OpenCV学习笔记(4)——图像上的算术运算

    学习图像上的算术运算,加法,减法,位运算等 1.图像加法 使用cv2.add()将两幅图像进行加法运算,也可以用numpy运算,直接img+img1.两幅图像的大小和类型必须一致,或者第二个图像可以是 ...

  5. OpenCV学习笔记:如何扫描图像、利用查找表和计时

    目的 我们将探索以下问题的答案: 如何遍历图像中的每一个像素? OpenCV的矩阵值是如何存储的? 如何测试我们所实现算法的性能? 查找表是什么?为什么要用它? 测试用例 这里我们测试的,是一种简单的 ...

  6. OpenCV学习笔记(七) 图像金字塔 阈值 边界

    转自: OpenCV 教程 使用 图像金字塔 进行缩放 图像金字塔是视觉运用中广泛采用的一项技术.一个图像金字塔是一系列图像的集合 - 所有图像来源于同一张原始图像 - 通过梯次向下采样获得,直到达到 ...

  7. OpenCV 学习笔记(13)图像转换成视频

    关键 1参数里的分辨率是图像本身的分辨率,而不是指定生成的视频分辨率.如果要修改分辨率,要么后期软件处理,要么读图的时候resize 2要正常退出,不要强制退出. 3生成的只能是avi格式. #inc ...

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

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

  9. CV 两幅图像配准

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

随机推荐

  1. 金九银十跳槽高峰,面试必备之 Redis + MongoDB 常问80道面试题

    前言 有着“金九银十”之称的招聘旺季已经开启,跳槽高峰期也如约而至. 本文为主要是 Redis + MongoDB 知识点的攻略,希望能帮助到大家. 内容较多,大家准备好耐心和瓜子矿泉水. Redis ...

  2. 大一C语言课程设计——班级档案管理系统

    记录我在大一第二学期期末做的C语言课程毕业设计 1. 班级档案管理系统运用到的主要结构体 typedef struct birthday //出生日期{int year;int month;int d ...

  3. Tomcat 对静态资源的处理

    Tomcat 中的请求都是由 Servlet 处理,静态资源也不例外.在默认的 web.xml 中,配置了一个 DefaultServlet 用于处理静态资源,它支持缓存和断点续传. DefaultS ...

  4. WPF矢量字体图标(iconfont)

    原文:WPF矢量字体图标(iconfont) 转载:点击打开链接 步骤: 一.下载添加iconfont文件 二.添加到资源文件夹,并设置不复制,且为资源文件 三.增加FIcon.xaml文件 < ...

  5. 服务发现框架选型: Consul、Zookeeper还是etcd ?

    背景 本文并不介绍服务发现的基本原理.除了一致性算法之外,其他并没有太多高深的算法,网上的资料很容易让大家明白上面是服务发现.想直接查看结论的同学,请直接跳到文末.目前,市面上有非常多的服务发现工具, ...

  6. Map接口---Day20

    Map接口概述: 现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等, 这种一一对应的关系,就叫做映射.Java提供了专门的集合类用来存放这种对象关系 ...

  7. Devops K8s

    公司在组建Devops团队,base在上海 徐家汇.具体职位有Devops工程师和K8s工程师. 有意者请私信.

  8. 回调、Promise、async-await

    第一章 异步:现在与将来 程序中现在运行的部分和将来运行的部分之间的关系就是异步编程的核心. 场景:等待用户输入.从数据库或文件系统中请求数据.通过网络 发送数据并等待响应,或者是在以固定时间间隔执行 ...

  9. js如何保留两位小数,并进行四舍五入

    保留两位小数,并进行四舍五入使用js函数 toFixed() 函数传递一个参数(Number) Number就为需要保留小数的位数 具体实现代码 <script language="j ...

  10. Java 之 Object 类

    一.Object 概述  java.lang.Object 类是 Java 语言中的根类,即所有类的父类. 在对象实例化的时候,最终找的父类就是 Object. 如果一个类没有特别指定父类,那么默认则 ...