ARToolKit編程框架研究

一. ARToolKit SDK中基於多標示的識別例程:

 

    ART是基於OPENGL和DSVL的增強現實軟件包,它遵循OPENGL的運行模式,基於幀循環實現3D圖像的渲染,
在每次進入幀循環後做標識物的檢測和攝像機的重定位。

 

    當然這裏使用DSVL的視頻處理和基於OPENGL的圖像處理,都可以用其他方式來代替。比如可以用OSG圖形
引擎來完成較爲複雜的圖像處理,效果會更好,它也是基於OPENGL的接口,也需要在幀循環中處理。

 

下面的步驟必須在應用程序中採取的主要代碼:

 

 

Initialization 1. 初始化視頻捕獲和讀取文件的標記模式和相機參數.
Main Loop 2. 獲取一幀輸入視頻.
3. 在輸入視頻圖像中檢測標識和註冊的模版.
4. 計算攝像機相對於檢測到的模版的位置.
5. 繪製虛擬模型到檢測到的模板上.
Shutdown 6. 關閉視頻捕獲,回收資源.

 

#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>
#include <AR/arMulti.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;

char           *cparam_name    = "Data/camera_para.dat";    //攝像機特徵參數
ARParam         cparam;

char                *config_name = "Data/multi/marker.dat"; //標識信息
ARMultiMarkerInfoT  *config;

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 trans1[3][4], double trans2[3][4], int mode );

//程序入口
int main(int argc, char **argv)
{
 //初始化OPENGL
 glutInit(&argc, argv);

 //初始化攝像機參數和顯示窗口
    init();

 //啓動攝像機
    arVideoCapStart();

 //註冊響應事件函數(分別是鼠標事件、鍵盤事件、幀循環) 
    //實際是用OPENGL的內部事件處理機制,這裏只是傳遞函數指針
    argMainLoop( NULL, keyEvent, mainLoop );
 return (0);
}

//鍵盤事件響應函數
static void   keyEvent( unsigned char key, int x, int y)
{
    /* quit if the ESC key is pressed */
 /* 點擊ESC退出 */
    if( key == 0x1b ) {
        printf("*** %f (frame/sec)/n", (double)count/arUtilTimer());

  //釋放資源
        cleanup();
        exit(0);
    }

 //調整二值化閘值 
    if( key == 't' ) {
        printf("*** %f (frame/sec)/n", (double)count/arUtilTimer());
        printf("Enter new threshold value (current = %d): ", thresh);
        scanf("%d",&thresh); while( getchar()!='/n' );
        printf("/n");
        count = 0;
    }

    /* turn on and off the debug mode with right mouse */
 /* 調試模式開關,顯示二值化圖像*/
    if( key == 'd' ) {
        printf("*** %f (frame/sec)/n", (double)count/arUtilTimer());
        arDebug = 1 - arDebug;
        if( arDebug == 0 ) {
            glClearColor( 0.0, 0.0, 0.0, 0.0 );
            glClear(GL_COLOR_BUFFER_BIT);

   //交換緩衝區
            argSwapBuffers();
            glClear(GL_COLOR_BUFFER_BIT);
            argSwapBuffers();
        }
        count = 0;
    }

}

