基于标记的AR的OpenCV实现:动态视频输入

我的上篇博客《基于标记的AR的OpenCV实现》实现的是单幅图片的标记检测和增强现实,稍微改动了程序实现了摄像头视频流图像的动态检测和实时增强,经测试,

实时性不错,在标记不被遮挡的情况下,绘制的虚拟模型和实时与检测标记结合,但标记只要有被遮挡一少部分,标记就检测失败。

以下讲下程序修改部分。

1:show函数并没有修改,但还是讲一下程序流程,首先在main()函数中调用show()函数后,在show()函数中,首先完成一些显示参数的初始化,这部分只需执行一次即可,然后将图像数据读入pixeldata中,之后通过glutDisplayFunc(&display)调用display()函数进行显示但请注意,display()函数只会执行一次。glutMainLoop进入GLUT事件处理循环。在一个GLUT程序中,这个例程被调用一次 。一旦被调用,这个程序将永远不会返回 。它将调用必要的任何已注册的回调

int show(const char* filename,int argc, char** argv,Mat_& cameraMatrix, vector& detectedMarkers)  
{  
    //打开文件  
    FILE* pfile=fopen(filename,"rb");  
    if(pfile == 0) exit(0);  
    //读取图像大小  
    fseek(pfile,0x0012,SEEK_SET);  
    fread(&imagewidth,sizeof(imagewidth),1,pfile);  
    fread(&imageheight,sizeof(imageheight),1,pfile);  
    //计算像素数据长度  
    pixellength=imagewidth*3;  
    while(pixellength%4 != 0)pixellength++;  
    pixellength *= imageheight;  
    //读取像素数据  
    pixeldata = (GLubyte*)malloc(pixellength);  
    if(pixeldata == 0) exit(0);  
    fseek(pfile,54,SEEK_SET);  
    fread(pixeldata,pixellength,1,pfile);  
    //以上是读取一个bmp图像宽高和图像数据的操作
    //关闭文件  
    fclose(pfile);  
  
    build_projection(cameraMatrix);  //这是建立摄像机内参数矩阵,就是相机矩阵,display函数开始导入的模型就是相机矩阵
    setMarker(detectedMarkers);  //导入找到的标识
    //初始化glut运行  
    glutInit(&argc,argv);  
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);  
    glutInitWindowPosition(100,100);  
    glutInitWindowSize(imagewidth,imageheight);  
    glutCreateWindow(filename);  
    glutDisplayFunc(&display);  
    glutMainLoop();  
    //-------------------------------------  
    free(pixeldata);  
    return 0;  
}

2:为了实现 display()函数的循环调用,执行glutPostRedisplay();语句会触发一次display()的执行,有两种思路:1:设置一个定时器,定时执行glutPostRedisplay();从而周期性

调用display()函数;2:在display()函数体最后执行glutPostRedisplay();从而完成自我不断触发调用。我采用了思路2的做法成功实现,思路1原理上也可实现。

主要修改display()函数。#if 1---#endif为添加部分,主要是更新图像数据,并执行markerDetector.processFrame(src,camMatrix, distCoeff,markers);从而得到更新后标记。

pixeldata的更新还是采用show()函数中读图像文件的方法,因此先将从摄像头读入图像保存为一个临时图片文件"aa.bmp",在用fread()读入的方式,这种方法确实比较low,
但比较容易实现了想要达到的效果。

void display(void)  
{  
#if 1
    Mat src;
    camera >> src;
    imwrite("aa.bmp",src);
    //打开文件  
    FILE* pfile=fopen("aa.bmp","rb");  
    if(pfile == 0) exit(0);  
    fseek(pfile,54,SEEK_SET);  
    fread(pixeldata,pixellength,1,pfile);  
    //以上是读取一个bmp图像宽高和图像数据的操作
    //关闭文件  
    fclose(pfile);  

  double t = (double)getTickCount();
      markerDetector.processFrame(src,camMatrix, distCoeff,markers);
  t = ((double)getTickCount() - t)/getTickFrequency(); 
  cout<<"t"<(&glMatrix.data[0]));  //reinterpret_cast:任何类型的指针之间都可以互相转换,修改了操作数类型,仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换
  
        glVertexPointer(2, GL_FLOAT, 0, squareVertices);  //指定顶点数组的位置,2表示每个顶点由三个量构成(x, y),GL_FLOAT表示每个量都是一个GLfloat类型的值。第三个参数0。最后的squareVertices指明了数组实际的位置。这个squareVertices是由第一个参数和要画的图形有几个顶点决定大小,理解。
        glEnableClientState(GL_VERTEX_ARRAY);  //表示启用顶点数组
        glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);  //RGBA颜色,四个顶点
        glEnableClientState(GL_COLOR_ARRAY);  //启用颜色数组
  
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  
        glDisableClientState(GL_COLOR_ARRAY);  
  
        float scale = 0.5;  
        glScalef(scale, scale, scale);  
  
        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);  
    }     
    glFlush();  
    glPopMatrix();  
  
    glDisableClientState(GL_VERTEX_ARRAY);    
    
    glutSwapBuffers();  
    glutPostRedisplay();
} 


本博客所改代码为mastering opencv with practical computer vision projects 第二章书中代码。

我实现的代码已上传到,需要的自行下载。



你可能感兴趣的:(基于标记的AR的OpenCV实现:动态视频输入)