增强现实代码+注释解析(三)

2023-11-15

1、书名:Mastering OpenCV with Practical Computer Vision Projects

2、章节:Chapter 3:Marker-less Augmented Reality

3、书中源代码的最新更新可以参考网址:https://github.com/MasteringOpenCV/code

 

匹配过程中有什么麻烦么?

  有,就是有不匹配的问题。是的,这源自于图片大小,旋转角度、光照情况、图片的聚焦等一系列事件引发的匹配事故。如何解决,目前AR/MR的工作者仍在研究,只是已经取得了相对良好的测试结果,达到满足广大普通需求的一种状况。光学和机器视觉方面的研究是技术攻关的瓶颈。

  回到上一篇的结尾,我们省略的地方。这里就是通过随机采样一致性(RANSAC)方法对匹配过程中的特征点对进行过滤,找到一个精确的单应性矩阵,这个单应性矩阵可以矫正摄像机实时采集的图片,矫正标记图在虚拟世界中的方向角度,从而确定它的准确位置。在下面的代码中使用了两次refineMatchesWithHomography对单应性的计算,分别得到了粗糙的单应性矩阵和精确的单应性矩阵。精确的单应性矩阵是通过根据粗糙的单应性矩阵对图片进行透视变换,从而得到了辨识度更准确的特征点并检测出精确的单应性矩阵。

//在image中查找模式信息,如果找到返回真
bool PatternDetector::findPattern(const Mat &image, PatternTrackingInfo &info)//查找模式信息
{
    //转成成灰度图
    getGray(image, m_grayImg);//获取灰度图
    extractFeatures(m_grayImg, m_queryKeypoints, m_queryDescriptors);
    //从灰度图中获取关键点和描述信息
    getMatches(m_queryDescriptors, m_matches);  //获取匹配

    Mat tmp = image.clone();  //克隆一张相机图

    bool homographyFound = refineMatchesWithHomography(
        //查找单映射矩阵
        m_queryKeypoints,  //查询集的关键点
        m_pattern.keypoints,  //模式图像的关键点
        homographyReprojectionThreshold,  //阈值3
        m_matches, //匹配结果
        m_roughHomograhy
        );

    if (homographyFound)//如果找到8个以上的匹配点
    {
        if (enableHomographyRefinement) //如果要进行更加精细的单映射矩阵计算,用户决定
        {
            warpPerspective(m_grayImg, m_warpedImg, m_roughHomograhy, m_pattern.size,
            cv::WARP_INVERSE_MAP | cv::INTER_CUBIC);
            //将相机的灰度图根据单映射矩阵进行透视变换

            vector<KeyPoint>warpedKeypoints;  //透视变换的关键点
            vector<DMatch>refinedMatches; //匹配点

            //从透视变换图中提取关键点和特征向量描述
            extractFeatures(m_warpedImg, warpedKeypoints, m_queryDescriptors);
            //将这个特征向量和识别图的特征向量做匹配
            getMatches(m_queryDescriptors, refinedMatches);

            homographyFound = refineMatchesWithHomography(
                warpedKeypoints,  //透视变换后图的关键点
                m_pattern.keypoints, //识别图的关键
                homographyReprojectionThreshold, //阈值3
                refinedMatches, //匹配的点集
                m_refinedHomography  //单映射矩阵
                );

            info.homography = m_roughHomograhy*m_refinedHomography; //
            //将粗超的单映射矩阵和精细的单映射矩阵相乘,把这个矩阵作为总的单映射矩阵
            perspectiveTransform(m_pattern.points2d, info.points2d, m_roughHomograhy);
            //使用单应性矩阵透视变换将第一个点集转换为第二点集
            cv::perspectiveTransform(m_pattern.points2d, info.points2d, m_roughHomograhy);

            info.draw2dContour(tmp, CV_RGB(0, 200, 0));

            cv::perspectiveTransform(m_pattern.points2d, info.points2d, info.homography);
            info.draw2dContour(tmp, CV_RGB(200, 0, 0));

        }
        else
        {
            info.homography = m_roughHomograhy;  //使用粗超变换矩阵
            //对识别图的四个顶点做映射变换
            cv::perspectiveTransform(m_pattern.points2d, info.points2d, m_roughHomograhy);
            info.draw2dContour(tmp, CV_RGB(0, 200, 0));//绘制这四个点
        }
    }

    return homographyFound; //返回能否找到单映射矩阵
}

  寻找单应性矩阵就在这里,它通过opencv的findHomography函数计算得到的;