/* main loop */
/* 主循環:完成標示物的檢測和位置的重定位,並渲染模型。 */
static void mainLoop(void)
{
    ARUint8         *dataPtr;
    ARMarkerInfo    *marker_info; //標誌信息結構
    int             marker_num;
    double          err;
    int             i;

    /* grab a vide frame */
 /* 獲取一幀圖像 */
    if( (dataPtr = (ARUint8 *)arVideoGetImage()) == NULL ) {
  
  //調用延時
        arUtilSleep(2);
        return;
    }
 
 //計時復位
    if( count == 0 ) arUtilTimerReset();
    count++;

    /* detect the markers in the video frame */
 /* 檢測標識 */
    if( arDetectMarkerLite(
            dataPtr, //幀數據
             thresh, //二值化閘值
          &marker_info, //標識特徵信息
          &marker_num   // 標識數量
  ) < 0 ) {
        cleanup();
        exit(0);
    }

 //爲渲染2D或3D對象更新當前攝像機參數
    argDrawMode2D();
    if( !arDebug ) {
        argDispImage( dataPtr, 0,0 );
    }
    else {
        argDispImage( dataPtr, 1, 1 );//調試模式下不顯示攝像機圖像作爲背景
        if( arImageProcMode == AR_IMAGE_PROC_IN_HALF )
            argDispHalfImage( arImage, 0, 0 );
        else
            argDispImage( arImage, 0, 0);

        glColor3f( 1.0, 0.0, 0.0 );
        glLineWidth( 1.0 );
        for( i = 0; i < marker_num; i++ ) {
            argDrawSquare( marker_info[i].vertex, 0, 0 );
        }
        glLineWidth( 1.0 );
    }

 //每幀必須調用這個函數,完成諸多功能的支持...
    arVideoCapNext();

 //獲取攝像機位置
    if( (err=arMultiGetTransMat(marker_info, marker_num, config)) < 0 ) {
        argSwapBuffers();
        return;
    }
    printf("err = %f/n", err);
    if(err > 100.0 ) {
        argSwapBuffers();
        return;
    }
/*
    for(i=0;i<3;i++) {
        for(j=0;j<4;j++) printf("%10.5f ", config->trans[i][j]);
        printf("/n");
    }
    printf("/n");
*/
    argDrawMode3D();
    argDraw3dCamera( 0, 0 );//3D模式開關
    glClearDepth( 1.0 );
    glClear(GL_DEPTH_BUFFER_BIT);

 //將模型繪製到對應位置
    for( i = 0; i < config->marker_num; i++ ) {
        if( config->marker[i].visible >= 0 ) draw( config->trans, config->marker[i].trans, 0 );
        else                                 draw( config->trans, config->marker[i].trans, 1 );
    }
    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( (config = arMultiReadConfigFile(config_name)) == NULL ) {
        printf("config data load error !!/n");
        exit(0);
    }

    /* open the graphics window */
 /* 打開圖像窗口 */
    argInit( &cparam, 1.0, 0, 2, 1, 0 );
    arFittingMode   = AR_FITTING_TO_IDEAL;
    arImageProcMode = AR_IMAGE_PROC_IN_HALF;
    argDrawMode     = AR_DRAW_BY_TEXTURE_MAPPING;
    argTexmapMode   = AR_DRAW_TEXTURE_HALF_IMAGE;
}

/* cleanup function called when program exits */
/* 當退出程序時回收資源 */
static void cleanup(void)
{
    arVideoCapStop();
    arVideoClose();
    argCleanup();
}

//繪製3D模型,這部分完全屬於OPENGL的內容
static void draw( double trans1[3][4], double trans2[3][4], int mode )
{
    double    gl_para[16];
    GLfloat   mat_ambient[]     = {0.0, 0.0, 1.0, 1.0};
    GLfloat   mat_ambient1[]    = {1.0, 0.0, 0.0, 1.0};
    GLfloat   mat_flash[]       = {0.0, 0.0, 1.0, 1.0};
    GLfloat   mat_flash1[]      = {1.0, 0.0, 0.0, 1.0};
    GLfloat   mat_flash_shiny[] = {50.0};
    GLfloat   mat_flash_shiny1[]= {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};
   
 //進入3D繪圖模式
    argDrawMode3D();
    argDraw3dCamera( 0, 0 );
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
   
    /* load the camera transformation matrix */
 /* 加載攝像機轉換矩陣 */
    glMatrixMode(GL_MODELVIEW);
    argConvGlpara(trans1, gl_para);
    glLoadMatrixd( gl_para );
    argConvGlpara(trans2, gl_para);
    glMultMatrixd( gl_para );

    if( mode == 0 ) {
        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);
    }
    else {
        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_flash1);
        glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny1); 
        glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient1);
    }
    glMatrixMode(GL_MODELVIEW);
    glTranslatef( 0.0, 0.0, 25.0 );
    if( !arDebug ) glutSolidCube(50.0);
     else          glutWireCube(50.0);
    glDisable( GL_LIGHTING );

    glDisable( GL_DEPTH_TEST );
}

二 這個程序使用的標示圖像如下:

 

    其中包括了六個標示,這些標示的特徵被記錄在六個獨體的PATT文件中。加載時不需要一一說明,只需要加載這六個文件
的總說明文件即“marker.dat”即可。

 

 

三 標示特徵文件“marker.dat”的內部結構:

 

    這個文件中並沒有標示物的具體特徵參數,而是他們加載後的識別順序和對應的特徵文件名。

 

 

四 程序運行的效果:

 

 

五 如果對這個說明還有任何疑問,可以留言。我會盡量補充!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章