位置: 编程技术 - 正文

OpenGL与OpenCV实现增强现实(opengl和openglskia)

编辑:rootadmin

推荐整理分享OpenGL与OpenCV实现增强现实(opengl和openglskia),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:opengl openal,opengl vs,opengl opencv opencl,opengl与opencl,opengl 和opencv,opengl 和opencv,opengl与opencl,opengl 和opencv,内容如对您有帮助,希望把文章链接给更多的朋友!

很久没有写博客了,最近在学习计算机视觉的相关知识,于是写了一个AR的小Demo。

该程序通过OpenCV实现对Marker的识别和定位,然后通过OpenGL将虚拟物体叠加到摄像头图像下,实现增强现实。首先来看看我们使用的Marker:

这是众多Marker中的一个,它们都被一圈的黑色边框所包围,边框之中是编码信息,白色代表1,黑色代表0。将每一行作为一个字,那么每个字有5bits。其中,1、3、5位为校验位,2、4位为信息位。也就是说,整个Marker的信息位只有bits,所以最多可表示个数(0~)。这种编码方式实际上是汉明码的变种,唯一区别在于它的首位是对应汉明码首位的反(比如汉明码是,那么Marker中的编码为)。这么做的目的是防止某一行全黑,从而提高识别率。汉明码还有另一大优势——不具有旋转对称性,因此程序能通过汉明码确定Marker的方向,因此从Marker中解码的信息是唯一的。

一、Marker的检测与识别

我们首先实现一个类,用于检测图像中的Marker,解码信息,并计算Marker相对于摄像头的坐标位置。

检测部分比较简单。首先将输入图像进行灰度变换,然后对灰度图像进行自适应二&#;化。之所以使用自适应二&#;化,是因为它能更好的适应光照的变化。但有一点要注意,很多朋友使用自适应二&#;化后表示得到的结果很像边缘检测的结果,那是因为自适应窗口过小造成的。使用自适应二&#;化时,窗口的大小应大于二&#;化目标的大小,否则得到的阈&#;不具有适应性。在自适应二&#;化之后,为了消除噪音或小块,可以加以形态学开运算。以上几部可分别得到下列图像(其中二&#;化的结果经过了反色处理,方便以后的轮廓提取)。

得到二&#;图像后,就可以使用OpenCV中的findContours来提取轮廓了。一副二&#;图像当中的轮廓有很多,其中有一些轮廓很小,我们通过一个阈&#;将这些过小的轮廓排除。排除过小轮廓后,就可以对轮廓进行多边形近&#;了。由于我们的Marker是正方形,其多边形近&#;结果应该满足以下条件:

1、只有4个顶点

2、一定是凸多边形

3、每一个边的长度不能过小

通过以上几个条件,我们可以排除绝大部分轮廓,从而找到最有可能为Marker的部分。找到这样的候选轮廓后,我们将它的多边形四个顶点保存下来,并做适当的调整,使所有顶点逆时针排序。代码如下:

下一步,从这些候选区域中进一步筛选出真正的Marker。首先,由于摄像机视角的关系,图像中的Marker是经过透视变换的。为了方便提取Marker中的信息,要使用warpPerspective方法对候选区域进行透视变换,得到Marker的正视图。之后,由于Marker只有黑白两种颜色,其直方图分布是双峰的,所以用大津法(OTSU)对透视变换后的图像做二&#;化。

由于Marker都有一圈黑色的轮廓,这成为了我们进一步判定Marker的标准。获取正确的Marker图像后,可能有4个不同方向。这时我们就可以通过Marker中的汉明码确定Marker的正确朝向了,正确朝向的Marker,其汉明距离一定为零。得到Marker的朝向后,就可以提取Marker的信息(即ID),还可以调整Marker的4个顶点顺序,使其不随视角的变换而变换。在Demo中,我将正向放置的Marker的左上角作为1号顶点,逆时针旋转依次为2号、3号和4号。