//寻找单应性变换
bool PatternDetector::refineMatchesWithHomography(const vector<KeyPoint>& queryKeypoints, 
const vector<KeyPoint>&trainKeyPoints, float reprojectionThreshold, vector<DMatch>&matches,
 Mat &homography)
{
    const int minNumberMatchesAllowed = 8;  //允许匹配的最小数量
    if (matches.size()<minNumberMatchesAllowed) //数量过小返回
        return false;
    //准备数据存储映射矩阵
    vector<Point2f>srcPoints(matches.size());  //保存原图点中和当前动态图匹配的点
    vector<Point2f>dstPoints(matches.size());

    for (size_t i = 0; i<matches.size(); i++)  //将匹配的点找出来
    {
        srcPoints[i] = trainKeyPoints[matches[i].trainIdx].pt;
        dstPoints[i] = queryKeypoints[matches[i].queryIdx].pt;
    }

    vector<unsigned char>inliersMask(srcPoints.size()); //内层mask
    homography = findHomography(//在原平面和目标平面之间返回一个单映射矩阵(类似仿射变换中变换矩阵)
        srcPoints, //(识别图)原图中匹配的点集
        dstPoints, //相机图中匹配的点集
        CV_FM_RANSAC, //采用随机采样一致性算法
        3,  //最大容忍重投影误差
        inliersMask //输出矩阵这里使用无符号char类型数组来保存
        );

    vector<DMatch>inliers;  //匹配
    for (size_t i = 0; i<inliersMask.size(); i++) //遍历数组
    {
        if (inliersMask[i])
            inliers.push_back(matches[i]); //按照单映射矩阵的大小提取一些匹配点
    }
    matches.swap(inliers); //将两个数组内容交换matche中存储当前的匹配集合
    return matches.size()>minNumberMatchesAllowed;  //返回时候大于8个点
}

  到这里计算出来标记图在虚拟世界中的位置信息,可以在屏幕中显示出来位置信息,也表示知道了标记图在虚拟世界中的坐标系。接下来就可以完成在实时图片上调用opengl绘制三维物体的任务了。

  单应性矩阵

  参考第一个博文吧,我找不到公式编辑器。。

 

 

 

 

  RANSAC算法步骤: 

          1. 随机从数据集中随机抽出4个样本数据 (此4个样本之间不能共线),计算出变换矩阵H,记为模型M;

          2. 计算数据集中所有数据与模型M的投影误差,若误差小于阈值,加入内点集 I ;

          3. 如果当前内点集 I 元素个数大于最优内点集 I_best , 则更新 I_best = I,同时更新迭代次数k ;

          4. 如果迭代次数大于k,则退出 ; 否则迭代次数加1,并重复上述步骤;

   注:迭代次数k在不大于最大迭代次数的情况下,是在不断更新而不是固定的;

                                       

  其中,p为置信度,一般取0.995;w为"内点"的比例 ; m为计算模型所需要的最少样本数=4;

   
  

  RANSAC算法的输入是一组观测数据(往往含有较大的噪声或无效点),一个用于解释观测数据的参数化模型以及一些可信的参数。RANSAC通过反复选择数据中的一组随机子集来达成目标。被选取的子集被假设为局内点,并用下述方法进行验证: 

  • 有一个模型适应于假设的局内点,即所有的未知参数都能从假设的局内点计算得出。
  • 用1中得到的模型去测试所有的其它数据,如果某个点适用于估计的模型,认为它也是局内点。
  • 如果有足够多的点被归类为假设的局内点,那么估计的模型就足够合理。
  • 然后,用所有假设的局内点去重新估计模型(譬如使用最小二乘法),因为它仅仅被初始的假设局内点估计过。
  • 最后,通过估计局内点与模型的错误率来评估模型。
  • 上述过程被重复执行固定的次数,每次产生的模型要么因为局内点太少而被舍弃,要么因为比现有的模型更好而被选用。

  RANSAC算法用作配准

  模型对应的是空间中一个点云数据到另外一个点云数据的旋转矩阵以及平移向量。

  第一步随机得到的是一个点云中的点对 ,利用其不变特征(两点距离,两点法向量夹角)作为哈希表的索引值搜索另一个点云中的一对对应点对,然后计算得到旋转及平移的参数值。
  应用模型,找到其他局内点,并在找到局内点之后重新计算旋转及平移为下一个状态。
  迭代上述过程,找到最终的位置。
  其中观测数据就是源点云,一个可以解释或者适应于观测数据的参数化模型是旋转矩阵及平移向量,可信的参数是两个点对的不变特征(两点距离,两点法向量夹角)

  RANSAC算法成立的条件里主要是先要有一个模型和确定的特征,用确定的特征计算模型的具体参数

   

  三维模型的加载,以后弄清再更。

