您的位置:首页 > 移动开发 > IOS开发

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

2015-09-18 13:52 676 查看
本文原始地址:OpenCV for Ios 学习笔记(9)-用OPENGL渲染AR场景2

drawFrame的操作步骤是:

1.清除场景。

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

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

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

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

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

7.展示帧缓存。

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

   下面的就是drawFrame的代码:

[cpp] view
plaincopyprint?

- (void)drawFrame  

{  

    //启动激活的帧缓存  

    [m_glview setFramebuffer];  

      

    // 绘制背景  

    [self drawBackground];  

      

    // 在检测到的标记处绘制3维物体  

    [self drawAR];  

      

    // 呈现帧缓存  

    bool ok = [m_glview presentFramebuffer];  

      

    int glErCode = glGetError();  

    if (!ok || glErCode != GL_NO_ERROR)  

    {  

        std::cerr << "opengl 检测出错,错误代码是:" << glErCode << std::endl;  

    }  

}  

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

[cpp] view
plaincopyprint?

- (void) drawBackground  

{  

    //获取视口的宽高  

    GLfloat w = m_glview.bounds.size.width;  

    GLfloat h = m_glview.bounds.size.height;  

      

    //四个顶点坐标  

    const GLfloat squareVertices[] =  

    {  

        0, 0,  

        w, 0,  

        0, h,  

        w, h  

    };  

      

    //纹理顶点  

     static const GLfloat textureVertices[] =  

     {  

     1, 0,  

     1, 1,  

     0, 0,  

     0, 1  

     };  

      

    //正视矩阵  

    static const GLfloat proj[] =  

    {  

        0, -2.f/w, 0, 0,  

        -2.f/h, 0, 0, 0,  

        0, 0, 1, 0,  

        1, 1, 0, 1  

    };  

    /* 

     glMatrixMode - 指定哪一个矩阵是当前矩阵 

      

     mode 指定哪一个矩阵堆栈是下一个矩阵操作的目标,可选值: GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE. 

     说明 

     glMatrixMode设置当前矩阵模式: 

     GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作. 

     GL_PROJECTION,对投影矩阵应用随后的矩阵操作. 

     GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作. 

     与glLoadIdentity()一同使用 

     glLoadIdentity():该函数的功能是重置当前指定的矩阵为单位矩阵。 

     在glLoadIdentity()之后我们为场景设置了透视图。glMatrixMode(GL_MODELVIEW)设置当前矩阵为模型视图矩阵,模型视图矩阵储存了有关物体的信息。 

     */  

    glMatrixMode(GL_PROJECTION);  

    glLoadMatrixf(proj);  

      

    glMatrixMode(GL_MODELVIEW);  

    glLoadIdentity();  

      

    glDepthMask(FALSE);  

    glDisable(GL_COLOR_MATERIAL);  

      

    glEnable(GL_TEXTURE_2D);  

    glBindTexture(GL_TEXTURE_2D, m_backgroundTextureId);  

      

    // 更新属性值.  

    glVertexPointer(2, GL_FLOAT, 0, squareVertices);  

    glEnableClientState(GL_VERTEX_ARRAY);  

    glTexCoordPointer(2, GL_FLOAT, 0, textureVertices);  

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);  

      

    glColor4f(1,1,1,1);  

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  

      

    glDisableClientState(GL_VERTEX_ARRAY);  

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);  

    glDisable(GL_TEXTURE_2D);  

}  

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

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

[cpp] view
plaincopyprint?

- (void)buildProjectionMatrix:(Matrix33)cameraMatrix: (int)screen_width: (int)screen_height: (Matrix44&) projectionMatrix  

