1
平成 26年度 機械情報工学科演習
コンピュータグラフィクス (2)
動画やカメラを用いた 3DCGの応用
担当:谷川 智洋 講師,鳴海 拓志 助教,中垣 好之 技官
TA: 岡田 直弥,川瀬 佑司
2014年 10月 17日
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 カメラは,「リアルワールド認識」(2014/11/10(月),11(火),13(木))「メディアインタフェース」
(2012/11/17(月), 18(火))でも使用するので,忘れずに持参すること.
また,「ロボットシミュレーション」において貸出を行う BluetoothのUSBアダプタは,「メディアイン
タフェース (2)」(2012/11/18(火))で使用するので,忘れずに持参すること.
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 51204 0
compat_ioctl32 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を指定する.
4 2 動画の取り扱い
� �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.� �
6 2 動画の取り扱い
同様に,関数 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>
8 2 動画の取り扱い
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);� �
10 2 動画の取り扱い
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)倍した値を指定する.
12 2 動画の取り扱い
� �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はアプリケーションが終了
するまでずっと繰り返される.これらのステップに加え,アプリケーションはマウス、キーボードまたは他の
アプリケーションに特定のイベントの処理も行う.
16 4 ARToolKitとは
初期設定 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);
カメラパラメータのロード.カメラパラメータは現在の画像サイズに応じて変更する.
18 4 ARToolKitとは
/* 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()関数により,マーカーとカメラの間の座標変換行列を求める.マーカ iに対応したカメ
ラ位置と方向が 3x4マトリクス patt transに含まれる.
20 4 ARToolKitとは
/* 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のプログラム例 21
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();
22 4 ARToolKitとは
4.3 ARToolKitと OpenGLの座標変換
ARToolKit では,検出されたマーカの情報から,カメラ視点に対するマーカの 3 次元位置姿勢を計算し,
その情報に基づいてキャプチャした画像上に OpenGLで描画を行っている.
XcZc
Yc Xm
Ym
Zm
カメラ座標系 マーカ座標系
4x4 変換行列 gl_para[16]
図 9 ARToolKitにおける座標変換
arGetTransMat()関数を実行すると,回転成分と並進成分を含む座標変換行列 patt trans(3x4行列)が得
られる. r11~r33 が回転成分,tx, ty, tz が並進成分となっている.ただし,この行列は ARToolKit上での記
述になっているので,OpenGLにおいて 3次元物体の描画位置を検出するには,OpenGLの座標系に変換す
る必要がある.
patt trans =
r11 r12 r13 txr21 r22 r23 tyr31 r32 r33 tz
(1)
argConvGlpara()関数でこの変換を行い,OpenGL形式の座標変換行列 gl para(4x4行列)が得られる.
argConvGlpara(patt_trans, gl_para);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd( gl_para );
gl para =
r11 r12 r13 txr21 r22 r23 tyr31 r32 r33 tz0 0 0 1
(2)
OpenGLにおいても原点はカメラの位置にあるが,この変換行列をモデルビュー行列として読み込むこと
により,マーカ中心を原点とした座標系になる.原点にオブジェクトを描画すれば,マーカ上に指定したオブ
ジェクトがレンダリングされることになる.Xc
Yc
Zc
1
=
r11 r12 r13 txr21 r22 r23 tyr31 r32 r33 tz0 0 0 1
Xm
Ym
Zm
1
(3)
また,ARにおいては,OpenGLのオブジェクトと実空間とのスケールの対応付けを行う必要がある.
4.4 ARToolKitのインストール 23
double patt_width = 80.0
上記ではマーカの一辺の長さを mm単位で指定しており,実際に印刷したマーカのサイズと一致させるこ
とで,CGオブジェクトのサイズも mm単位で正確に配置することが可能になる.一辺 50mmの立方体を配
置したければ glutSolidCube(50.0)とすればよい.
glMatrixMode(GL_MODELVIEW);
glTranslatef( 0.0, 0.0, 25.0 );
glutSolidCube(50.0);
4.4 ARToolKitのインストール
演習用のノートには,ARToolKitがインストールされていない.Linux上でコンパイルが通るようにパッ
チを当てた ARToolKit が演習のページにあるので,ダウンロードしてコンパイルすること.手順は以下の
通り.� �$ cd ARToolkit
$ ./Configure� �Configureの質問に対し,1つめの質問は”3”,2つめの質問以降,すべて”n”と答えること.終了後,make
することでライブラリやサンプルプログラムがコンパイルされる.� �$ make� �
ライブラリは (解凍先ディレクトリ)/ARToolkit/lib に,サンプルの実行プログラムは (解凍先ディレクト
リ)/ARToolkit/bin,サンプルのソースコードは (解凍先ディレクトリ)/ARToolkit/examplesにある.実行
ファイルを実行する際は,必ず binディレクトリの移動してから実行すること.
24 4 ARToolKitとは
◇ 課題 2 ◇� �1. sampleLite.cをコンパイルし,カメラ画像が表示されること確認せよ.また,Hiroと書いて
あるパターンにオブジェクトが重ねられることを確認せよ.なお,マーカが曲がっていると
認識できないので,マーカを机に置いてカメラを動かすとよい.
2. 表示されているオブジェクトを変更してみよ.テクスチャを貼ってみるのもよい.
3. 表示されているオブジェクトをアニメーションさせよ.上下移動や回転でよい.
4. (オプション) 複数のパターンが認識され,それぞれ別のオブジェクトが表示できるようにせ
よ.(参考:http://www.hitl.washington.edu/artoolkit/documentation/devmulti.htm)
� �
図 10 参考課題 実行時の画面例 図 11 参考課題 実行時の画面例