开发原则
要使用 ARToolKit 开发应用有两个部分:编写应用程序,以及训练对增强现实应用中
所用到的真实世界标志的图像处理例程。
使用 ARToolKit 编写应用是很简单的:新建一个 AR 应用需要一个简单的框架。我们
在这个框架的基础上编写新的应用。同样地,因为应用这个简单的框架,训练模板的过程
也被简化。
一个应用程序的主代码必须包含以下步骤:
初始化
1 初始化视频捕获,读取标识文件和相机参数
2 抓取一帧输入视频的图像
3 探测标识以及识别这帧输入视频中的模板
4 计算摄像头相对于探测到的标识的转换矩阵
5 在探测到的标识上叠加虚拟物体
关闭
6 关闭视频捕捉
第二步到第五步一直重复,直到应用程序退出。但是步骤一和步骤六只分别在应用程
序的初始化时和关闭时才执行。除了这些步骤之外,一个应用程序还应该对鼠标、键盘或
者其他的特殊事件响应。
下一页将详细介绍各个步骤,再接着是讲解如何训练标识(还有处理多个标识的情
况)。
开发你的第一个程序:第一部分
Introduction
main
init
mainLoop
draw
cleanup
介绍
为了详细地示范怎么样开发一个 ARToolKit 的应用,我们将一步步地介绍一个现有的
例程的源代码:simpleTest(或者在有的版本里是 simple)。可以在目录 examples/simple/里
找到这个程序。
程序 simpleTest
我们要找的文件名字是 simpleTest.c (或者 simple.c )。这个程序仅仅包含了一个主函
数和几个绘制图像的函数。
相应于上节介绍的六个应用步骤的函数列出在表 1 中。相应于步骤二到步骤五的函数
在 mainLoop 函数(主循环)中被调用。
表格 1:相应于 ARToolKit 应用程序步骤的函数调用和代码
ARToolKit 步骤
1、应用程序初始化
2、抓取一帧输入视频
3、探测标识卡
函数
init
arVideoGetImage (在主循环中调用)
arDetectMarker(在主循环中调用)
4、计算摄像头的转移矩阵
arGetTransMat(在主循环中调用)
5、画上虚拟物体
6、关闭视频捕捉
draw(在主循环中调用)
cleanup
在这个程序中,最重要的函数是 main ,init , mainloop ,draw 和 cleanup。在本节的其他
部分我们将详细地解释这些函数调用。
main
Simple 例程中 main 函数的流程如下所示:
其中的初始化例程 init 包含的代码可以初始化视频捕捉,读取标识卡信息和摄像机参
数信息,以及设置图像窗口。这相对于《开发原则》中的第一步。接下来,我们通过调用
视频开始函数 arVideoCapStart 输入实时状态。再接着,函数 argMainLoop 被调用,这个函
数启动了主要的程序循环,通过键盘事件与函数 keyEvent 结合使用,通过主要的图像显示
循环与 mainLoop 结合使用。函数 argMainLoop 的定义在文件 gsub.c 中。
init
init 例程在 main 例程中被调用,它的作用是初始化视频捕捉以及读入 ARToolKit 应用
的初始参数信息。
首先,视频通道被打开,确定视频图像大小:
变量 vconf 包含了初始视频的配置,在 simple.c 的顶部被定义。但它的内容在你的平
台的函数里可能很不一样:参照视频配置链接。对于每一个平台,都定义了一个默认的字
符串,这个字符串一般都打开你的应用程序结构中第一个可用的视频流。
然后,我们需要初始化 ARToolKit 应用程序的参数。对于 ARToolKit 应用程序来说,
关键的参数是:
可能被用来进行模板模式匹配的模板信息,以及这些模板锁对应的虚拟物体。
所用的视频摄像机的相机特性参数。
这些都是从文件里读取,这些文件的名字可以在命令行里被指定,或使用硬件编码的
文件的默认名称。
因此,摄像机的参数信息通过默认的摄像机参数文件名 Data/camera_para.dat 被读入:
接下来,这些参数根据现有的图像大小被转换,因为摄像机的参数根据图像的大小而
改变,甚至是使用相同的摄像机。
摄像机的参数被读入它的程序设置,摄像机的参数被输出显示到屏幕上:
这样之后我们通过默认的模板文件 Data/patt.hiro 读入模板的定义信息:
其中 patt_id 是一个已经被识别的模板的鉴定信息(告诉我们是哪一个模板,相当于人
类的身份证)。
最终打开了图像窗口:
函数 arginit 的第二个参数定义了一个缩放函数,适应视频图像格式时的值设为 1.0,
值设为 2.0 时是双倍大小(比如说,输入 320*240 图像,输出为 VGA AR 格式)。
mainloop
ARToolKit 应用程序的大部分调用都在这个例程里完成,这个例程包含了相对于《开
发原则》中所要求的步骤二到步骤五。
首先通过函数 arVideoGetImage 来捕捉一个输入视频帧:
该视频图像立即被输出显示到屏幕上。这个图像可以是一幅没有被扭曲的图像,也可
以是一幅根据摄像头的失真信息被扭曲修正。扭曲以修正图像可以生成更加正常的图像,
但是可能会导致视频帧的速率明显降低。在下例中图像是已经被扭曲的:
接着函数 arDetectMarker 被使用以搜索整个图像来寻找含有正确的标识模板的方块:
找到的标识卡的数量被存放在变量 marker_num 里,同时 marker_info 是一个指向一列
标识结构体的指针,这个结构体包含了坐标信息,识别可信度,以及每个标识对应的鉴定
信息和物体。marker_info 的详细信息在 API documentation 中。
此时,视频图像已经被显示和分析了。所以我们不需要再使用它:我们可以在使用新
的函数的同时使用帧捕捉器来启动一个新的帧捕捉操作。完成这些工作,你只需要调用函
数 arVideoCapNext:
备注:当你调用这个函数时,使用上一个视频图像缓冲会导致坏的结果(根据你的应
用程序平台而定)。确保你已经处理好了视频图像缓冲。
接下来,所有的已经探测到的标识的可信度信息被加以比较,最终确定正确的标识鉴
定信息为可信度最高的标识的鉴定信息:
标识卡和摄像机之间的转移信息可以通过使用函数 arGetTransMat 来获取:
相对于标识物体 i 的真实的摄像机的位置和姿态包含在一个 3*4 的矩阵 patt_trans 中。
最后,使用绘图函数,虚拟物体可以被叠加在标识卡上:
备注:如果没有标识被找到(k==-1),应用程序会做一个简单的优化步骤,我们可以
交换缓冲器而不需要调用函数 draw,然后返回:
draw
函数 draw 分为显示环境初试化,设置矩阵,显示物体几个部分。你可以使用 ARToolKit
显示一个三维物体并设置最小的 OpenGL 状态来初始化一个 3d 显示:
在这之后你需要这个把转移矩阵(3*4 的矩阵)转化成 OpenGL 适用的格式(16 个值
的向量),可用函数 argConvGlpara 来完成此功能。这十六个值是真实世界的摄像机的位置
和姿态信息,因此利用这些信息可以设置虚拟世界摄像机的位置,因此任何的图形物体都
可以被准确地放置在相应的真实标识卡上。
虚拟世界的摄像机的位置是用函数 glLoadMatrixd(gl_para)来设置的。代码的最后是三
维物体的显示。在这个例子中,显示的是白色光束下是一个蓝色立方体:
在最后,你要重置某些 OpenGL 的参数为默认值:
上述所讲到的步骤出现并贯穿了主要显示函数的始终,当这个程序在运行时,鼠标事
件被鼠标事件函数控制,键盘事件被键盘函数控制。
cleanup
函数 cleanup 被调用的作用的停止视频处理以及关闭视频路径并释放它使其他的应用
可以使用:
这些工作可以使用函数 arVideoCapStop, arVideoClose 和 argCleanup 来完成。
你可以编译这个程序并运行它!
这个程序的一个限制的,它只使用模板 Hiro:使用其他多个模板是很有趣的!我们将
在下一节介绍怎么样使用其他模板。