您的位置:首页 > 运维架构

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

2016-03-21 14:23 330 查看
我的上篇博客《基于标记的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_<float>& cameraMatrix, vector<Marker>& 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"<<t<<endl;
setMarker(markers);  //导入找到的标识
#endif
cout<<"display"<<endl;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//绘制图片,第一、二、三、四个参数表示图象宽度、图象高度、像素数据内容、像素数据在内存中的格式,最后一个参数表示用于绘制的像素数据在内存中的位置
glDrawPixels(imagewidth,imageheight,GL_BGR_EXT,GL_UNSIGNED_BYTE,pixeldata);

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

glMatrixMode设置当前矩阵模式:
GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作.
GL_PROJECTION,对投影矩阵应用随后的矩阵操作.
GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作.
与glLoadIdentity()一同使用
glLoadIdentity():该函数的功能是重置当前指定的矩阵为单位矩阵。
在glLoadIdentity()之后我们为场景设置了透视图。glMatrixMode(GL_MODELVIEW)设置当前矩阵为模型视图矩阵,模型视图矩阵储存了有关物体的信息。
*/
//绘制坐标  ,导入相机内参数矩阵模型
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projectionMatrix.data);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

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_detectedMarkers.size(); transformationIndex++)
{
const Transformation& transformation = m_detectedMarkers[transformationIndex].transformation;
Matrix44 glMatrix = transformation.getMat44();

//导入相机外参数矩阵模型
glLoadMatrixf(reinterpret_cast<const GLfloat*>(&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 第二章书中代码。
我实现的代码已上传到,需要的自行下载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: