平成 25 年度機械情報工学科演習 コンピュータグラフィクス (2) 動画や

1
平成 25 年度 機械情報工学科演習
コンピュータグラフィクス (2)
動画やカメラを用いた 3DCG の応用
担当:谷川 智洋 講師,鳴海 拓志 助教,中垣 好之 技官
TA: 国分 新,田崎 亮平
2013 年 10 月 22 日
1 演習の目的
本日の演習では,前回学習した OpenGL の基礎を元に,USB カメラから取り込んだ動画を三次元コン
ピュータグラフィックス (3DCG) に貼り込む演習を通して,OpenCV との連携も学習する.また,CG とカ
メラ画像の連携による Augmented Reality についてもふれ,ARToolKit を利用したプログラムの演習を通し
て 3DCG への理解を深める.
1.1 資料など
本日の演習の資料などは,
http://www.cyber.t.u-tokyo.ac.jp/~tani/class/mech_enshu/
においてある.
本日使用するソースファイルも同じ場所からダウンロードすること.前回の資料を参照したい場合も同じ場
所を参照のこと.
1.2 出席・課題の確認について
出席の確認は,課題の確認によって行う.課題が終了したら,教員・TA を呼び,指示に従って実行して説
明せよ.
1.3 USB カメラについて
「メディアインタフェース」の演習 (2012/11/5(火), 7(木)) でも使用するので,忘れずに USB カメラを持参
すること.
2 動画の取り扱い
2
2 動画の取り扱い
前回の学習した画像の取り扱いを一歩進んで,OpenGL を用いて動画を取り扱うことについて説明する.
Linux におけるカメラ
Linux において,動画を利用するためには,Video for Linux(Video4Linux, v4l と略される) と呼ばれるカメ
ラデバイスを使うための API 仕様を利用する.Video4Linux を用いることにより,USB カメラ,IEEE1394
カメラなどから画像を読み込むことができるとともに,ビデオキャプチャボードからの読み込みもできる.ま
た,チューナー操作のための API 仕様などもそろっている.最近の Linux のカーネルでは,Video for Linux
2(Video4Linux2, v4l2 と略される) が組み込まれており,OpenCV でもこの API 仕様に基づいてキャプチャ
を行っている.
なお,現在は USB でカメラを扱う規格 (USB Video Class, UVC) が USB 2.0 の規格の拡張として策定さ
れており,この規格に準拠するカメラは一つのドライバで扱えるようになりつつある.本演習で配布してい
るカメラもこの規格に準拠しており,Linux に用意されている共通ドライバで扱うことができる.Linux の
カーネルに Video4Linux のドライバがインストールされており,かつ,ビデオキャプチャ用のドライバ(モ
ジュール)が正しくロードされていた場合,lsmod とコマンドで打ち込んだとき下記の様にロードされている
ことが確認できるはずである.
uvcvideo
compat_ioctl32
51204
0
5569
1 uvcvideo
videodev
30785
1 uvcvideo
v4l1_compat
17349
2 uvcvideo,videodev
v4l2_common
20801
2 uvcvideo,videodev
2.1 動画を利用するプログラム
OpenCV について
動画ファイルやカメラの利用は,Video4Linux などの API を利用しても,様々なパラメータの設定や読み
出しのための手順が不可欠である.OpenCV(Open Source Computer Vision Library) を利用することで,
複雑になりがちな動画の読み込みや動画像処理のプログラムの読みやすさや再利用性を向上させることがで
きる.また,OpenCV は OpenGL と同様にマルチプラットフォームなライブラリであり,どのようなオペ
レーティングシステムの上でも動作することを目指している.カメラを扱う場合でも,Video4Linux のよう
な API を利用すると,OS によって用意されている関数が異なるため,実行したい環境が変わるとプログラム
を書き直す必要がある.OpenCV は OS の違いを吸収し,対応する全ての OS の上で同じ関数を用いて,動
画を取り扱うことが可能である.
OpenCV と OpenGL は,それぞれ画像処理と 3DCG のライブラリであり,連携することで 3DCG の手法
でカメラ画像や動画ファイルを取り扱うことができる.本演習では,OpenCV でカメラ画像から取得したフ
レーム画像をテクスチャとして貼り付け,ポリゴンとして自由に操作することを可能にすることを目指す.
なお,OpenCV の各種情報は http://opencv.jp/ を見るとよい.http://opencv.jp/sample/ サンプルプロ
2.1 動画を利用するプログラム
3
グラムが数多く載っている.
OpenCV における画像データ
OpenCV の画像データの基本的な構造体は IplImage 構造体になり,OpenCV ではこの構造体を各種関数
の引数として渡している.既に何度か説明しているように,コンピュータ上での画像の取り扱いは,画像を
微小長方形領域(ピクセル=画素という)に分割し,そのピクセル単位で処理を行う.現在,カメラ映像は
640 * 480 のカラーピクセルの集合となっている場合が多く,配布しているカメラも同様である.カラー画像
の場合は,各画素には 3 つの値がデジタルデータとして入力され,三原色の赤緑青の RGB がそれぞれ 8bit
の値をとる.RGB の三原色をコンピュータのメモリにどのように格納するかにはさまざまな方法があるが,
OpenCV の場合,始めのバイトが左上角の B,次が左上角の G,その次が左上角の R で,さらにその次が一
つ右隣の B,それから一つ右隣の G,一つ右隣の R というように格納されている.この場合 3 バイトごとに
1 画素ずつが相当することになる.
nSize
IplImage 構造体のサイズ
nChannels
チャンネル数 1,2,3,4 のどれか
depth
1 画素あたりのビット数
origin
画像データの原点(基準)
width
画像の幅(画素数)
height
画像の高さ(画素数)
imageSize
画像データのサイズ(バイト数) (= widthStep * height)
imageData
画像データへのポインタ
widthStep
画像データの幅のバイト数(画素数ではない)
表 1 IplImage 構造体の主なメンバ変数
画像データをファイルから確保する場合は,cvLoadImage 関数を呼ぶ.
IplImage* cvLoadImage( const char* filename, int flags=CV_LOAD_IMAGE_COLOR );
filename
読み込むファイル名.
flags
読み込む画像がカラー/グレースケールのどちらか,とデプスを指定する.
画像を取り扱う構造体を新規に確保する場合は,cvCreateImage 関数をよぶ.例えば,一般的によく使われ
る RGB 各 8 ビット,各画素 24 ビットの画像を取り扱う場合は,depth に符号無し 8 ビット整数を意味する
IPL DEPTH 8U を,channels に 3 を指定する.
2 動画の取り扱い
4
IplImage* cvCreateImage( CvSize size, int depth, int channels );
size
画像の幅と高さ.
depth
画像要素のビットデプス.以下の内のいずれか.
IPL_DEPTH_8U - 符号無し 8 ビット整数
IPL_DEPTH_8S - 符号有り 8 ビット整数
IPL_DEPTH_16U - 符号無し 16 ビット整数
IPL_DEPTH_16S - 符号有り 16 ビット整数
IPL_DEPTH_32S - 符号有り 32 ビット整数
IPL_DEPTH_32F - 単精度浮動小数点数
IPL_DEPTH_64F - 倍精度浮動小数点数
channels
要素(ピクセル)毎のチャンネル数.1, 2, 3, 4 のいずれか.
また,プログラム終了時や対象とする構造体が不要になった場合は,cvReleaseImage 関数をよぶことで必
ず解放する.
void cvReleaseImage( IplImage** image );
image
確保した画像ヘッダへのポインタのポインタ.
なお,OpenGL では,左下角から,R,G,B の順番に格納された画像データを前提としているため,
OpenCV で読み込んだ画像データを OpenGL 使用する場合,OpenCV 側で格納の順番を変換する処理を行
うか,OpenGL の関数引数の設定 (GL BGR EXT や GL BGRA など) や座標の変換による処理が必要に
なる.OpenCV 側で行う場合,cvCvtColor() 関数の引数に CV BGR2RGB を指定することで,BGR から
RGB の順に配列を変換することができる.
void cvCvtColor( const CvArr* src, CvArr* dst, int code );
src
入力画像,8 ビット(8u),16 ビット(16u),あるいは単精度浮動小数点型(32f).
dst
出力画像,入力画像と同じデータタイプ.チャンネル数は違うこともある.
code
CV_<src_color_space>2<dst_color_space> の定数を用いて色空間の変換を指定
2.1 動画を利用するプログラム
5
カメラからのキャプチャ準備
OpenCV で動画像を扱うプログラムを記述する際には,準備のために CvCapture 構造体を初期化する必要
がある.
カメラから動画を入力する場合,初期化は下記のように行う.cvCreateCameraCapture() は OpenCV 内
でのキャプチャデバイスとしてのカメラを初期化する関数で,引数はカメラのインデックスを表している.カ
メラが複数ある場合はこの引数を変えて指定する.0 を指定した場合は自動で使用可能なカメラを判断する.
なお,接続可能なデバイスがない場合 cvCreateCameraCapture() は NULL を返す.なお,OpenCV のサン
プルプログラムには cvCaptureFromCAM() が用いられている場合もあるが,cvCreateCameraCapture() と
等価である.
CvCapture* cvCreateCameraCapture( int index );
index
使われるカメラのインデックス.
使用するカメラが1台のときか,何台のカメラを使うかが重要でないときは,
-1 でも問題ない場合もある.
また,動画ファイルから入力する場合は,初期化において cvCreateCameraCapture() のかわりに cvCre-
ateFileCapture() を呼び出す.プログラムの他の部分はそのままで,カメラ入力処理のプログラムを動画ファ
イルから画像を読み込んで処理するプログラムとすることができる.
CvCapture* cvCreateFileCapture( const char* filename );
filename
ビデオファイル名.
関数 cvSetCaptureProperty() により,ビデオキャプチャ構造体のプロパティをセットすることができる.
例えば,下記の様にすることによりキャプチャをおこなう際の画面サイズ(幅と高さ)を指定することができ
る.ただし,実際のカメラがサポートしていないキャプチャサイズは指定できない.
int cvSetCaptureProperty( CvCapture* capture, int property_id,
double value );
capture:
ビデオキャプチャ構造体.
property_id
プロパティ ID.
2 動画の取り扱い
6
同様に,関数 cvGetCaptureProperty() により,ビデオキャプチャ構造体のプロパティを取得することがで
きる.カメラのキャプチャ画面のサイズ(幅と高さ)を取得することができる.ただし,正しい値を取得する
には,cvQueryFrame() などで一度画像を取得しておく必要がある.
double cvGetCaptureProperty( CvCapture* capture, int property_id );
capture
ビデオキャプチャ構造体.
property_id
プロパティ ID.
なお,引数として与えられるプロパティ ID は以下の通り.
CV CAP PROP POS MSEC
ファイル中の現在の位置(ミリ秒単位)
CV CAP PROP POS FRAMES
次にデコード/キャプチャされるフレームのインデックス.
CV CAP PROP POS AVI RATIO
ビデオファイル内の相対的な位置
CV CAP PROP FRAME WIDTH
ビデオストリーム中のフレームの幅
CV CAP PROP FRAME HEIGHT
ビデオストリーム中のフレームの高さ
CV CAP PROP FPS
フレームレート
CV CAP PROP FOURCC
コーデックを表す 4 文字
CV CAP PROP FRAME COUNT
ビデオファイル中のフレーム数
表2
ビデオキャプチャ構造体のプロパティ ID
キャプチャ処理
カメラやビデオファイルから 1 つのフレームを取り出して返す場合は,キャプチャデバイス(前項で取得し
た CvCapture 構造体)が有効な間,カメラや動画ファイルからフレーム(1 枚の画像)を取り込むことがで
きる.この処理には cvQueryFrame() を呼び出す.この関数が呼び出されるとカメラ又は AVI ファイルから
画像が 1 枚取り込まれ,IplImage 構造体へのポインタが返される.ここで返ってくる画像(IplImage 構造
体)はデバイスの初期化関数の内部で確保されているので,プログラムの途中で解放してはいけない.また,
この返り値が NULL の場合,対象となるカメラと切断されたかファイルの最後まで処理されたことになるの
で,終了処理を行う必要がある.
IplImage* cvQueryFrame( CvCapture* capture );
capture
ビデオキャプチャ構造体.
2.2 簡単な例
7
キャプチャの終了処理
cvCreateCameraCapture(),又は cvCreateFileCapture() で取得したキャプチャデバイスは,デバイス使
用終了時(典型的にはプログラム終了時)に cvReleaseCapture() を呼びだして解放する必要がある.
void cvReleaseCapture( CvCapture** capture );
capture
ビデオキャプチャ構造体へのポインタ.
2.2 簡単な例
キャプチャをしたデータを表示すると,下記のように Window 内に表示することが可能となる(図 1).
図 1 動画読み込みと描画
カメラキャプチャの初期化と解放
以下に,OpenGL でキャプチャ画像を表示する場合の,OpenCV によるキャプチャデバイスの初期化と解
放の例を示す.
/* OpenGL */
#include <GL/glut.h>
/* OpenCV */
#include <opencv/cv.h>
#include <opencv/highgui.h>
2 動画の取り扱い
8
IplImage
*frame;
/* Capture Imege from OpenCV */
CvCapture*
capture = 0;
/* Video Capture Structure */
int
dev_index = 0;
/* Capture Device ID */
void my_init(int argc, char **argv)
{
// Initialization Part -
OpenCV
// Connect to Capture Device
capture = cvCreateCameraCapture(dev_index);
if (capture) {
frame = cvQueryFrame(capture);
cap_width = cvGetCaptureProperty(capture,
CV_CAP_PROP_FRAME_WIDTH);
cap_height = cvGetCaptureProperty(capture,
CV_CAP_PROP_FRAME_HEIGHT);
} else {
fprintf(stderr, "Found No Camera\n");
exit(-1);
}
// Flip Captured Image
if (frame->origin==0) {
cvFlip(frame, frame, 0);
}
// Convert Color Alignment BGR -> RGB
cvCvtColor(frame, frame, CV_BGR2RGB);
win_width = cap_width;
win_height = cap_height;
}
int my_exit(int e)
{
/* Release Process - OpenCV */
if (capture) cvReleaseCapture(&capture);
exit(e);
}
2.2 簡単な例
9
カメラ画像の取得
カメラからの画像の更新は,idle 関数内において cvQueryFrame() を呼び出すことで行う.また,OpenGL
で扱うために画像の上下反転処理を cvFlip(),BGR から RGB 配列への変換処理を cvCvtColor() で行って
いる.
void idle(void)
{
if (capture) {
frame = cvQueryFrame(capture);
if (frame->origin==0) {
cvFlip(frame, frame, 0 );
}
cvCvtColor(frame, frame, CV_BGR2RGB);
}
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glutPostRedisplay();
}
本演習ではキャプチャデバイスから取得した IplImage 構造体の画像データを直接表示している.実際に画
像処理をした画像を表示する場合は,cvCloneImage() などで確保した構造体に処理結果を格納した上で,そ
の画像データの表示を行う.
IplImage* cvCloneImage( const IplImage* image );
image
オリジナル画像.
読み込んだ動画の描画
「コンピュータグラフィックス」で学習した glDrawPixels() を呼び出して,キャプチャした画像を表示する
ことができる.
void glDrawPixels(GLsizei width, GLsizei height, GLenum format,
GLenum type, GLvoid *pixels);
void glRasterPos{234}{sifd}(TYPE x, TYPE y, TYPE z, TYPE w);
2 動画の取り扱い
10
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom((GLdouble)(win_width-2)/(GLdouble)cap_width,
(GLdouble)(win_height-2)/(GLdouble)cap_height);
glRasterPos2i(-win_width/2+1, -win_height/2+1);
glDrawPixels(cap_width, cap_height, GL_RGB, GL_UNSIGNED_BYTE,
frame->imageData);
glFlush();
glutSwapBuffers();
}
2.3 カメラ画像のテクスチャマッピング
また,図 2 に示すように,読み込んだ画像データをテクスチャとしてマッピングすることで,動画を貼るこ
とが可能である.テクスチャマッピングは通常の方法と同じである.参照: sample-texture.c
図2
動画:3 次元ポリゴンへのテクスチャマッピング
テクスチャを動画として動的に更新したい場合,あらかじめ確保したテクスチャ・オブジェクトの画像を上
書きして実現する方法を用いる.glTexImage2D() で設定したテクスチャ・オブジェクトの画像を更新するに
は,2 次元テクスチャ画像を上書きする glTexSubImage2D() 関数を用いる.
2.3 カメラ画像のテクスチャマッピング
11
void glTexSubImage2D( GLenum target, GLint level,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height,
GLenum format, GLenum type, const GLvoid *pixels );
下記に示すように,idle 関数内において,カメラからの画像キャプチャを行い,glTexSubImage2D() 関数
を用いてテクスチャ画像の更新を行う.
void idle(void)
{
if (capture) {
frame = cvQueryFrame(capture);
if (frame->origin==0) {
cvFlip(frame, frame, 0);
}
cvCvtColor(frame, frame, CV_BGR2RGB);
}
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glBindTexture( GL_TEXTURE_2D, tex_index );
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
frame->width, frame->height,
GL_RGB, GL_UNSIGNED_BYTE, frame->imageData );
glutPostRedisplay();
}
なお,テクスチャマッピングでは,画像を物体のポリゴン面などに対応づけ,各頂点に画像上の位置を対応
づけることで行われる.画像上の位置とポリゴンの頂点の対応付けには,glVertex() で頂点座標を指定する前
に,対応する画像の位置を glTexCoord() で指定を行う.なお,画像上の位置は画像の画素数ではなく,画像
全体をテクスチャ画像全体を 0.0...1.0 で正規化された座標系で位置を指定する.ただし,OpenGL における
テクスチャ画像は,2 の累乗である必要がある.そのため,テクスチャ画像は貼りたい画像のサイズより大き
い 2 の累乗のサイズで確保する.例えば,今回の様に 640 * 480 の画像をテクスチャとしてマッピングした
い場合,1024 * 512 の画像として扱う.
テクスチャ座標は確保したテクスチャ画像の大きさで正規化されているため,更新される動画像をテクス
チャとして正しくマッピングするためには,それぞれ確保されたテクスチャ画像のサイズに対する貼りたい画
像のサイズの比率をかけた値を指定する必要がある.例えば,図 3 に示すように 640 * 480 の動画像をマッ
ピングしたい場合,1024 * 512 のテクスチャ画像として確保されているため,glTexCoord() で指定するテク
スチャ座標には,横方向に 0.625(=640/1024) 倍,縦方向に 0.9375(=480/512) 倍した値を指定する.
2 動画の取り扱い
12
void glTexCoord{1,2,3,4}{s,i,d,f}(TYPE coords);
void glTexCoord{1,2,3,4}{s,i,d,f}v(TYPE *coords);
図 3 ポリゴンへの動画テクスチャマッピング
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
...
glColor3f(1.0, 1.0, 1.0);
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, tex_index );
glPushMatrix();
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(0.0, 0.0);
glVertex3f(-cap_width/2, -cap_height/2, 0.0);
glTexCoord2f((float)cap_width/tex_width, 0.0);
glVertex3f(cap_width/2, -cap_height/2, 0.0);
glTexCoord2f((float)cap_width/tex_width,
(float)cap_height/tex_height);
glVertex3f(cap_width/2, cap_height/2, 0.0);
glTexCoord2f(0.0, (float)cap_height/tex_height);
glVertex3f(-cap_width/2, cap_height/2, 0.0);
glEnd();
glPopMatrix();
}
2.3 カメラ画像のテクスチャマッピング
13
テクスチャマッピングを 3 次元コンピュータグラフィックス上に行うことで,動画を単純なポリゴンにマッ
ピング (図 2) するだけではなく,複雑な 3 次元局面にもマッピング (図 4) することができる.それぞれの表
面上のテクスチャはカメラを接続しているので,リアルタイムに動画が変化する.
◇ 課題 1 ◇
1. 解凍された opencv-sample ディレクトリ内のプログラムをコンパイルせよ.また USB カメ
ラを接続した後実行し,カメラ画像が表示されるか確認せよ.また,v4l2-sample 内のプロ
グラムと比較してみよう.
2. opencv-texture ディレクトリ内のプログラムを同様に実行し,図 2 と同じ実行結果がえられ
ることを確認せよ.
3. opencv-divtex ディレクトリ内のプログラムで,TODO を埋めて課題 2.2 と同じ結果がえら
れることを確認せよ.
4. さらに,図 4 に示すように,複雑な面にカメラからの画像がテクスチャマッピングされるよ
うに変更せよ.
5. opencv-dynamic ディレクトリ内のプログラムを,時間経過に合わせてポリゴンが動的に変
化するようにせよ.(オプション)
図4
動画:3 次元の複雑な面へのテクスチャマッピング
14
3 Augmented Reality
3 Augmented Reality
3.1 Augmented Reality とは
現実環境と VR 環境をシームレスに融合させ,現実環境の情報の豊かさと VR 環境の柔軟性を兼ね備えた強
化された環境を実時間に提供する,拡張現実感 (AR: AugmentedReality),あるいは複合現実感 (MR: Mixed
Reality) と呼ばれる技術が注目されている.これはヘッドマウントディスプレイ (HMD: Head Mounted
Display) などを用いて実世界の画像と VR 物体を合成表示することにより,あたかも現実世界に仮想物体が
そのまま出現したかのように見せる技術である.
CG 画像と実写画像の合成方法によって次の 2 つのタイプに分けられる.
• 光学シースルー (Optical See-Through) 方式
• ビデオシースルー (Video See-Through) 方式
それぞれの原理と特徴を述べると,前者は現実空間をハーフミラーで直接見て,VR 空間と重ね合わせる方
式であり,実時間で安定して動作するという特徴がある.VR 物体による現実物体の遮蔽が困難であり,ハー
フミラーを用いるために現実環境が若干暗く見え,VR 物体が半透明に見えるなどの短所がある.一方後者
は,現実空間をビデオカメラで撮影して VR 空間と合成したあとにディスプレイに表示するものである.実写
画像を一旦コンピュータに取り込んでから合成処理を施すため,シームレスな重ねあわせには有利である.し
かし,処理の遅延により,船酔いや宇宙酔いのような VR 酔いを起こしやすい.
図5
光学シースルー (Optical See-Through) 方式における HMD
図6
ビデオシースルー (Video See-Through) 方式
15
4 ARToolKit とは
ARToolKit とは,これまで OpenCV や OpenGL で実現してきた拡張現実感(AR:Augmented Reality)
の実現を容易にするためのライブラリ群である.ARToolKit はワシントン大学の HITL(Human Interface
Technology Lab)により開発され,現在までに非常に多くの拡張現実感プロジェクトにおいて利用されてい
る.ARToolKit Home Page (http://www.hitl.washington.edu/artoolkit/) よりダウンロードすることがで
きる.
通常、AR アプリケーションを構築するには,画像解析の演習などで行った通り,カメラ等で現実世界を取
り込んだ映像の解析,カメラや対象ビジュアルマーカの位置情報の解析,コンピュータグラフィックの生成及
び合成といった非常に複雑な処理が必要になる.ARToolKit を利用することによりこれらのビジュアルマー
カの検出アルゴリズムやカメラ位置の計算アルゴリズムグラフィックの生成等を行ってくれるため,開発者は
ビジュアルマーカ内の固有パターンの定義やグラフィックの動作等を定義することにより拡張現実感を実現す
ることが出来る.
ARToolKit は現在 SGI IRIX, PC リナックス,Mac OS X,および PC Windows(95/98/NT/2000/XP)
のオペレーティングシステムで動作する.ARToolKit の最新バージョンはマルチプラットフォームであり,
ツールキットのそれぞれのバージョンの機能性は同じである.(図) ARToolkit のビデオキャプチャモジュー
ルは,内部で OS に応じたインタフェースを使うようになっている.画像の描画が 3DCG における視点の設
定 (グラフィック処理) には,OpenGL と GLUT を用いている.
図 7 ARToolKit のアーキテクチャ
4.1 ARToolKit の概要
ARToolKit を使用するアプリケーションの開発は,アプリケーションを記述する部分と,アプリケーショ
ンで使用される実際のマーカー上の画像処理のトレーニング部に分かれる.
アプリケーションの主な構成は以下の方法を取る.
ステップ 1 と 6 はアプリケーションの初期化と閉鎖に実行され,ステップ 2∼5 はアプリケーションが終了
するまでずっと繰り返される.これらのステップに加え,アプリケーションはマウス、キーボードまたは他の
アプリケーションに特定のイベントの処理も行う.
4 ARToolKit とは
16
初期設定
1. ビデオキャプチャを初期化.
マーカーパターンとカメラパラメタの読み込み.
メインループ
2. ビデオ入力画像の取得.
3. ビデオ入力画像にマーカーと認識されたパターンの検出.
4. 検出されたパターンに比例してカメラパラメータを算出.
5. 検出されたパターンに VR オブジェクトの描画.
終了
6. ビデオキャプチャの終了
表 3 ARToolKit の処理ステップ
4.2 ARToolKit のプログラム例
まずは,簡単な ARToolKit アプリケーションのソースコード (simpleTest(simple.c)) を通して,プログラ
ムの書き方を説明する.
図 8 simpleTest の実行例
ARToolKit Step
Functions
1. Initialize the application
init
2. Grab a video input frame
arVideoGetImage (called in mainLoop)
3. Detect the markers
arDetectMarker (called in mainLoop)
4. Calculate camera transformation
arGetTransMat (called in mainLoop)
5. Draw the virtual objects
draw (called in mainLoop)
6. Close the video capture down
cleanup
表 4 ARToolKit の処理ステップと命令
プログラムの重要な部分は,main, init, mainLoop, draw, cleanup の 5 つになる.
4.2 ARToolKit のプログラム例
17
main 関数 main()
main 関数では,主に初期化処理とメインループの起動を行う. argMainLoop() によってメインループが
起動される.
main(int argc, char *argv[])
{
init();
arVideoCapStart();
argMainLoop( NULL, keyEvent, mainLoop );
}
初期化ルーチンはマーカーとカメラパラメタを読み込み、ビデオキャプチャを始めるためのコード,および
ウィンドウのセットアップを含んでいる.ステップ 1 に対応.次に、ビデオへの呼び出しで,arVideoCapStart
呼び,リアルタイムキャプチャが開始する.続いて,argMainLoop は,レンダリングを行う rendering loop
を伴う main program loop を始動する.
初期化 init()
初期化ルーチンは,main からコールされ,ビデオキャプチャの初期化,ARToolKit のアプリケーションパ
ラメータの読み込みを行う.ARToolKit アプリケーションのための主要なパラメタは以下の通り.
• ビデオデバイスの設定 (設定が記録された XML ファイルの読み込み)
• カメラパラメータファイルの読み込み.デフォルト:Data/camera para.dat).
• パターンテンプレート照合に使用されるパターンの読み込み
• ウィンドウの作成
まず,ビデオデバイスを開き,ウインドウサイズの取得を行う.
/* 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);
カメラパラメータのロード.カメラパラメータは現在の画像サイズに応じて変更する.
4 ARToolKit とは
18
/* set the initial camera parameters */
if( arParamLoad(cparaname, 1, &wparam) < 0 ) {
printf("Camera parameter load error !!\n");
exit(0);
}
arParamChangeSize( &wparam, xsize, ysize, &cparam );
カメラパラメータの設定と表示.
arInitCparam( &cparam );
arParamDisp( &cparam );
パターンの定義を読み込む.(デフォルト:Data/patt.hiro)
if( (patt_id=arLoadPatt(patt_name)) < 0 ) {
printf("pattern load error !!\n");
exit(0);
}
patt id は特定されたパターンの ID.
/* open the graphics window */
argInit( &cparam, 1.0, 0, 0, 0, 0 );
最後に,ウィンドウを開く.2 つめのパラメータは,ズームの比率.
メインループ mailLoop()
表 3 のステップ 2-5 に対応する.まず,ビデオ画像は arVideoGetImage を使用することでキャプチャする.
/* grab a video frame */
if( (dataPtr = (ARUint8 *)arVideoGetImage()) == NULL ) {
arUtilSleep(2);
return;
}
画面上にビデオ画像を表示.
4.2 ARToolKit のプログラム例
19
argDrawMode2D();
argDispImage( dataPtr, 0,0 );
arDetectMarker はビデオ画像から正しいマーカパターンを持つ正方形を検出する.
発見されたマーカの数は,marker num に含まれる.marker info にはマーカの座標情報は,認識時の信頼
度,ID が含まれる構造体のポインタが入る.marker info[j].id はj番目に検出されたマーカに対するマーカ
ID,marker info[j].cf はどれだけ近いかを示す一致度 (0.0∼1.0) が格納される.
if( arDetectMarker(dataPtr, thresh, &marker_info, &marker_num) < 0 ) {
cleanup();
exit(0);
});
次のカメラ画像を取得.
arVideoCapNext();
検出されたマーカのすべての信頼度を比較し,どの ID と相関が高いか調べる.どのパターンも見つからな
かった場合 (k==-1),SwapBuffers のみ.
/* 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 ) {
argSwapBuffers();
return;
}
arGetTransMat により,マーカーとカメラの間の Transformation を求める.マーカ i に対応したカメラ
位置と方向が 3x4 マトリクス patt trans に含まれる.
4 ARToolKit とは
20
/* get the transformation between the marker and the real camera */
arGetTransMat(&marker_info[k], patt_center, patt_width, patt_trans);
ここで,draw 関数が呼ばれ,実際の 3D オブジェクトの描画を行う.
draw();
argSwapBuffers();
描画処理 draw()
draw 関数では,レンダリングの初期化, マトリックスのセットアップ, 物体のレンダリングに分かれる.
ARToolKit に問い合わせを行い 3D レンダリングの初期化を行う.argDrawMode3D() 関数で OpenGL のモ
デルビュー行列を初期化し, argDraw3dCamera() 関数で 3D 空間の視野範囲を設定する.
argDrawMode3D();
argDraw3dCamera( 0, 0 );
glClearDepth( 1.0 );
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
argConvGlpara により,ARToolKit で算出された 3x4 行列を,OpenGL 形式 (4x4 行列) に変換する.こ
の値は,実際のカメラの位置と方向を表し,OpenGL のカメラ位置に設定することで,マーカー上にオブジェ
クトをレンダリングすることができる.
/* load the camera transformation matrix */
argConvGlpara(patt_trans, gl_para);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd( gl_para );
OpenGL の関数によりオブジェクトの描画.この場合,白色光の下の青い立方体を描画.原点から 25.0mm
浮かしてあることに注意すること.
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);
4.2 ARToolKit のプログラム例
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);
OpenGL パラメータをデフォルトに戻す.
glDisable( GL_LIGHTING );
glDisable( GL_DEPTH_TEST );
終了処理 cleanup()
cleenup では,他のアプリケーションのため,ビデオプロセッシングを終了し video path を閉じる.
arVideoCapStop();
arVideoClose();
argCleanup();
21
4 ARToolKit とは
22
4.3 ARToolKit と OpenGL の座標変換
ARToolKit では,検出されたマーカの情報から,カメラ視点に対するマーカの 3 次元位置姿勢を計算し,
その情報に基づいてキャプチャした画像上に OpenGL で描画を行っている.
4x4 変換行列 gl_para[16]
Zm
Ym
Zc
Xc
Yc
カメラ座標系
マーカ座標系
Xm
図 9 ARToolKit における座標変換
arGetTransMat() 関数を実行すると,回転成分と並進成分を含む座標変換行列 patt trans(3x4 行列) が得
られる. ただし,この行列は ARToolKit 上での記述になっているので,OpenGL において 3 次元物体の描
画位置を検出するには,OpenGL の座標系に変換する必要がある.

