代码如下:

// BasisMatrixCalculate.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream> #include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
//引用cv::KeyPoint 特征检测器通用接口
#include <opencv2/features2d/features2d.hpp>
# include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/nonfree/nonfree.hpp> //引用features2d.hpp中 SurfFeatureDetector
#include <opencv2/legacy/legacy.hpp>
int main()
{
//读取2张图像
cv::Mat image1 = cv::imread("../../aTestImage/church01.jpg", 0);
cv::Mat image2 = cv::imread("../../aTestImage/church03.jpg", 0);
if (!image1.data || !image2.data)
return 0;
//使用SURF特征 获取图像特征点
std::vector<cv::KeyPoint> keyPoints1;
std::vector<cv::KeyPoint> keyPoints2;
cv::SurfFeatureDetector surf(3000);
surf.detect(image1, keyPoints1);
surf.detect(image2, keyPoints2); //获取两幅图像的特征点 // //展示图像中的keyPoints
//cv::Mat imagekeyPt;
//cv::drawKeypoints(image1, keyPoints1, imagekeyPt, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//cv::namedWindow("image1SURFkeyPt");
//cv::imshow("image1SURFkeyPt", imagekeyPt);
//cv::drawKeypoints(image2, keyPoints2, imagekeyPt, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//cv::namedWindow("image2SURFkeyPt");
//cv::imshow("image2SURFkeyPt", imagekeyPt); //通过特征点获取描述子
cv::SurfDescriptorExtractor surfDesc; // 构造描述子提取器
cv::Mat descriptors1, descriptors2; //描述子记录局部强度差值/梯度变化/位置等信息
surfDesc.compute(image1, keyPoints1, descriptors1);
surfDesc.compute(image2, keyPoints2, descriptors2); //匹配图像的描述子 descriptors
cv::BruteForceMatcher< cv::L2<float> > matcher; //构造匹配器
std::vector<cv::DMatch> matches; //匹配描述子
matcher.match(descriptors1, descriptors2, matches);
std::cout << "matches size= " << matches.size() << std::endl; //选择部分描述子 使用 一对图像的基础矩阵 进行匹配观测
std::vector<cv::DMatch> partmatches; //部分匹配描述子 | 特征点对 的对应 索引结构体
partmatches.push_back(matches[14]); //选择第n个匹配描述子
partmatches.push_back(matches[16]);
partmatches.push_back(matches[141]);
partmatches.push_back(matches[242]);
partmatches.push_back(matches[236]);
partmatches.push_back(matches[238]);
//partmatches.push_back(matches[100]);
partmatches.push_back(matches[200]); //画出选择的匹配描述子 两幅图像连线
cv::Mat imagePartMatches;
cv::drawMatches(image1, keyPoints1, image2, keyPoints2,
partmatches, imagePartMatches, cv::Scalar(255, 255, 255));
cv::namedWindow("imagePartMatches");
cv::imshow("imagePartMatches", imagePartMatches); //将一维向量的keyPoints点转换成二维的Point2f点
std::vector <int> pointIndexes1;//记录选择的匹配特征点的索引向量
std::vector <int> pointIndexes2; for (std::vector<cv::DMatch>::const_iterator it = partmatches.begin();
it != partmatches.end(); ++it)
{
pointIndexes1.push_back(it->queryIdx); //查询图像1特征点索引
pointIndexes2.push_back(it->trainIdx); //训练图像2特征点索引
}
std::vector <cv::Point2f> selPoints1, selPoints2;
cv::KeyPoint::convert(keyPoints1, selPoints1, pointIndexes1);//将索引指定的 特征点 转换成2D点
cv::KeyPoint::convert(keyPoints2, selPoints2, pointIndexes2);
画出转换后的点二维点到原图像
std::vector<cv::Point2f>::const_iterator it = selPoints1.begin();
//while (it != selPoints1.end())
//{
// cv::circle(image1, *it, 3, cv::Scalar(255, 255, 255), 5);
// ++it;
//}
it = selPoints2.begin();
while (it != selPoints2.end())
{
cv::circle(image2, *it, 3, cv::Scalar(255, 255, 255), 2);
++it;
}
//cv::namedWindow("image1");
//cv::imshow("image1", image1);
//cv::namedWindow("image2");
//cv::imshow("image2", image2); // 获取该对图像的基础矩阵 (使用7个匹配描述子matches) CV_FM_7POINT cv::Mat fundemental = cv::findFundamentalMat(cv::Mat(selPoints1), cv::Mat(selPoints2),CV_FM_8POINT);//CV_FM_LMEDS
std::cout << "F-Matrix size= " << fundemental.rows << "," << fundemental.cols << std::endl; //使用基础矩阵 在对应图像上绘制外极线
std::vector<cv::Vec3f> lines1; //存储外极线
cv::computeCorrespondEpilines(cv::Mat(selPoints1), 1, fundemental, lines1);//获取图像1中的二维特征点 在图像2中对应的外极线
for (std::vector<cv::Vec3f>::const_iterator it = lines1.begin();
it != lines1.end(); ++it)
{
cv::line(image2,
cv::Point(0, -(*it)[2] / (*it)[1] ),
cv::Point(image2.cols , -( (*it)[2] + (*it)[0] * image2.cols )/(*it)[1] ),
cv::Scalar(255,255,255));
}
cv::namedWindow("Image2 Epilines");
cv::imshow("Image2 Epilines", image2); cv::waitKey(0);
return 0;
}