代码如下:

得到最终的Marker后,为了之后计算精确的摄像机位置,还需对Marker四个顶点的坐标进行子像素提取,这一步很简单,直接使用cornerSubPix即可。

为了检查算法的结果,将Marker的提取结果画到了图像上。其中蓝色边框标记了Marker的区域,空心圆圈代表Marker的1号顶点(正向放置时的左上角),较小的实心原点代表2号顶点,数字代表Marker的ID。

2、计算摄像机位置

计算摄像机的位置,首先需要对摄像机进行标定,标定是确定摄像机内参矩阵K的过程,一般用棋盘进行标定,这已经是一个很成熟的方法了,在这就不细说了。得到相机的内参矩阵K后,就可以使用solvePnP方法求取摄像机关于某个Marker的位置。摄像机成像使用小孔模型,如下:

x = K[R|T]X

其中,X是空间某点的坐标(相对于世界坐标系),[R|T]是摄像机外参矩阵,用于将某点的世界坐标变换为摄像机坐标,K是摄像机内参,用于将摄像机坐标中的某点投影的像平面上,x即为投影后的像素坐标。

对于一个确定的Marker,x是已知的,K是已知的,使用solvePnP求取相机位置实际上就是求取相机相对于Marker的外参矩阵[R|T],但现在X还不知道,如何确定呢?

外参矩阵与世界坐标系的选取有关,而世界坐标系的选取是任意的,因此我们可以将世界坐标系直接设定在Marker上,如下图:

我们想象Marker位于世界坐标系的XY平面上(Z分量为零),且原点位于Marker的中心。由此,我们就确定了四个点的X坐标,将四个点的X坐标以及对应的像素坐标x传入solvePnP方法,即可得到相机关于该Marker的外参了。为了方便之后的使用,使用Rodrigues方法将旋转向量变为对应的旋转矩阵。

那么现在问题来了!我们设定世界坐标系时,只设定了X轴与Y轴的方向,由于Z分量为零,它的方向并不影响求得的外参矩阵。但之后将虚拟物体放入该世界坐标时,却需要知道Z轴的方向,那么我们的Z轴方向到底是什么呢?

首先,solvePnP返回的结果是一个旋转向量和一个平移向量,两者构成一个刚体运动,刚体运动不会改变坐标系的手性(即右手坐标系经过刚体运动后还是右手坐标系),所以世界坐标系的手性应该和相机坐标系的手性一致。从相机的小孔成像模型中可以知道,相机坐标系的Z轴是指向像平面的,因此,通过下图我们可以断定,世界坐标系的Z轴是垂直于Marker向下的。

二、从OpenCV到OpenGL

得到摄像机的内参K和相对于每个Marker的外参[R|T]后,就可以开始考虑将虚拟物体添加进来了。老惯例,我还是使用OpenFrameworks。OpenFrameworks是在OpenGL基础上构建的一套框架,所以3D显示上,其本质还是OpenGL。

OpenGL的投影模型和普通相机的小孔投影模型是类&#;的,其PROJECTION矩阵对应与相机的内参K,MODELVIEW矩阵对应与相机的外参。但是,我们之前求得的K和[R|T]还不能直接使用,原因有二,其一,OpenGL投影模型使用的坐标系与OpenCV的不同;其二,OpenGL为了进行Clipping,其投影矩阵需要将点投影到NDC空间中。

OpenGL与OpenCV实现增强现实(opengl和openglskia)

Perspective Frustum and Normalized Device Coordinates (NDC)

由上图(左边)可知,OpenGL的相机坐标系相当于OpenCV的相机坐标系绕着X轴旋转了度,因此,我们使用外参矩阵[R|T]对世界坐标系中的某点进行变换后,还需要左乘一个旋转矩阵才能得到该点在OpenGL坐标系中的坐标。绕X轴旋转度的旋转矩阵很简单,如下:

[ 1, 0, 0,

0, -1, 0,

0, 0, -1 ]