r11
patt trans = r21
r31
r12
r22
r32
r13
r23
r33

t1
t2 
t3
(1)
argConvGlpara() 関数でこの変換を行い,OpenGL 形式の座標変換行列 gl para(4x4 行列)が得られる.
argConvGlpara(patt_trans, gl_para);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd( gl_para );

r11
r21

gl para = 
r31
0
r12
r22
r32
0
r13
r23
r33
0

t1
t2 

t3 
(2)
1
OpenGL においても原点はカメラの位置にあるが,この変換行列をモデルビュー行列として読み込むこと
により,マーカ中心を原点とした座標系になる.原点にオブジェクトを描画すれば,マーカ上に指定したオブ
ジェクトがレンダリングされることになる.
double patt_width = 80.0
また,OpenGL のオブジェクトと実空間との対応付けを行う必要がある.上記ではマーカの一辺の長さを
mm 単位で指定しており,実際に印刷したマーカのサイズと一致させることで,CG オブジェクトのサイズも
mm 単位で正確に配置することが可能になる.一辺 50mm の立方体を配置したければ glutSolidCube(50.0)
とすればよい.
4.4 ARToolKit のインストール
23
4.4 ARToolKit のインストール
演習用のノートには,ARToolKit がインストールされていない.Linux 上でコンパイルが通るようにパッ
チを当てた ARToolKit が演習のページにおいてあるので,ダウンロードしてコンパイルすること.解凍した
後,make することでライブラリやサンプルプログラムがコンパイルされる.
$ cd ARToolkit
$ make
ライブラリは,(解凍先ディレクトリ)/ARToolkit/lib に,サンプルプログラムは,(解凍先ディレクト
リ)/ARToolkit/bin にある.
◇ 課題 2 ◇
1. sampleTest.c をコンパイルし,カメラ画像が表示されること確認せよ.また,Hiro と書いて
あるパターンにオブジェクトが重ねられることを確認せよ.
2. 表示されているオブジェクトを変更してみよ.可能であればテクスチャを貼ってみるのも
よい.
3. 表示されているオブジェクトをアニメーションさせよ.上下移動や回転でよい.
4. (オプション) 複数のパターンが認識され,それぞれ別のオブジェクトが表示できるよう
に せ よ .http://www.hitl.washington.edu/artoolkit/documentation/devmulti.htm を 参
考にせよ.
図 10
参考課題 実行時の画面
図 11 参考課題 実行時の画面
24
メモ
4 ARToolKit とは