我们这次分析ARtooklit里面的simple2这个程序,我们先上源码,随后分析一些不同于simpletest的地方
#ifdef _WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef __APPLE__
#include <GL/gl.h>
#include <GL/glut.h>
#else
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#endif
#include <AR/gsub.h>
#include <AR/video.h>
#include <AR/param.h>
#include <AR/ar.h>
/* set up the video format globals */
#ifdef _WIN32
char *vconf = "Data\\WDM_camera_flipV.xml";
#else
char *vconf = "";
#endif
int xsize, ysize;
int thresh = 100;
int count = 0;
int mode = 1;//标识位
char *cparam_name = "Data/camera_para.dat";
ARParam cparam;
char *patt_name = "Data/patt.hiro";
int patt_id;
int patt_width = 80.0;
double patt_center[2] = {0.0, 0.0};
double patt_trans[3][4];
static void init(void);
static void cleanup(void);
static void keyEvent( unsigned char key, int x, int y);
static void mainLoop(void);
static void draw( double trans[3][4] );
int main(int argc, char **argv)
{
glutInit(&argc, argv);
init();
arVideoCapStart();
argMainLoop( NULL, keyEvent, mainLoop );
return (0);
}
static void keyEvent( unsigned char key, int x, int y)
{
/* quit if the ESC key is pressed */
if( key == 0x1b ) {
printf("*** %f (frame/sec)\n", (double)count/arUtilTimer());
cleanup();
exit(0);
}
//如果键盘输入c
if( key == 'c' ) {
printf("*** %f (frame/sec)\n", (double)count/arUtilTimer());
count = 0;
mode = 1 - mode;//让每次键盘输入c都让mode变化
//此处mode转换为布尔型,如果mode=0,则为假arGetTransMatCont
if( mode ) printf("Continuous mode: Using arGetTransMatCont.\n");
//如果mode不为假,输出arGetTransMat
else printf("One shot mode: Using arGetTransMat.\n");
}
}
/* main loop */
static void mainLoop(void)
{
static int contF = 0;//静态变量
ARUint8 *dataPtr;
ARMarkerInfo *marker_info;
int marker_num;
int j, k;
/* grab a vide frame */
if( (dataPtr = (ARUint8 *)arVideoGetImage()) == NULL ) {
arUtilSleep(2);
return;
}
if( count == 0 ) arUtilTimerReset();
count++;
argDrawMode2D();
argDispImage( dataPtr, 0,0 );
/* detect the markers in the video frame */
if( arDetectMarker(dataPtr, thresh, &marker_info, &marker_num) < 0 ) {
cleanup();
exit(0);
}
arVideoCapNext();
/* check for object visibility */
k = -1;
for( j = 0; j < marker_num; j++ ) {
if( patt_id == marker_info[j].id ) {
if( k == -1 ) k = j;
else if( marker_info[k].cf < marker_info[j].cf ) k = j;
}
}
if( k == -1 ) {
contF = 0;
argSwapBuffers();
return;
}
/*计算摄像头的转移矩阵,标识卡和摄像机之间的转移信息通过使用函数*/
//mode为0
if( mode == 0 || contF == 0 ) {
arGetTransMat(&marker_info[k], patt_center, patt_width, patt_trans);
}
else {
//mode为1
arGetTransMatCont(&marker_info[k], patt_trans, patt_center, patt_width, patt_trans);
}
contF = 1;
draw( patt_trans );
argSwapBuffers();
}
static void init( void )
{
ARParam wparam;
/* open the video path */
if( arVideoOpen( vconf ) < 0 ) exit(0);
/* find the size of the window */
if( arVideoInqSize(&xsize, &ysize) < 0 ) exit(0);
printf("Image size (x,y) = (%d,%d)\n", xsize, ysize);
/* set the initial camera parameters */
if( arParamLoad(cparam_name, 1, &wparam) < 0 ) {
printf("Camera parameter load error !!\n");
exit(0);
}
arParamChangeSize( &wparam, xsize, ysize, &cparam );
arInitCparam( &cparam );
printf("*** Camera Parameter ***\n");
arParamDisp( &cparam );
if( (patt_id=arLoadPatt(patt_name)) < 0 ) {
printf("pattern load error !!\n");
exit(0);
}
/* open the graphics window */
argInit( &cparam, 1.0, 0, 0, 0, 0 );
}
/* cleanup function called when program exits */
static void cleanup(void)
{
arVideoCapStop();
arVideoClose();
argCleanup();
}
static void draw( double trans[3][4] )
{
double gl_para[16];
GLfloat mat_ambient[] = {0.0, 0.0, 1.0, 1.0};
GLfloat mat_flash[] = {0.0, 0.0, 1.0, 1.0};
GLfloat mat_flash_shiny[] = {50.0};
GLfloat light_position[] = {100.0,-200.0,200.0,0.0};
GLfloat ambi[] = {0.1, 0.1, 0.1, 0.1};
GLfloat lightZeroColor[] = {0.9, 0.9, 0.9, 0.1};
argDrawMode3D();
argDraw3dCamera( 0, 0 );
glClearDepth( 1.0 );
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
/* load the camera transformation matrix */
argConvGlpara(trans, gl_para);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd( gl_para );
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambi);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMatrixMode(GL_MODELVIEW);
glTranslatef( 0.0, 0.0, 25.0 );
glutSolidCube(50.0);
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
}
上面的是每次输入字母C后的变化和用Hiro标识出现的结果
这篇simple2不同于simpletest的地方我用了特殊的颜色进行标记,在开头,添加了一个标识位,在后面用到了标识位。这篇代码在simpletest的基础上在键盘响应事件里面添加了如果用键盘输入字母C的响应事件,这里的意思是如果输入C,选择连续模式,就是使用arGetTransMatCout函数,或者选择单帧模式arGetTransMat求转换矩阵此时mode为0,这里的mode由整形强制转换为布尔类型,此处为布尔类型即为假则在控
制台输出"Continuous mode: Using arGetTransMatCont.\n",如果mode为1,则输出"One shot mode: Using arGetTransMat.\n"。后面我给大家讲解arGetTransMatCont函数和arGetTransMat函数的不同。
第二个不同在mainloop里面加入了一个 static contF = 0,在下面 计算摄像头的转移矩阵这
里,这里是如果mode==0或者contF==0,就执行arGetTransMat()函数,如果mode不等于0,就执行arGetTransMatCont()函数,这两个函数里面实现的内容都一样,都是&marker_info[k], patt_center, patt_width, patt_trans。
marker_info[k]:由arDetectMarker产生的结构体,下面为结构体的内容:
area:标识区域内的像素数量
id :为标识号
dir:方向,它告诉标记的旋转(可能的值是0、1、2或3).此参数告诉我们所检测标记的行序(即哪一行是第一行),从而找到第一个顶点。这对于计算arGetTransMat()中的转换矩阵非常重要
cf:置信度值(概率作为一个标记)
pons:中心(理想屏幕坐标)
line:理想屏幕坐标
vertex:标记点的顶点边缘点(在理想屏幕坐标中)
以上的内容能在ar.h中找到。