结果:

原文链接:https://blog.csdn.net/shyjhyp11/article/details/66526685

[转]OpenCV_Find Basis F-Matrix and computeCorrespondEpilines(获取一对图像的基础矩阵及对应极线)的更多相关文章

  1. XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game

    题目: Problem F. Matrix GameInput file: standard inputOutput file: standard inputTime limit: 1 secondM ...

  2. 2D-2D:对极几何 基础矩阵F 本质矩阵E 单应矩阵H

    对极约束 \[ \boldsymbol{x}_{2}^{T} \boldsymbol{F} \boldsymbol{x}_{1}=\boldsymbol{0} \quad \hat{\boldsymb ...

  3. Halcon学习之六:获取Image图像中Region区域的特征参数

    area_center_gray ( Regions, Image : : : Area, Row, Column )    计算Image图像中Region区域的面积Area和重心(Row,Colu ...

  4. 前端 JS 获取 Image 图像 宽高 尺寸

    前端 JS 获取 Image 图像 宽高 尺寸 简介 项目中用到获取图片的原始尺寸,然后适配宽高:网上的大部分前端解决方案,都是new Image()后,在onload事件中获取image的尺寸. 在 ...

  5. vc/mfc获取rgb图像数据后动态显示及保存图片的方法

    vc/mfc获取rgb图像数据后动态显示及保存图片的方法 该情况可用于视频通信中获取的位图数据回放显示或显示摄像头捕获的本地图像 第一种方法 #include<vfw.h> 加载 vfw3 ...

  6. Html5 中获取镜像图像 - 解决 WebGL 中纹理倒置问题

    Html5 中获取镜像图像 - 解决 WebGL 中纹理倒置问题 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致& ...

  7. WordPress获取特色图像的链接地址

    为什么要获取WordPress的特色图像呢? 这主要是因为,我们已经写好了静态模板文件,只有获取WordPress特色图像地址插入进去就可以了,非常方便. 还有就是有的时候,我们需要设置图片的宽度为1 ...

  8. Hi3516开发笔记(十):Qt从VPSS中获取通道图像数据存储为jpg文件

    前言   上一篇已经将himpp套入qt的基础上进行开发.那么qt中拿到frame则是很关键的交互,这是qt与海思可能编解码交叉开发的关键步骤.   受限制   因为直接配置sample的vi比较麻烦 ...

  9. 【枚举】【最小表示法】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game

    给你一个n*m的字符矩阵,将横向(或纵向)全部裂开,然后以任意顺序首尾相接,然后再从中间任意位置切开,问你能构成的字典序最大的字符串. 以横向切开为例,纵向类似. 将所有横排从大到小排序,枚举最后切开 ...

  10. 【图像处理】Golang 获取JPG图像的宽高

    一.背景 有些业务需要判断图片的宽高,来做一些图片相关缩放,旋转等基础操作. 但是图片缩放,旋转,拼接等操作需要将图片从 JPG 格式转成 RGBA 格式操作,操作完毕后,再转回 JPG 图片. 那如 ...

随机推荐

  1. 在 KubeSphere 中使用 APISIX Ingress 网关接入自定义监控

    KubeSphere 3.2.0 发布了!为项目网关增配了整套监控及管理页面,同时引入了集群网关来提供集群层面全局的 Ingress 网关能力.当然,我们还是可以部署使用第三方 Ingress Con ...

  2. KubeSphere Cloud 月刊|灾备支持 K8s 1.22+,轻量集群支持安装灾备和巡检组件

    功能升级 备份容灾服务支持 K8s v1.22+ 版本集群 随着 Kubernetes 近一年频繁的发版.升级,越来越多的用户开始部署并使用高版本的 Kubernetes 集群.备份容灾服务支持 Ku ...

  3. NebulaGraph 的云产品交付实践

    作者:乔雷,Vesoft.Inc 云原生技术专家 NebulaGraph 介绍 NebulaGraph 是由杭州悦数科技有限公司自主研发的一款开源分布式图数据库产品,擅长处理千亿节点万亿条边的超大数据 ...

  4. 不用PLC和板卡,一台电脑就可以控制伺服

    1.前言 大家好!我是付工. EtherCAT是运动控制领域使用最广泛的总线通信协议之一. 如果我们只有一台电脑,能不能直接控制EtherCAT总线伺服呢? 这个是完全可以的. 我们可以在电脑上安装实 ...

  5. OpenPSG:离AGI再进一步,首个开放环境关系预测框架 | ECCV'24

    全景场景图生成(PSG)的目标是对对象进行分割并识别它们之间的关系,从而实现对图像的结构化理解.以往的方法主要集中于预测预定义的对象和关系类别,因此限制了它们在开放世界场景中的应用.随着大型多模态模型 ...

  6. curl命令详解【转载】

    本文转载自curl 的用法指南-阮一峰 简介 curl 是常用的命令行工具,用来请求 Web 服务器.它的名字就是客户端(client)的 URL 工具的意思. 它的功能非常强大,命令行参数多达几十种 ...

  7. .NET 全能高效的 CMS 内容管理系统

    前言 推荐一款强大的企业级工具 - SSCMS 内容管理系统. SSCMS 为企业级客户设计,完全开源免费,适用于商业用途且无需支付任何产品或授权费用. 本文将详细介绍 SSCMS 系统的功能.用户界 ...

  8. 鸿蒙Navigation页面生命周期

    Navigation作为路由容器,其生命周期承载在NavDestination组件上,以组件事件的形式开放.其生命周期大致可分为三类,自定义组件生命周期.通用组件生命周期和自有生命周期.其中,abou ...

  9. 超级干货!Air780E的串口通信分享

    ​ 猛然发现,Air780E的串口通信还没分享,难怪已经有小伙伴提出了要求! 那我们来讲解低功耗4G模组Air780E的串口通信的基本用法,小伙伴们,学起来吧! 一.硬件准备  ​ 780E开发板一套 ...

  10. ABC240Ex Sequence of Substrings

    ABC240Ex Sequence of Substrings LIS 的好题改编. 约定 \(S(l,r)\) 为字符串 \(s\) 中第 \(l\) 位到底 \(r\)​ 位. \(S(l,r)& ...