1. 程式人生 > >【ARToolkit】第二個例項simple2

【ARToolkit】第二個例項simple2

我們這次分析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中找到。

patt_center:標識的物理中心,這個函式假定標識在2維平面,z軸向下,所以角頂點位置能被呈現在2D平面上,標識的角頂點位置順時針指明;

patt_width:標識的大小,因為是正方形標識,寬度就代表了大小,單位為mm;

patt_trans:相對於標識物體 i 的真實的攝像機的位置和姿態包含在一個 3*4 的矩陣 patt_trans 中。其中patt_trans[0][3],patt_trans[1][3],patt_trans[2][3],分別表示了攝像頭的座標系的X軸,Y軸,Z軸。標識往左移動,第一個值會增加(往X軸正方向移動),往上移動(對應攝像機的Y軸負方向),數值減小,往前移動(對應Z軸正方向),數值增加,這裡的座標系是攝像頭的座標系

大家可以把printf("%f %f %f\n",patt_trans[0][3],patt_trans[1][3],patt_trans[2][3])這一行程式碼新增在arGetTransMat()函式的後面試一下。

       說了了那麼多,說完了函式的內容,接下里就要說一下這兩個函式arGetTransMat()和arGetTransMatCont()都是計算相機位置和檢測到的標識之間的轉換矩陣(重要的是函式裡面的內容&marker_info[k], patt_center, patt_width, patt_trans這些)。

       這兩個函式實現的東西是一樣的,不一樣的地方就是arGetTransMatCont()使方塊看起來很穩定,這是因為,在arGetTransMatCont()下,我們使用了歷史函式,使用歷史資訊會降低精確度,但是提供了更為穩定的影象,但是速度稍快些,在arGetTransMat()函式下,方塊像是有點微微的抖動。前一種情況就是我們使用了歷史函式,在後一種 情況下沒有使用。 所以這兩個函式的區別就在於一個使影象更穩定,但會降低精確度,另一個則不會降低精確度,影象不是那麼穩定。