参考博文:

https://www.zhihu.com/question/23310855

http://blog.csdn.net/luoshixian099/article/details/50217655

http://blog.sina.com.cn/s/blog_7a936e3b0102vctz.html

转载于:https://www.cnblogs.com/Alip/p/7681628.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

增强现实代码+注释解析(三) 的相关文章

  • Activiti7与SpringBoot整合开发

    SpringBoot 整合 Activti7 的具体步骤大概包括以下4步 1 添加 SpringBoot 整合 Activti7 的相关jar包 2 添加 SpringSecurity 安全框架的整合配置信息 3 使用 Activti7 新
  • 用递归解决八皇后问题

    单纯用递归解决该问题 就是利用一个一维数组表示出每种解 例如arry n i 其中n表示第n行的棋子 而 i 表示该 行的棋子所在列的位置 该问题可以用贪心算法进行优化 这是针对初学者练习递归时的一种解决办法 该代码并不是为了优化解决问题
  • flutter 开发踩坑集

    一 TextField设置高度后 文字无法居中 解决方案 TextField style TextStyle decoration InputDecoration prefixIcon ImageUtils getImage search
  • 区块链技术发展现状与展望 论文阅读摘要(袁勇、王飞跃)

    阅读摘要
  • 前端代码审查和测试

    检查代码的概念和过程 来自百度回答 https zhidao baidu com question 499002410583455364 html 1 代码检查法 1 桌面检查 这是一种传统的检查方法 由程序员检查自己编写的程序 程序员在程
  • GPT带我学-设计模式-命令模式

    1 你知道设计模式的命令模式吗 是的 我知道设计模式中的命令模式 命令模式是一种行为型设计模式 它将请求封装成一个对象 从而允许使用不同的请求 队列或日志来参数化其他对象 命令模式还支持撤销操作 并且可以提供事务的实现 在命令模式中 有四个
  • 机器学习——RBF神经网络

    RBF神经网络 本文部分资料与案例来源 MATLAB神经网络43个案例分析 RBF神经网络简述 再介绍RBF神经网络之前我们先来看一下径向基函数 RBF 在百度百科上 RBF定义如下 径向基函数是一个取值仅仅依赖于离原点距离的实值函数 也就
  • 未能加载文件或程序集“Newtonsoft.Json, Version=4.5.0.0"[已解决]

    前两天升级系统架构 升级后打开网页报错了 详细信息如下 未能加载文件或程序集 Newtonsoft Json Version 4 5 0 0 Culture neutral PublicKeyToken 30ad4fe6b2a6aeed 或
  • PHP架构师成长路线,PHP架构师要求

    在软件开发圈 架构师 是一个受万人追捧的头衔 架构师给人的感觉是站在软件系统后面指点江山的诸葛亮 一个系统的如何运作 运作得如何 架构师都能提前设想出来 然而 梦想是美好的 现实却是残酷的 很多人在实际工作后就会发现 梦想是成为大牛 但做的
  • 当对比学习遇上prompt,擦出了怎样的火花……

    细数最近NLP领域的热门关键词 transformer 多模态 预训练 还有不得不提的prompt 本质上说 prompt是一种激发语言模型中知识的手段 随着prompting技术的大火 有越来越多的研究者在思考 Prompt 除了让这个方
  • vue3 antd pro 框架动态路由

    此框架中路由权限使用了两种方法 主要介绍第二种方法 从路由表构建路由 前端对比后端权限字段过滤静态路由表 即 前端配置好全部的路由表 然后根据权限来与后端获取到的进行对比 最终展示对比后的数据 从后端获取路由表结构体 并构建前端路由 从后端
  • ubuntu的使用--系统目录篇(文末附Desktop目录位置)

    Ubuntu的Desktop 桌面 的目录是什么 ubuntu下的系统目录是什么样子的 1 cd命令技巧 直接进入用户的home目录 cd 进入上一个目录 cd 进入当前目录的上一层目录 cd 进入当前目录的上两层目录 cd 2 每次初始打
  • navicat 传输和同步

    同步 如果表存在 数据相同的则留 不同的则删除 然后插入目的表不存在的数据 同步相当于两个数据库表的数据拿出来比对是否有差异 传输 直接删表 插入源表数据 传输是一个数据表的数据进行插入 优缺点 这样比较的话 同步占内存但是快 适合数据量少
  • IDA反编译的几个注意和技巧

    IDA逆向程序的经验总结 关于一些类型转换以及指针和地址的总结 关于F5汇编代码不能转成c的伪代码的几个问题总结 1 jmpout的问题 2 positive sp value has been found 的问题 3 call analy
  • Java反射机制的学习

    转自 http www cnblogs com keis archive 2011 03 29 1998736 html Java反射机制是Java语言被视为准动态语言的关键性质 Java反射机制的核心就是允许在运行时通过Java Refl
  • Spring Boot 集成 Activiti7(工作流)

    Spring Boot 集成 Activiti7 工作流 本章节将介绍 Spring Boot 集成 Activiti7 工作流 Spring Boot 2 x 实践案例 代码仓库 介绍 Activiti 是一个工作流引擎 它可以将业务系统
  • 系统架构设计知识梳理--分布式架构

    CAP理论 C 一致性 一般指强一致性 A 可用性 常见指标TP999 P 分区容错性 其中一致性与可用性存在矛盾 需要开发者根据实际业务取舍 一致性解决方案 Raft算法 原理是将集群中所有服务归为三类角色 leader 领导者 foll
  • 高级应用:内部类的设计模式与内部类与外部类之间的交互

    1 内部类与外部类之间的交互 内部类与外部类之间可以相互访问对方的私有成员 这为程序设计提供了更大的灵活性和可扩展性 public class Outer private int outerVar public Outer int oute
  • 【图像分类】基于卷积神经网络和主动学习的高光谱图像分类(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现 1 概述 文献来源 深度神经网络最近已广泛应用于高光
  • android studio里查看一个类的帮助及其成员的方法

    在Android studio里 按f1仅仅是查看关于这工具本身的帮助 这点与Qt Creator不同 要想查看一个类及其成员的说明时 就不能简单的按 F1 键了 一 增加光标定住在一个类名或一个函数时 自动弹出相应的提供 如下图 光标在

随机推荐

  • 多线程的一些小问题集锦

    1 线程死亡之后不能再次启动 测试线程是否已经死亡 可以调用isAlive 方法 当线程处于就绪 运行 阻塞三种状态时 返回true 当线程处于死亡 新建状态时返回false 实例代码如下 package com thread public
  • Eclipse下通过Maven的Jetty插件运行Web工程的配置

    引用来源 Jetty7 8 的Maven插件配置 http wiki eclipse org Jetty Feature Jetty Maven Plugin Jetty9 最新的Maven插件配置 http www eclipse org
  • 卷积神经网络----无监督特征学习

    卷积神经网络是近年发展起来 并引起广泛重视的一种高效识别方法 20世纪60年代 Hubel和Wiesel在研究猫脑皮层中用于局部敏感和方向选择的神经元时发现其独特的网络结构可以有效地降低反馈神经网络的复杂性 继而提出了卷积神经网络 Conv
  • MyBatis插件的使用:mybatis-generator、mybatis-plugin、mybatis-pagehelper

    使用Intellij Idea2016 3 1 Maven3 3 9 一 mybatis generator的使用 作用 根据数据库自动生成pojo dao和xml文件 1 引入mybatis generator pom xml中引入配置
  • 408知识框架总结——计算机网络

    个人复习用 有用自取 欢迎转载 标明出处即可 不推荐在第一遍复习时使用 第一遍建议还是认认真真看书做题 第二遍复习时可以配合框架来过知识点 哪里不熟翻书来强化记忆 重点难点不构成参考建议 仅为个人想法 第一章 计算机网络体系结构 1 1计算
  • 基于若依对接微信jssdk

    基于若依对接微信jssdk java package com ruoyi system controller import com alibaba fastjson2 JSONObject import com ruoyi common c
  • 电脑键盘练习_电脑初学者指法练习的基本知识

    对于电脑初学者来说 打字无疑是最基本的电脑操作 经常有人问笔者 如何才能提升打字的速度 我每次回答的都是让他多玩玩电脑 多打打字 熟能生巧 此外 打字指法也是提高打字速度的最有效训练基础 朋友们在练习的时候一定要使用正确的手指去按按键 下面
  • 文件管理.

    1 touch 创建测试用的空文件修改文件的时间戳记 格式 touch 选项 文件名 2 echo 创建文件并编辑内容 格式 echo 123 gt 111 3 dd转换和拷贝文件 格式 dd if 拿取容量的文件名 of 要创建的文件名
  • 多路查找树——2-3树和2-3-4树

    目录 2 3树定义 2 3树的插入 2 3树的删除 PS 2 3 4树定义 2 3 4树插入 2 3 4树删除 PS 2 3树定义 定义 多路查找树 其中每一个结点都具有两个孩子 称为2结点 或三个孩子 称为3结点 所有叶节点都在树结构的同
  • IBM MQ开发通用方法,包括客户端连接、服务器端连接、发送接受消息

    1 接口方法 IQueueManager java author weiya public interface IQueueManager 发送消息 param b param queueName roseuid 447BE52F01C2
  • cs寄存器 x86 特权模式_segmentation和保护模式(二)

    segmentation和保护模式 一 上文讲到了segment descriptor 把这些descriptors放在一起 在内存里连续分布 就构成了GDT Global Descriptor Table 所以GDT也可以被称为段 描述符
  • 总离差平方和推导公式

    总离差平方和推导
  • 使用股票程序交易系统应该注意哪些问题?

    尽管使用了程序交易系统 但交易者应该明白 交易的主体是人而不是程序交易系统 交易系统不过是贯彻交易者的思想 执行了交易者的指令而已 交易者仍是交易的主体 这一点不因使用了程序交易系统而改变 交易系统有其高峰期和低谷期 交易系统从大类来分可分
  • stream新特性

    package com jeethink system domain public class Employee public Integer age public String name public Integer getAge ret
  • 十几行代码就可以让你的微信小程序挂掉

    mpvue github 地址请参见 是一个使用Vue js 开发小程序的前端框架 框架基于 Vue js核心 mpvue 修改了 Vue js 的runtime 和compiler 实现 使其可以运行在小程序环境中 从而为小程序开发引入了
  • HTML5

    文章目录 前言 滚动长画幅 实现细节 语义化标签 语言的本地化 前言 本文将分析 AirPods Pro 产品介绍使用的技巧与有趣的第三方库 滚动长画幅 这次AirPods Pro 的产品介绍以一个由用户手动进行滚动推进的长画幅组成 这个长
  • day02-HTML5列表/表格/媒体元素/结构元素

    0目录 补充知识点 HTML5列表 HTML5表格 HTML5媒体元素 HTML5结构元素 1 行内元素和块元素 行内元素 不独占一行 例如 a 标签 strong标签 em标签 块级元素 独占一行 例如 p 标签 h1 h6标签 2 HT
  • Python爬虫系列之爬取猫眼电影,没办法出门就补一下往期电影吧

    前言 今天给大家介绍利用Python爬取并简单分析猫眼电影影评 让我们愉快地开始吧 开发工具 Python版本 3 6 4 相关模块 requests模块 pyecharts模块 jieba模块 scipy模块 wordcloud模块 以及
  • 运行Pangolin时提示以下错误: terminate called after throwing an instance of 'std::runtime_error'

    在运行Pangolin时提示以下错误 terminate called after throwing an instance of std runtime error what Pangolin X11 Unable to retrieve
  • 增强现实代码+注释解析(三)

    1 书名 Mastering OpenCV with Practical Computer Vision Projects 2 章节 Chapter 3 Marker less Augmented Reality 3 书中源代码的最新更新可