接上一则:ARToolkit(5):解决“error LNK2019: 无法解析的外部符号 ___glutCreateWindowWithExit@8”错误(http://blog.csdn.net/qingyang8513/article/details/45339445)
这部分内容参考了官网教程和网上一些帖子,同时添加了自己如何创建一个ARToolkit程序,而不是仅仅翻译官网的教程,到目前为止还没有找到一篇从创建工程开始的帖子。由于自己的水平有限,可能会有一些错误,仅供自己学习与记录,同时也给刚刚入门的小白们一个方向。
过程中可能会遇到一个问题,在上一则ARToolkit(5)中已有总结,如果遇到同样的问题请参考前一则内容。
下面使用VS2010从创建自己的项目开始,同时参考ARToolkit例程ARToolKit\examples\simple\simpleTest.c中的程序,并对程序做详细的注释。
一、开发环境
1、操作系统:Windows 7(64位)
2、编程环境:Microsoft Visual Studio 2010
3、ARToolkit版本:ARToolKit-2.72.1
二、创建自己的项目
1、打开Microsoft Visual Studio 2010,创建一个32位控制台程序;
2、输入项目名称,如这里我用的ARFirstApplication,选择项目目录,点击确定;
3、选择默认设置,完成项目创建;
4、打开ARToolKit\examples\simple\simpleTest.c文件,将全部代码复制到自己创建的项目的资源文件里,这里我的是ARFirstApplication.cpp;
5、点击“生成 --- 生成解决方案”,发现程序报错,详细错误如前一则内容ARToolkit(5);
6、按照前一则内容,将bin文件夹、Data文件夹和Wrl文件夹复制到相应位置,并设置VS附件库目录;
7、点击“生成 --- 生成解决方案”,此时已经显示生成成功。
成功创建自己的项目以后, 就可以按照ARToolkit例程中的程序框架编写自己的ARToolkit程序,当然首先应该完全清楚例程中的流程和每一步的含义,下面将ARToolKit\examples\simple\simpleTest.c中的代码贴出来,并做详细的注释,方便自己后续学习和使用。
三、代码详细注释
// ARFirstApplication.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#ifdef _WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#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>
using namespace std;
//
// Camera configuration.
//
#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 *patt_name = "Data/patt.hiro";
int patt_id;
double 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( void );
int main(int argc, char **argv)
{
glutInit(&argc, argv);
init();
arVideoCapStart();
argMainLoop( NULL, keyEvent, mainLoop );
//system("pause");
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);
}
}
/* main loop */
static void mainLoop(void)
{
ARUint8 *dataPtr; // 图像数据,unsigned char类型
ARMarkerInfo *marker_info; // 标记块信息,结构体类型:面积、id、方向dir、自信度、中心点位置、四边的直线方程、顶点坐标4个
int marker_num; // 标记块序号
int j, k;
/* grab a vide frame */ // 从摄像头获取图像数据,如果未获取图像,则2ms后返回
if( (dataPtr = (ARUint8 *)arVideoGetImage()) == NULL ) {
arUtilSleep(2);
return;
}
if( count == 0 ) arUtilTimerReset();// 启动程序时,复位定时器
count++; // 获取图像后,计数器加一
argDrawMode2D(); // 更新摄像头参数,为渲染2D和3D对象做准备
argDispImage( dataPtr, 0,0 ); // 显示图像
/* detect the markers in the video frame */ // 在摄像头输入帧中识别标记块,过程:阈值化、标记分类、轮廓提取、线角点估计。成功返回0,否则返回-1。
if( arDetectMarker(dataPtr, thresh, &marker_info, &marker_num) < 0 ) {
cleanup();
exit(0);
}
arVideoCapNext(); // 获取下一帧图像
/* check for object visibility */ // 寻找可识别的标记块,按照可信度大小选择可信度最大的一个,如果没有找到则k=-1
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 ) {
argSwapBuffers(); // 如果没有找到,则清除渲染缓冲区
return;
}
/* get the transformation between the marker and the real camera */
arGetTransMat(&marker_info[k], patt_center, patt_width, patt_trans); // 获取摄像机和标记块之间的坐标变换,其中patt_trans存储变换矩阵是指从标记块坐标系(图像坐标系)到摄像机坐标系的变换矩阵
draw(); // 渲染模型
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( void )
{
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(); // 更新摄像头参数用于3D渲染
argDraw3dCamera( 0, 0 ); // 对argDrawMode3D()的补充
glClearDepth( 1.0 );
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
/* load the camera transformation matrix */
argConvGlpara(patt_trans, gl_para); // 将ARToolkit下的参数矩阵转换为OpenGL下的参数矩阵(使用齐次坐标系)
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);//绘制一个边长为50的正方体
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
}
四、重要参考
1、官网教程:Documentation --- > Developing your First Application, Part 1(http://www.hitl.washington.edu/artoolkit/documentation/devstartup.htm)
2、ARToolkit中文论坛:日记的ARTOOLKIT笔记(1):从流程开始看(http://www.artoolkit.net/viewthread.php?tid=3597&extra=page%3D1)
在此,特别感谢ARToolkit中文论坛版主“杯具的黑白日记”,虽然已经时隔5年,但是他的良好习惯依然感染我让我这样详细的记录每一步学习历程,后续还会继续坚持下去,敬请期待!