我的上篇博客《基于标记的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;
}
调用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();
}
我实现的代码已上传到,需要的自行下载。