OpenCV for Ios 学习笔记(9)-用OPENGL渲染AR场景2

本文原始地址:OpenCV for Ios 学习笔记(9)-用OPENGL渲染AR场景2


drawFrame的操作步骤是:

1.清除场景。

2.启动正射投影绘制背景。

3.在视口绘制最后一个从相机获取到的图像。

4.根据相机内在参数设置透视投影。

5.把每个侦测到的标记的坐标系移动到标记的3维位置(把4x4的变换矩阵应用到opengl的模型矩阵上)。

6.呈现一个任意的3维物体。

7.展示帧缓存。


 我们将会在帧准备好时调用drawFrame - 当一个新的相机帧被上传到视频内存中,并且标记监测的步骤已经完成。

   下面的就是drawFrame的代码:

  1. - (void)drawFrame  
  2. {  
  3.     //启动激活的帧缓存  
  4.     [m_glview setFramebuffer];  
  5.       
  6.     // 绘制背景  
  7.     [self drawBackground];  
  8.       
  9.     // 在检测到的标记处绘制3维物体  
  10.     [self drawAR];  
  11.       
  12.     // 呈现帧缓存  
  13.     bool ok = [m_glview presentFramebuffer];  
  14.       
  15.     int glErCode = glGetError();  
  16.     if (!ok || glErCode != GL_NO_ERROR)  
  17.     {  
  18.         std::cerr << "opengl 检测出错,错误代码是:" << glErCode << std::endl;  
  19.     }  
  20. }  

绘制一个背景对我们来说相当容易。我们启用正视投影并绘制一个全屏的当前帧的图像纹理。下面是opengl es1的代码:

  1. - (void) drawBackground  
  2. {  
  3.     //获取视口的宽高  
  4.     GLfloat w = m_glview.bounds.size.width;  
  5.     GLfloat h = m_glview.bounds.size.height;  
  6.       
  7.     //四个顶点坐标  
  8.     const GLfloat squareVertices[] =  
  9.     {  
  10.         0, 0,  
  11.         w, 0,  
  12.         0, h,  
  13.         w, h  
  14.     };  
  15.       
  16.     //纹理顶点  
  17.      static const GLfloat textureVertices[] =  
  18.      {  
  19.      1, 0,  
  20.      1, 1,  
  21.      0, 0,  
  22.      0, 1  
  23.      };  
  24.       
  25.     //正视矩阵  
  26.     static const GLfloat proj[] =  
  27.     {  
  28.         0, -2.f/w, 0, 0,  
  29.         -2.f/h, 0, 0, 0,  
  30.         0, 0, 1, 0,  
  31.         1, 1, 0, 1  
  32.     };  
  33.     /* 
  34.      glMatrixMode - 指定哪一个矩阵是当前矩阵 
  35.       
  36.      mode 指定哪一个矩阵堆栈是下一个矩阵操作的目标,可选值: GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE. 
  37.      说明 
  38.      glMatrixMode设置当前矩阵模式: 
  39.      GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作. 
  40.      GL_PROJECTION,对投影矩阵应用随后的矩阵操作. 
  41.      GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作. 
  42.      与glLoadIdentity()一同使用 
  43.      glLoadIdentity():该函数的功能是重置当前指定的矩阵为单位矩阵。 
  44.      在glLoadIdentity()之后我们为场景设置了透视图。glMatrixMode(GL_MODELVIEW)设置当前矩阵为模型视图矩阵,模型视图矩阵储存了有关物体的信息。 
  45.      */  
  46.     glMatrixMode(GL_PROJECTION);  
  47.     glLoadMatrixf(proj);  
  48.       
  49.     glMatrixMode(GL_MODELVIEW);  
  50.     glLoadIdentity();  
  51.       
  52.     glDepthMask(FALSE);  
  53.     glDisable(GL_COLOR_MATERIAL);  
  54.       
  55.     glEnable(GL_TEXTURE_2D);  
  56.     glBindTexture(GL_TEXTURE_2D, m_backgroundTextureId);  
  57.       
  58.     // 更新属性值.  
  59.     glVertexPointer(2, GL_FLOAT, 0, squareVertices);  
  60.     glEnableClientState(GL_VERTEX_ARRAY);  
  61.     glTexCoordPointer(2, GL_FLOAT, 0, textureVertices);  
  62.     glEnableClientState(GL_TEXTURE_COORD_ARRAY);  
  63.       
  64.     glColor4f(1,1,1,1);  
  65.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  
  66.       
  67.     glDisableClientState(GL_VERTEX_ARRAY);  
  68.     glDisableClientState(GL_TEXTURE_COORD_ARRAY);  
  69.     glDisable(GL_TEXTURE_2D);  
  70. }  


在场景中渲染虚拟物体是很机灵的事。首先我们需要根据相机内在参数,适应OpenGL投影矩阵。如果没有这步,我们将得到错误的透射投影,这会使虚拟的物体看起来不那么自然,好像“飘在空中”,没有真实感!正确的投影是所有增强现实应用的必备。

