一. 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”的內部結構:
這個文件中並沒有標示物的具體特徵參數,而是他們加載後的識別順序和對應的特徵文件名。
四 程序運行的效果:
五 如果對這個說明還有任何疑問,可以留言。我會盡量補充!