总之,外参矩阵[R|T]左乘以上矩阵后,即得OpenGL中的MODELVIEW矩阵,代码如下,注意OpenGL的矩阵元素是以列主序存储的。

下一步是求PROJECTION矩阵。由于OpenGL要做Clipping,要求所有在透视椎体中的点都投影到NDC中,在NDC中的点能够显示在屏幕上,之外的点则不能。因此,我们的PROJECTION矩阵不仅要有与内参矩阵K相同的透视效果,还得把点投影到NDC中。

首先先看看内参矩阵K的形式:

首先假设OpenGL的投影椎体是对称的,那么PROJECTION矩阵的形式如下:

使用以上矩阵对某一点(X, Y, Z, 1)投影后,可以得到如下关系:

接下来,OpenGL会对该结果进行Clipping,具体方法是将四个分量都除以-Z,那么,要使我们的点最终显示到屏幕上,前三个分量在除以-Z后其变化范围必须在[-1, 1]内。如下:

由摄像机投影模型(相&#;三角形)知:

其中由于OpenGL相机的相面在Z轴负方向上,所以是-fx和-fy。xp和yp分别为某点在相面上的横坐标和纵坐标,这两个坐标的原点在图像的中心,图像的宽度和高度分别为w和h,因此xp和yp的取&#;范围分别为[-w/2, w/2]和[-h/2, h/2],可得:

于是

接下来,我们为OpenGL相机设定两个面,near和far,只有处于这两个面之间的点才能投影到NDC空间中,所以当 Z=-n 时,(AZ&#;B)/-Z = -1,当 Z=-f 时,(AZ&#;B)/-Z = 1,由此我们可以得到关于A和B的二元一次方程,从而解出A、B:

现在再来考虑OpenGL投影椎体不对称的情况,这种情况下,PROJECTION矩阵的形式为:

由于椎体不对称,这时xp和yp的变化范围分别为[l, r]和[b, t],代表图像左侧(left)右侧(right),以及底部(bottom)顶部(top),用同样的方法,我们有:

可得:

于是:

关于l&#;r和b&#;t是怎么计算的,可以参考下图:

综上所述,我们可以得到OpenGL投影矩阵的最终形式:

到此,我们就可以将这个矩阵的数据传递给PROJECTION矩阵了:

现在是时候放一些虚拟物体进来了,为了简单,我就放了几个立方体,由于OpenFrameworks绘制立方体时以立方体在中心为原点,所以为了使立方体的底面贴在Marker上,必须在Marker上方二分之一立方体边长的地方绘制,也就是绘制立方体的坐标为(0, 0, -0.5*size),为什么是负0.5呢?还记得之前所说的世界坐标系的Z轴是垂直于Marker并朝下的吗?所以要画在Marker上方,必须向Z轴负方向移动!

注意,我在设置投影矩阵时,左乘了一个垂直方向的镜像矩阵,这是因为,我发现OpenFrameworks将NDC空间中(-1, -1)点映射到屏幕的左上角,而非一般OpenGL所映射的左下角,如果不乘这个镜像矩阵,得到的图像就是上下颠倒的。至于为什么OpenFrameworks是这样,由于没仔细研究它的代码,我只能猜测是其在初始化时对OpenGL做了一些设置所致。所以,如果我的理解或猜测有错误,还请大家指出^_^

最后给出代码的下载地址,程序用VS开发,解压后放到”OpenFrameworks安装目录appsmyApps“下打开编译:

多边形画圆 vc6.0+opengl #includeGL/glut.h#includemath.hvoidDrawing();voidInit();voidDisplay();voidReshape(int,int);voidDrawNGon(float,float,float,int,float=,bool=false);voidmain(intargc,char**argv){glutInit(argc,argv);glut

OpenGL渲染流水线 OpenGL实现了通常所说的渲染流水线。这个流水线分为一系列不同的阶段,能够将应用程序提供给OpenGL的数据转化为一幅最终的渲染图。下面的图为OpenGL4.

OpenGL学习日记-..--简单裁剪 spanstyle=font-size:px;font-family:微软雅黑;line-height:px;Opengl中,除了视景体的立方体裁剪平面之外,另外还可以额外指定多达6个裁剪平面,对视景体做进一

标签: opengl和openglskia

本文链接地址:https://www.jiuchutong.com/biancheng/373187.html 转载请保留说明!

上一篇:简易bmp图片读取(简易bmp图片读取软件)

下一篇:多边形画圆 vc6.0+opengl(绘制多边形工具使用方法)

  • 设计印刷合同
  • 什么是税收超额征收
  • 可以抵扣的进项税额是什么意思
  • 企业所得税表利润总额怎么填写
  • 报销招待费事由有哪些
  • 注册资本没缴足可以注销吗
  • pos机刷卡的银行有哪些
  • 已抵扣专用发票冲红怎么操作
  • 以前年度的税务怎么查
  • 逃税漏税不用坐牢吗
  • 劳务建筑公司一年可以赚多少
  • 税务电子钥匙补办需要多久
  • 财务费用是否存入银行卡
  • 广告公司需要交消费税吗
  • 房地产企业开发资质等级
  • 多交增值税如何退回
  • 股东以个人名义签订租赁合同
  • 公司销售二手车怎么做账
  • 买免税产品
  • 减征资源税中是否包含水资源税?
  • 公证处委托他人办理房产证手续
  • 路由器突然不能上网了显示红灯
  • 坏账准备冲回是借方还是贷方
  • 华为鸿蒙系统的服务
  • 汇算清缴是什么时间
  • win11 应用商店
  • 购入的车辆入账包括哪些费用
  • 鼠标怎么设置为右键功能
  • 发票未到先付款的账务处理
  • 企业的做账流程有哪些
  • 坏账减值准备账务处理
  • pytorch f
  • 库存股属于什么会计科目
  • yii2框架从入门到精通pdf
  • 小微企业认定标准时间
  • vscode怎么写前端代码
  • 520要来了要吵架的赶紧
  • 数据挖掘的四种基本方法
  • 百度文心一言对未来商业的影响
  • cvpr2021录用文章
  • 计提本月银行存款应收利息会计分录
  • 银行本票和汇票的定义
  • 暂估价与发票价的区别
  • jvm调优思路
  • 贴现模式怎么计算利息
  • 商业汇票贴现时间轴
  • 财务报表审计的基础是独立性和专业性
  • 人工费用计入
  • 已认证发票是否已抵扣
  • 银行承兑汇票背书转让会计分录
  • 以无形资产换入固定资产发生的净损益
  • 营改增企业可以转小规模吗
  • 呆滞原材料变卖的会计处理
  • 税务滞纳金计入什么会计科目
  • 政府补助冲减成本
  • 验资户和基本户账号一致么
  • 金蝶kis专业版怎么备份账套
  • 数据库崩了怎么恢复
  • win 系统
  • macbookair怎么开启
  • win7如何创建新桌面
  • qdcsfs.exe - qdcsfs是什么进程 有何作用
  • linux 多网卡配置
  • Windows8和Windows Phone8中IE10两者相同点和区别
  • win10系统笔记本怎么连接wifi
  • win10输入法怎么添加美式键盘
  • ext.grid.editorgridpanel
  • android 坐标系
  • unity flybird
  • Node.js中的包管理工具是什么
  • shell脚本中判断grep的结果
  • 基于jQuery Ajax实现上传文件
  • 海南税务局增值税按次缴纳
  • 天津租房网个人房源出租
  • 税务局的前身是什么
  • 上海个人所得税税率表2023
  • 朝阳区下面分几个区
  • 补充耕地指标费用能从储备中心支付吗
  • 增值税和消费税申报对比不符怎么处理
  • 交17000办的保险是什么保险
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设