下面是根据相机内参创建OpenGL投影矩阵的一片代码:

  1. - (void)buildProjectionMatrix:(Matrix33)cameraMatrix: (int)screen_width: (int)screen_height: (Matrix44&) projectionMatrix  
  2. {  
  3.     float near = 0.01;  // 近裁剪距离  
  4.     float far  = 100;  // 远裁剪距离  
  5.       
  6.     // 相机的参数  
  7.     float f_x = cameraMatrix.data[0]; // Focal length in x axis  
  8.     float f_y = cameraMatrix.data[4]; // Focal length in y axis (usually the same?)  
  9.     float c_x = cameraMatrix.data[2]; // Camera primary point x  
  10.     float c_y = cameraMatrix.data[5]; // Camera primary point y  
  11.       
  12.     projectionMatrix.data[0] = - 2.0 * f_x / screen_width;  
  13.     projectionMatrix.data[1] = 0.0;  
  14.     projectionMatrix.data[2] = 0.0;  
  15.     projectionMatrix.data[3] = 0.0;  
  16.       
  17.     projectionMatrix.data[4] = 0.0;  
  18.     projectionMatrix.data[5] = 2.0 * f_y / screen_height;  
  19.     projectionMatrix.data[6] = 0.0;  
  20.     projectionMatrix.data[7] = 0.0;  
  21.       
  22.     projectionMatrix.data[8] = 2.0 * c_x / screen_width - 1.0;  
  23.     projectionMatrix.data[9] = 2.0 * c_y / screen_height - 1.0;  
  24.     projectionMatrix.data[10] = -( far+near ) / ( far - near );  
  25.     projectionMatrix.data[11] = -1.0;  
  26.       
  27.     projectionMatrix.data[12] = 0.0;  
  28.     projectionMatrix.data[13] = 0.0;  
  29.     projectionMatrix.data[14] = -2.0 * far * near / ( far - near );  
  30.     projectionMatrix.data[15] = 0.0;  
  31. }  
在我们载入这个矩阵到OpenGL管道后,接下来我们绘制物体。

任何一个变换都能够被4x4矩阵呈现并且载入到OpenGL模型视图矩阵,这一步将会把坐标系移动到世界坐标系中的标记处。

例如,让我们在每个标记的上方绘制一个坐标轴-它将会展示标记的在空间中的方向,并用渐变的矩形填充整个标记

。这个视觉化操作将会像预期一样给我们视觉上反馈。

下面是drawAR函数的实现:

  1. - (void) drawAR  
  2. {  
  3.     Matrix44 projectionMatrix;  
  4.     //相机的内参 屏幕的宽高 待输出的投影矩阵  
  5.     [self buildProjectionMatrix:m_calibration.getIntrinsic():m_frameSize.width :m_frameSize.height :projectionMatrix];  
  6.       
  7.     glMatrixMode(GL_PROJECTION);  
  8.     glLoadMatrixf(projectionMatrix.data);  
  9.       
  10.     glMatrixMode(GL_MODELVIEW);  
  11.     glLoadIdentity();  
  12.       
  13.     glDepthMask(TRUE);  
  14.     glEnable(GL_DEPTH_TEST);  
  15.     //glDepthFunc(GL_LESS);  
  16.     //glDepthFunc(GL_GREATER);  
  17.       
  18.     glEnableClientState(GL_VERTEX_ARRAY);  
  19.     glEnableClientState(GL_NORMAL_ARRAY);  
  20.       
  21.     glPushMatrix();  
  22.     glLineWidth(3.0f);  
  23.       
  24.     //三条轴  
  25.     float lineX[] = {0,0,0,1,0,0};  
  26.     float lineY[] = {0,0,0,0,1,0};  
  27.     float lineZ[] = {0,0,0,0,0,1};  
  28.       
  29.     const GLfloat squareVertices[] = {  
  30.         -0.5f, -0.5f,  
  31.         0.5f,  -0.5f,  
  32.         -0.5f,  0.5f,  
  33.         0.5f,   0.5f,  
  34.     };  
  35.     const GLubyte squareColors[] = {  
  36.         255, 255,   0, 255,  
  37.         0,   255, 255, 255,  
  38.         0,     0,   0,   0,  
  39.         255,   0, 255, 255,  
  40.     };  
  41.       
  42.     //遍历标记变换  
  43.     for (size_t transformationIndex=0; transformationIndex<m_transformations.size(); transformationIndex++)  
  44.     {  
  45.         const Transformation& transformation = m_transformations[transformationIndex];  
  46.           
  47.         Matrix44 glMatrix = transformation.getMat44();  
  48.           
  49.         glLoadMatrixf(reinterpret_cast<const GLfloat*>(&glMatrix.data[0]));  
  50.           
  51.         // 绘制数据  
  52.         glVertexPointer(2, GL_FLOAT, 0, squareVertices);  
  53.         glEnableClientState(GL_VERTEX_ARRAY);  
  54.         glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);  
  55.         glEnableClientState(GL_COLOR_ARRAY);  
  56.           
  57.         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  
  58.         glDisableClientState(GL_COLOR_ARRAY);  
  59.           
  60.         float scale = 0.5;  
  61.         glScalef(scale, scale, scale);  
  62.           
  63.         glTranslatef(0, 0, 0.1f);  
  64.           
  65.         glColor4f(1.0f, 0.0f, 0.0f, 1.0f);  
  66.         glVertexPointer(3, GL_FLOAT, 0, lineX);  
  67.         glDrawArrays(GL_LINES, 0, 2);  
  68.           
  69.         glColor4f(0.0f, 1.0f, 0.0f, 1.0f);  
  70.         glVertexPointer(3, GL_FLOAT, 0, lineY);  
  71.         glDrawArrays(GL_LINES, 0, 2);  
  72.           
  73.         glColor4f(0.0f, 0.0f, 1.0f, 1.0f);  
  74.         glVertexPointer(3, GL_FLOAT, 0, lineZ);  
  75.         glDrawArrays(GL_LINES, 0, 2);  
  76.     }  
  77.       
  78.     glPopMatrix();  
  79.     glDisableClientState(GL_VERTEX_ARRAY);  
  80. }  


作为一个例子的结尾,我们将演示我们的成果并总结。

OpenCV for Ios 学习笔记(10)-标记检测总结

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值