{  

    float near = 0.01;  // 近裁剪距离  

    float far  = 100;  // 远裁剪距离  

      

    // 相机的参数  

    float f_x = cameraMatrix.data[0]; // Focal length in x axis  

    float f_y = cameraMatrix.data[4]; // Focal length in y axis (usually the same?)  

    float c_x = cameraMatrix.data[2]; // Camera primary point x  

    float c_y = cameraMatrix.data[5]; // Camera primary point y  

      

    projectionMatrix.data[0] = - 2.0 * f_x / screen_width;  

    projectionMatrix.data[1] = 0.0;  

    projectionMatrix.data[2] = 0.0;  

    projectionMatrix.data[3] = 0.0;  

      

    projectionMatrix.data[4] = 0.0;  

    projectionMatrix.data[5] = 2.0 * f_y / screen_height;  

    projectionMatrix.data[6] = 0.0;  

    projectionMatrix.data[7] = 0.0;  

      

    projectionMatrix.data[8] = 2.0 * c_x / screen_width - 1.0;  

    projectionMatrix.data[9] = 2.0 * c_y / screen_height - 1.0;  

    projectionMatrix.data[10] = -( far+near ) / ( far - near );  

    projectionMatrix.data[11] = -1.0;  

      

    projectionMatrix.data[12] = 0.0;  

    projectionMatrix.data[13] = 0.0;  

    projectionMatrix.data[14] = -2.0 * far * near / ( far - near );  

    projectionMatrix.data[15] = 0.0;  

}  

在我们载入这个矩阵到OpenGL管道后,接下来我们绘制物体。

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

例如,让我们在每个标记的上方绘制一个坐标轴-它将会展示标记的在空间中的方向,并用渐变的矩形填充整个标记
。这个视觉化操作将会像预期一样给我们视觉上反馈。

下面是drawAR函数的实现:

[cpp] view
plaincopyprint?

- (void) drawAR  

{  

    Matrix44 projectionMatrix;  

    //相机的内参 屏幕的宽高 待输出的投影矩阵  

    [self buildProjectionMatrix:m_calibration.getIntrinsic():m_frameSize.width :m_frameSize.height :projectionMatrix];  

      

    glMatrixMode(GL_PROJECTION);  

    glLoadMatrixf(projectionMatrix.data);  

      

    glMatrixMode(GL_MODELVIEW);  

    glLoadIdentity();  

      

    glDepthMask(TRUE);  

    glEnable(GL_DEPTH_TEST);  

    //glDepthFunc(GL_LESS);  

    //glDepthFunc(GL_GREATER);  

      

    glEnableClientState(GL_VERTEX_ARRAY);  

    glEnableClientState(GL_NORMAL_ARRAY);  

      

    glPushMatrix();  

    glLineWidth(3.0f);  

      

    //三条轴  

    float lineX[] = {0,0,0,1,0,0};  

    float lineY[] = {0,0,0,0,1,0};  

    float lineZ[] = {0,0,0,0,0,1};  

      

    const GLfloat squareVertices[] = {  

        -0.5f, -0.5f,  

        0.5f,  -0.5f,  

        -0.5f,  0.5f,  

        0.5f,   0.5f,  

    };  

    const GLubyte squareColors[] = {  

        255, 255,   0, 255,  

        0,   255, 255, 255,  

        0,     0,   0,   0,  

        255,   0, 255, 255,  

    };  

      

    //遍历标记变换  

    for (size_t transformationIndex=0; transformationIndex<m_transformations.size(); transformationIndex++)  

    {  

        const Transformation& transformation = m_transformations[transformationIndex];  

          

        Matrix44 glMatrix = transformation.getMat44();  

          

        glLoadMatrixf(reinterpret_cast<const GLfloat*>(&glMatrix.data[0]));  

          

        // 绘制数据  

        glVertexPointer(2, GL_FLOAT, 0, squareVertices);  

        glEnableClientState(GL_VERTEX_ARRAY);  

        glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);  

        glEnableClientState(GL_COLOR_ARRAY);  

          

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  

        glDisableClientState(GL_COLOR_ARRAY);  

          

        float scale = 0.5;  

        glScalef(scale, scale, scale);  

          

        glTranslatef(0, 0, 0.1f);  

          

        glColor4f(1.0f, 0.0f, 0.0f, 1.0f);  

        glVertexPointer(3, GL_FLOAT, 0, lineX);  

        glDrawArrays(GL_LINES, 0, 2);  

          

        glColor4f(0.0f, 1.0f, 0.0f, 1.0f);  

        glVertexPointer(3, GL_FLOAT, 0, lineY);  

        glDrawArrays(GL_LINES, 0, 2);  

          

        glColor4f(0.0f, 0.0f, 1.0f, 1.0f);  

        glVertexPointer(3, GL_FLOAT, 0, lineZ);  

        glDrawArrays(GL_LINES, 0, 2);  

    }  

      

    glPopMatrix();  

    glDisableClientState(GL_VERTEX_ARRAY);  

}  

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

OpenCV for Ios 学习笔记(10)-标记检测总结
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opencv