インタフェースデバイスと nuitani/class/mech_enshu/enshu...1 機械情報工学科演習...

26
1 機械情報工学科 演習 メディアインタフェース(2) インタフェースデバイスと NUI の基礎 担当:谷川智洋,鳴海拓志,中垣好之 TA: 榊原佑太,鈴木啓太 2015 11 10 1 演習の目的 本日の演習では,「コンピュータグラフィックス」で学習した OpenGL の基礎,画像の表示,テクスチャ マッピングを元に,三次元コンピュータグラフィックスとのインタラクションについて学ぶ.一つは,インタ フェースデバイスの一種である Wii リモコンを用いて,三次元グラフィックスとのインタラクション手法を 学習する.Wii リモコンは,リモコンを操作する人間の手の動きやボタン入力などを取り込むことが可能で あり,計算機の世界と実世界をつなぐインタフェースになる.本演習ではボタンを押すことや腕ふりなどの 動作と OpenGL 内での動作を連携させるインタラクション手法を学習する.もう一つは,別の種類のインタ フェースデバイスである Kinect を用いて,奥行きを表現するデプス画像や,それに基づいて人間の位置や姿 勢を判別し,それらの情報を元に三次元グラフィックスとインタラクションする手法について学習する. 1.1 資料など 本日の演習の資料などは, http://www.cyber.t.u-tokyo.ac.jp/~tani/class/mech_enshu/ においてある. 本日使用するソースファイルも同じ場所からダウンロードすること.「イメージプロセッシング」「コン ピュータグラフィックス」や前回の「メディアインタフェース」の資料を参照したい場合も同じ場所を参照の こと.参考となる URL もリンクが貼ってあるため,参照のこと.ネットワークにつながらない者は,教員に USB メモリを借りてデータをコピーすること.

Upload: others

Post on 21-Feb-2020

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

1

機械情報工学科 演習

メディアインタフェース(2)

インタフェースデバイスと NUIの基礎

担当:谷川智洋,鳴海拓志,中垣好之

TA: 榊原佑太,鈴木啓太

2015年 11月 10日

1 演習の目的

本日の演習では,「コンピュータグラフィックス」で学習した OpenGL の基礎,画像の表示,テクスチャ

マッピングを元に,三次元コンピュータグラフィックスとのインタラクションについて学ぶ.一つは,インタ

フェースデバイスの一種であるWiiリモコンを用いて,三次元グラフィックスとのインタラクション手法を

学習する.Wii リモコンは,リモコンを操作する人間の手の動きやボタン入力などを取り込むことが可能で

あり,計算機の世界と実世界をつなぐインタフェースになる.本演習ではボタンを押すことや腕ふりなどの

動作と OpenGL内での動作を連携させるインタラクション手法を学習する.もう一つは,別の種類のインタ

フェースデバイスである Kinectを用いて,奥行きを表現するデプス画像や,それに基づいて人間の位置や姿

勢を判別し,それらの情報を元に三次元グラフィックスとインタラクションする手法について学習する.

1.1 資料など

本日の演習の資料などは,� �http://www.cyber.t.u-tokyo.ac.jp/~tani/class/mech_enshu/� �

においてある.

本日使用するソースファイルも同じ場所からダウンロードすること.「イメージプロセッシング」「コン

ピュータグラフィックス」や前回の「メディアインタフェース」の資料を参照したい場合も同じ場所を参照の

こと.参考となる URLもリンクが貼ってあるため,参照のこと.ネットワークにつながらない者は,教員に

USBメモリを借りてデータをコピーすること.

Page 2: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

2 2 貸し出し物および動作確認

1.2 出席・課題の確認について

出席の確認は,課題の確認およびレポートの提出によって行う.課題が終了したら,教員・TAを呼び,指

示に従って実行して説明せよ.

課題が全て終了したらメール課題に取り組み,「メール課題」を [email protected] 宛てに

メールせよ.件名は「20151110MI-abcdefgh」とせよ.ただし abcdefghは学籍番号(半角の数字列)に置き

換えよ.なお,本文中には氏名と学籍番号を含めること.適切な件名でないものは未提出扱いになる可能性が

あるので要注意.メール提出後は退室してよい.演習時間終了後(16 時 15 分以降)は,課題が全て終了せず

とも退室は自由である.メール課題は来週 (11/17 23:59)までに提出のこと.

1.3 貸し出し物の返却について

課題が全て終了後,帰宅前に,貸し出しているWiiリモコン,電池,Bluetoothアダプタ,Kinectを TA

まで返却せよ.USBカメラについては各自保管し,自主プロ終了時に返却のこと.不具合があったりした場

合は,来年も使うために,不具合の内容を返却時に報告すること.

2 貸し出し物および動作確認

2.1 Wiiリモコンと電池

Wiiリモコンは 1人に 1台,電池は 1人に 2本を貸し出す.なくさないように.来年度以降も貸し出しを

するので大切に取り扱いをする.不具合があったりした場合は,交換を行うが,来年も使うため不具合の内容

を報告すること.

2.2 Wiiリモコンの動作確認

本演習では,Linux 用に C で書かれた Wii リモコン(Wiimote) 用のライブラリである CWiid

(http://abstrakraft.org/cwiid/)を使用する.まず,CWiid の動作確認として,下記を実行する.下記の

00:00:00:00:00:00には,Wiiリモコンにかかれている Bluetoothのアドレスを入力する.� �$ wmgui 00:00:00:00:00:00� �

wmguiの画面が立ち上がったら,「File」→「Connect」する (図 1).図 2のようなダイアログが出てくる

ので,Wiiリモコンの 1ボタンと 2ボタンを同時に押して LEDが点滅するのを確認し,OKボタンを押す.

Connectしたら,「Settings」→「Acc Data」にチェックをする.Wiiリモコンを動かしてデータが動いて

いるのを見ることができたら,動作確認終了.

2.3 CWiidのインストール

今回の演習で使用するWiiリモコン (Wiimote)の開発用ライブラリのインストールを行う (図 4).下記の

手順でインストールすること.

Page 3: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

2.3 CWiidのインストール 3

図 1 Connect画面

図 2 Connectのダイアログウィンドウ

1. 左のパネルから,Ubuntuソフトウェアセンターを起動する.

2. ソフトウェア検索ボックスを使って,”libcwiid”を検索する.

3. インストールボタンを押し,libcwiid-devをインストールする.

パスワードを聞かれるので,適宜自分の設定したパスワードを入力する.インストール終了後,上図のよ

うにアイコンに緑のチェックが付いていることを確認する.環境によっては libbluetooth-dev を別途インス

トール必要があるが,その場合は上記と同様にしてインストールすること.

それでもエラーが出てインストールできない場合は,下記のコマンドを打ち込んで試してみるとよい.� �$ sudo apt-get install libbluetooth-dev

$ sudo apt-get install libcwiid-dev� �

Page 4: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

4 3 三次元コンピュータグラフィックスとインタラクション

図 3 設定画面

図 4 Ubuntuソフトウェアセンターによる CWiidのインストール

3 三次元コンピュータグラフィックスとインタラクション

三次元コンピュータグラフィックスを操作するには,キーボード,マウスその他のインタフェースを用い

る.本演習では,身体の動きも取得することができるWiiリモコンを用いたインタラクション手法の基礎につ

いて学習する.任天堂Wiiは家庭用ゲーム機であり,従来型のボタンや矢印キーに加え,体を動かしたり,腕

を振ったり,という身体的動作まで含めたインタフェースを提供している.また,特徴としては,Bluetooth

Page 5: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

3.1 Wiiリモコン 5

を用いた無線での操作が可能であり,Wiiリモコンにケーブルがついておらず,空中での自由な操作が可能と

なっている点も特徴である.

3.1 Wiiリモコン

Wiiのインタフェースとしては,従来型のクラシックコントローラ,Wiiリモコン,Wiiリモコンに接続す

るヌンチャク,Wii Fitなどが発売されている.その中でもWiiリモコンは,簡単な操作,直感的な操作を目

指して開発されており,誰でも容易に使えるインタフェースの一つである.

Wii リモコンには,3 軸加速度センサ,スピーカ,スピーカ用アンプ,電源コントロール IC,サウンドデ

コーダ,Bluetooth 用 IC,振動モータ,ポインタ用 CMOS カメラ,似顔絵データ用メモリが搭載されてい

る.特に,Bluetoothが搭載されていることにより無線での利用が可能であり,3軸リニア加速度センサを搭

載していることによって,腕を振る動作や傾ける動作などを検出することが可能である.

図 5 Wiiリモコン(http://www.nintendo.co.jp/wii/features/wii remote.html)

3.2 CWiid

CWiid(http://abstrakraft.org/cwiid/)は,Linux用に Cで書かれたWiiリモコン(Wiimote)用のツー

ルであり,イベントの APIなどが含まれている.Wiiリモコンの APIやWiimoteライブラリ,GTKをベー

スにした GUIインタフェースなどが含まれている.なお,CWiidでは対応しているが,センサーバーなどが

ないため,今回の演習ではポインタ用 CMOSカメラやヌンチャクなどは用いずに行う.また,スピーカ部分

も用いない.ボタンや加速度,振動を用いることとする.

Wiiリモコンの接続と切断

Wiiリモコンを接続するには,cwiid open()関数を用いる.

bdaddrには,bluetoothのアドレスが入る.BDADDR ANYを指定した場合には,利用可能な任意の (1

台)Wiiリモコンと接続される.Wiiリモコンに接続が成功した場合,返り値として cwiid wiimote handleが

返る.

Page 6: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

6 3 三次元コンピュータグラフィックスとインタラクション

� �cwiid_wiimote_t *cwiid_open(bdaddr_t *bdaddr, int flags);� �

また,接続した Wii リモコンとコールバック関数との対応付けは,cwiid set mesg callback() 関数を用

いる.� �typedef void cwiid_mesg_callback_t(cwiid_wiimote_t *, int, union cwiid_mesg []);

int cwiid_set_mesg_callback(cwiid_wiimote_t *wiimote, cwiid_mesg_callback_t *callback);� �よって,Wiiリモコンの接続とコールバック関数の対応付けを行った例は下記のようになる.

if ((wiimote = cwiid_open(&bdaddr, CWIID_FLAG_MESG_IFC)) == NULL) {

printf("Unable to connect\n");

}

else {

if (cwiid_set_mesg_callback(wiimote, &wiimote_callback)) {

printf("Unable to set message callback\n");

}

     ....

}

なお,切断するときは,cwiid close()関数を用いる.接続のときに得られた cwiid wiimote handleを引数

に取る.� �int cwiid_close(cwiid_wiimote_t *wiimote);� �

if(cwiid_close(wiimote)){

fprintf(stderr,"Error on wiimote disconnect\n");

exit(-1);

}

Wiiリモコンからのコールバック

Wii リモコンからのコールバックとしては,union cwiid mesg mesg array[] に入っている.

mesg array.type を用いて加速度とボタンの情報を識別する.acc zero, acc one は zero point と 1G

pointの初期値である.

Page 7: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

3.2 CWiid 7

void wiimote_callback(cwiid_wiimote_t *wiimote, int mesg_count,

union cwiid_mesg mesg_array[], struct timespec *timestamp)

{

int i;

for (i=0; i < mesg_count; i++) {

switch (mesg_array[i].type) {

case CWIID_MESG_ACC:

wiimote_acc(&mesg_array[i].acc_mesg);

break;

case CWIID_MESG_BTN:

wiimote_btn(&mesg_array[i].btn_mesg);

break;

default:

break;

}

}

}

コマンドの送信

Wiiリモコンへのコマンドを送信するには,cwiid command()関数を用いる.

stateが 1で ON,0で OFFになる.

commandでは, CWIID CMD RUMBLEが振動,CWIID CMD LEDが LEDである.� �cwiid_command(wiimote, command, int state);� �

下記のようにして,任意の LEDの消灯や振動の ON/OFFが可能になる.

//vibration ON

cwiid_command(wiimote, CWIID_CMD_RUMBLE, 1);

//vibration OFF

cwiid_command(wiimote, CWIID_CMD_RUMBLE, 0);

//LED 1 ON

cwiid_command(wiimote, CWIID_CMD_LED, 1);

//LED 1 OFF

cwiid_command(wiimote, CWIID_CMD_LED, 0);

どのようにWiiリモコンからデータを返してもらうか設定するには,下記の様に書く.

Page 8: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

8 3 三次元コンピュータグラフィックスとインタラクション

void set_report_mode(void)

{

uint8_t rpt_mode;

rpt_mode = CWIID_RPT_STATUS | CWIID_RPT_BTN;

rpt_mode |= CWIID_RPT_ACC;

cwiid_command(wiimote, CWIID_CMD_RPT_MODE, rpt_mode);

}

加速度とボタン

Wii リモコンからの傾きなどの値としては,mesg-¿acc[CWIID X], mesg-¿acc[CWIID X], mesg-

¿acc[CWIID X] に格納されているが,初期値との差をとることによって,加速度を計算することがで

きる.

void wiimote_acc(struct cwiid_acc_mesg *mesg)

{

printf("x: %d, y: %d, z: %d\t", mesg->x, mesg->y, mesg->z);

double a_x, a_y, a_z;

a_x = ((double)mesg->acc[CWIID_X] - acc_zero.x) /

(acc_one.x - acc_zero.x);

a_y = ((double)mesg->acc[CWIID_Y] - acc_zero.y) /

(acc_one.y - acc_zero.y);

a_z = ((double)mesg->acc[CWIID_Z] - acc_zero.z) /

(acc_one.z - acc_zero.z);

}

Wiiリモコンからのボタンの値は,下記の手法で取得できる.

void wiimote_btn(struct cwiid_btn_mesg *mesg){

if(mesg->buttons & CWIID_BTN_UP){

    ...

}

ボタンは,下記の引数で取得できる.

Page 9: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

3.2 CWiid 9

CWIID BTN UP 十字キーの上ボタン

CWIID BTN DOWN 十字キーの下ボタン

CWIID BTN RIGHT 十字キーの右ボタン

CWIID BTN LEFT 十字キーの左ボタン

CWIID BTN PLUS +ボタン

CWIID BTN MINUS -ボタン

CWIID BTN A Aボタン

CWIID BTN B Bボタン

CWIID BTN HOME HOMEボタン

CWIID BTN 1 1ボタン

CWIID BTN 2 2ボタン

Wiiリモコンの軸

Wiiリモコンの軸は下記の通りである.

図 6 Wiiリモコンの軸(http://wiibrew.org/images/9/9e/Wiimote axis2.png)

Yaw, Pitch, Roll

参考までに,Yaw, Pitch, Rollについて図 7に示す.クォータニオン(四元数)を用いることで簡単に計算

できるようになるが,今回は省略する.

図 7 Yaw,Pitch,Roll(http://sorceryforce.com/programing/mdx/direct3d/stepup/quaternion.html)

Page 10: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

10 3 三次元コンピュータグラフィックスとインタラクション

CWiidを用いたサンプルプログラム

CWiidライブラリを使用するMakefileの例は下記の通りである.

CC = g++

COMMON = .

RM = rm -f

TARGET = sample

OBJS = sample.o

CFLAGS = -Wall -fpermissive

LDFLAGS =

LDLIBS = -lglut -lGL -lGLU -lcwiid -lrt -lbluetooth -lpthread

.c.o:

${CC} -c ${CFLAGS} $<

${TARGET}: ${OBJS}

${CC} -o ${TARGET} ${OBJS} ${LDLIBS} ${LDFLAGS}

clean:

${RM} ${TARGET} *.o *~

Page 11: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

3.2 CWiid 11

◇ 課題 1 ◇� �1. kadai1-1 のフォルダに入っている sample.c をコンパイルし,実行せよ.実行方法は Blue-

toothのアドレス 00:00:00:00:00:00を引数にとり,実行する.Bluetoothのアドレスは貸し

出したWiiリモコンに書かれている.

例: ./sample 00:00:00:00:00:00

(a)Wiiリモコンを傾けると,赤いボールが移動することを確認せよ.また,十字キー,+

ボタン,-ボタンで赤いボールが動くことを確認せよ.また,Aボタン,Bボタンなど

でボールの色が変化することを確認せよ.

(b)キーボードの「1」と「!」,「2」と「”」を押して,Wiiリモコンの LEDの 1番,2番が光

る,消えることを確認せよ.また「r」と「R]を押して,Wiiリモコンの振動が始まる・

止まることを確認せよ.

(c)ボタンを押すことによって,表示されているWireCubeの回転がスタート,ストップで

きるようにせよ.

2. kadai1-2のフォルダに入っている sample.cをコンパイルし,Wiiリモコンを傾けることで,

それに応じて Teapotが傾くことを確認せよ.

(a)十字キーを用いて大きさを変更できるようにせよ.

(b)Bボタンを押すと,つかめて動かせるようにせよ.

(c)移動平均などをとることにより,動きを安定化させよ(オプション).

3. kadai1-3のフォルダに入っている sample.cをコンパイルし,Wiiリモコンを振ることによっ

て球の動く方向が変化することを確認せよ. disp flagによって,左向き,右向き,静止の状

態が変化する.ホームボタンを押すと位置がリセットされる.

(a)加速度のパラメータを変化させ,手の動きに敏感あるいは鈍感に変更させてみよ.

(b)壁面を書いて,ぶつかったら反対向きに動くように変更せよ.壁をある位置に設定し,

そこに来たら反対方向に動くようにさせる.これができると,壁にあたって帰ってきた

球を,Wiiリモコンを振ることによって打ち返せる感じになる.

(c)ぶつかった際に振動が起きるようにせよ.

(d)余裕があったら,壁あてゲームのように,球の速さが変わりながら,壁に当たって,戻っ

てきたら打ち返すようにせよ.(オプション).

� �

Page 12: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

12 3 三次元コンピュータグラフィックスとインタラクション

図 8 球がWiiリモコンの傾きにより動く例

図 9 TeapotがWiiリモコンの向きにより動く例

図 10 Wiiリモコンを大きく振るとボールの動く向きが変更になる例

Page 13: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

13

4 インタフェースとしてのカメラ・Wiiリモコン

前回の演習で学習したように,カメラの三次元位置をチェスボードとの相対関係で知ることができる.応用

方法としての一つは上述したカメラの三次元位置を計算機内に描画することである.もう一つの方法として

は,実世界でチェスボードの周囲でカメラを動かし,そのカメラの動きに合わせて,計算機の世界を変化させ

る.つまり,あたかもチェスボードに物が乗っているかのように動かすことで,視点を動かし,見回す映像を

作ることができる.カメラを固定して,チェスボードを動かすことによっても同じような映像を作ることがで

きる.今回は,OpenGLの世界の中の映像を見回すために,カメラをインタフェースとして利用する.また,

同時に,Wiiリモコンを利用し,Wiiリモコンの動きに合わせて描画オブジェクトを変化させる.

図 11 カメラからキャプチャした画像図 12 カメラの角度により,表示角度が変わる

Teapot

◇ 課題 2 ◇� �1. kadai2 のフォルダに入っている cvglview wii.c をコンパイルし,実行せよ.実行には,

Bluetoothのアドレス 00:00:00:00:00:00を引数にとり,実行する.Bluetoothのアドレスは

貸し出したWiiリモコンの裏側に書かれている.� �./cvglview_wii 00:00:00:00:00:00� �

2. Wii リモコン部分のソースが追加されているが,プログラム内でどう利用されているのか,

ざっと読んで把握せよ.Wiiリモコンのイベントのコールバックを実装せよ.その後,カメ

ラ位置に合わせて映像が動くように gluLookAtを修正せよ.結果のイメージは,カメラ映像

が図 11であり,生成されている CGが図 12である.カメラの動きに応じて,Teapotの向

きも変わることを確認せよ.

3. Wiiリモコンのボタンや傾きによって,Teapotの移動や色の変化などインタラクションを加

えよ.この変更結果はスクリーンキャプチャせよ.

� �

Page 14: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

14 4 インタフェースとしてのカメラ・Wiiリモコン

座標マッピングの方法をうまく考えることによって,視点位置や描画画面の全体の変化をカメラで操作し,

描画されているオブジェクトの個別の変化をWiiリモコンで操作することなど,直観的な操作が可能となる.

インタフェースの特性を考慮に入れた設計などをすることが重要である.

課題 2において,カメラの三次元位置をチェスボードとの相対関係を知り,操作可能になった.そこで,カ

メラからの映像をコンピュータグラフィックスの中に取り込み,その中にコンピュータグラフィックスを重ね

合わせることにより,あたかもコンピュータグラフィックスが現実世界の上に乗っているように見せることが

可能となる.カメラを動かすことにより位置を動かすことができ,Wiiリモコンを動かすことにより他のパラ

メータをいじることができる.これらを発展させた技術が拡張現実感(AR)である.

◇ 課題 3(オプション) ◇� �1. kadai3 のフォルダに入っている cvglarview.c をコンパイルし,実行せよ.実行には Blue-

toothのアドレス 00:00:00:00:00:00を引数にとり,実行する.Bluetoothのアドレスは貸し

出したWiiリモコンに書かれている.� �./cvglarview 00:00:00:00:00:00� �

2. Wiiリモコン部分,キャプチャ部分,表示部分など,プログラムの全体像を把握せよ.カメ

ラ位置に合わせて映像が動くように gluLookAtを修正せよ.結果のイメージは,カメラ映像

が図 13であり,生成されているコンピュータグラフィックスが図 14である.

3. 表示させる物体を teapot以外の形に変化させよ.独自性が高いものが望ましい,その結果,

現実世界の上に重なっているように見えるか試みてみよ.この変更結果はスクリーンキャプ

チャせよ.

4. チェスボードの上で球が転がるようにし,それをWiiリモコンで操作できるようにせよ.そ

の結果をスクリーンキャプチャせよ.

� �

図 13 カメラからキャプチャした現実世界図 14 カメラからの現実世界の上に Teapot が乗っ

ている状態

Page 15: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

15

5 三次元コンピュータグラフィックスと Natural User Interface

人間とコンピュータがインタラクションを行う手法として,NUI(Natural User Interface)が注目を集めて

いる.NUIとは,「触れる」「動く」「話す」などの人間の自然な動作を利用してコンピューターを操作するイ

ンタフェースを指す.人間とコンピュータがインタラクションを行う手法としては,コマンドを文字で打ち込

んで対話する CUI(Character User Interface),PCのデスクトップ画面のようなコンピュータグラフィック

スとポインティングデバイスを利用して対話する GUI(Graphical User Interface)などが用いられてきたが,

これらはある一定の「お約束」を学習 (例えば特定のコマンドや,特定の場所をクリックすることなどを覚え

る必要がある)してから利用する必要があり,誰もがすぐに使いこなせるわけではない.一方,NUIを上手に

設計できた場合には,直観的で学習コストが少なく,すぐに誰でも使いこなせるインタフェースを実現するこ

とも可能となる.

5.1 Kinect

前章では人間とコンピュータがインタラクションを行う際に,人間の身体動作を取り入れるためのデバイス

としてWiiリモコンを紹介した.ここでは同様のインタフェースとして昨今注目を集めている Kinectを紹介

する.Kinectは,2010年にMicrosoft社から発売された,Xbox 360向けのゲームデバイスである.Kinect

では画像ベースで人間のジェスチャを検出することができるため,Wiiリモコンのようにユーザ側にデバイス

を身に着けさせる必要が無いというメリットがある.Kinectには RGBカメラ・深度センサ・マイクロフォ

ンアレイが付いており,ジェスチャ認識機能の他にも,深度画像取得や音声認識などの機能がある.これらの

機能は,Kinectを PCから扱うためのライブラリである OpenNIや Kinect Windows SDKを介して利用す

ることができる.そのため,Kinectはゲームのインタフェースとしてだけでなく,趣味の工作から研究まで

幅広く利用されている.また,Kinectと同等に扱えるデバイスとして,Xtion PRO・Xtion PRO LIVEと

いった類似デバイスも登場している.

5.2 OpenNIの概要

OpenNI (Open Natural Interaction)は,Kinectのセンサ部を開発した PrimeSence社が中心となって開

発したオープンソースのライブラリである.非公式のドライバを用いることで,OpenNIから Kinectの機能

にアクセスできるようになる.OpenNIの公式ページ http://openni.org/Downloads/OpenNIModules.aspx

 から入手することができたが,2014年 4月 23日に公開が終了した.なお,ソースコードについてはGitHub

上で公開されている.

OpenNIは RGB画像取得,深度データ取得,ユーザトラッキング(人間の識別と追跡),スケルトントラッ

キング(人間の関節位置などを推定し,ポーズを識別する)などの諸機能を有している. Kinectからの画像

をミラー反転させたり,RGB 画像と深度画像のビューポイントを一致させる関数や,Kinect から取得した

データをファイル(.oni)に書き出すなど,便利な機能が用意されている.

また,GNU Lesser General Public License (LGPL)ライセンス下でオープンソースとして公開されてお

り,商業利用時にも利用しやすいという利点がある.

本資料ではインストール方法の紹介は割愛する.利用したい場合には Kinect wiki ( http://www.kinect-

wiki.info/ )の情報が詳しいので参考にされたい.Kinect wikiにはWindows,Mac OS Xの場合のインストー

Page 16: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

16 5 三次元コンピュータグラフィックスと Natural User Interface

図 15 手をつかったジェスチャの認識

図 16 スケルトンの認識

ル方法が紹介されている.Linux (Ubuntu)での利用方法については「 Ubuntuで OpenNIと Kinectドライバ

と NITE のダウンロードとビルドとインストール」 ( http://www.kkaneko.com/rinkou/linux/openni.html

) 等に解説がある.

Page 17: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

5.3 OpenNIを利用した深度と画像情報の取得 17

5.3 OpenNIを利用した深度と画像情報の取得

本演習では,ROS用の OpenNIから Kinectを利用する.現在の演習環境で ROSの OpenNIを起動する

には,ROSが localhostを参照するように設定し(turtlebotを動かす際には改めて 133.11.216.159に設定し

直す必要がある),下記のように roslaunchコマンドから openni launchを呼び出す.� �export ROS_HOSTNAME=localhost

export ROS_MASTER_URI=http://localhost:11311

roslaunch openni_launch openni.launch� �起動するとエラーが表示されることがあるが,これは利用には問題ないので無視して良い.roslaunchを実

行した状態で,別の端末からプログラムを呼び出すと kinectが利用できる.

01-depth-testのフォルダに入っている main.cppは,Kinectの赤外線カメラを利用して距離を測るプログ

ラムである.Kinectでは 500mmの位置からミリメートル単位で,全てのピクセルの距離を計測できる.な

お,500mm以下の位置では正しく距離が計測できない.距離の測定には DepthGeneratorを使用する.

//DepthGeneratorの生成

DepthGenerator depth;

nRetVal = context.FindExistingNode(XN_NODE_TYPE_DEPTH, depth);

//デプスメタデータの取得

DepthMetaData depthMD;

depth.GetMetaData(depthMD);

//カメラ中心のピクセルに写った物体までの距離を計測して表示

printf("Frame %d Middle point is: %u. FPS: %f\n", depthMD.FrameID(),

depthMD(depthMD.XRes() / 2, depthMD.YRes() / 2), xnFPSCalc(&xnFPS));

DepthGeneratorを生成し,depth.GetMetaData(depthMD)とすることで depthMDにデプスメタデータ

が格納される.この状態で depthMD(x, y)とするとカメラ画像内の座標(x, y)のピクセルの距離が求めら

れる.なお,depthMD.XRes(),depthMD.YRes()はデプス画像の幅,高さを返す.

02-simple-imageのフォルダに入っている simple-image.cppは,Kinectの通常のカメラ画像を取得して表

示するプログラムである.なお,通常の OpenNI から呼び出す場合と,ROS から OpenNI を呼び出す場合

では画像データに格納されるデータの順番が異なる.simple-image.cppでは ROS MODEを 1にすることで

ROSの格納順に対応し,ROS MODEを 0にすることで通常の OpenNIに対応できるようにしてある.

Page 18: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

18 5 三次元コンピュータグラフィックスと Natural User Interface

//ImageGeneratorの生成

rc = g_context.FindExistingNode(XN_NODE_TYPE_IMAGE, g_image);

//フレームの更新

rc = g_context.WaitAnyUpdateAll();

//イメージメタデータの取得

g_image.GetMetaData(g_imageMD);

//イメージデータのバッファの先頭アドレスの取得

const XnUInt8* pImageRow = g_imageMD.Data();

ImageGenerator を生成し,image.GetMetaData(imageMD) とすることで imageMD にデプスメタデー

タが格納される.この状態で imageMD.Data()によりイメージデータのバッファの先頭アドレスを取得でき

る.その後,適切な色データの配列に変換し,表示する.

03-simple-depthのフォルダに入っている simple-depth.cppは,Kinectからデプス画像を取得して表示す

るプログラムである.デプス画像とは,Kinectの赤外線カメラを利用して計測した,各ピクセルに写った対

象までの距離を,一枚の濃淡画像として表わしたものである.全てのピクセルの距離データを使って奥行きを

可視化するために,元の画像中の距離の分布を平坦化して補正し,正しく描画可能なヒストグラムを求める.

得られたヒストグラムを元のデプス画像に上書きして表示することで,見やすいデプス画像を表示している.

図 17 simple-depth.cppを実行しデプス画像が表示されている様子

Page 19: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

5.3 OpenNIを利用した深度と画像情報の取得 19

// デプスのヒストグラムを計算し,デプス画像を生成する

unsigned int nNumberOfPoints = 0;

for (XnUInt y = 0; y < g_depthMD.YRes(); ++y) {

for (XnUInt x = 0; x < g_depthMD.XRes(); ++x, ++pDepth) {

if (*pDepth != 0) {

g_pDepthHist[*pDepth]++;

nNumberOfPoints++;

}

}

}

for (int nIndex=1; nIndex<g_nZRes; ++nIndex) {

g_pDepthHist[nIndex] += g_pDepthHist[nIndex - 1];

}

if (nNumberOfPoints) {

for (int nIndex=1; nIndex<g_nZRes; ++nIndex) {

g_pDepthHist[nIndex] = (unsigned int)(256 *

(1.0f - (g_pDepthHist[nIndex] / nNumberOfPoints)));

}

}

◇ 課題 4 ◇� �1. 01-depth-testのフォルダに入っているmain.cppを実行し,動作を確認せよ.

2. 02-simple-imageのフォルダに入っている simple-image.cppを実行し,動作を確認せよ.

3. 03-simple-depthのフォルダに入っている simple-depth.cppを実行し,動作を確認せよ.

4.(オプション)main.cppと simple-image.cppを組み合わせ,カメラ画像を確認しながら,そ

の中央に写った物体までの距離を出力するプログラムを作成せよ.画面中央には赤い円等を

表示し,画像を見ながら直観的にある物体までの距離を計測できるようにするとなお良い.

� �

Page 20: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

20 5 三次元コンピュータグラフィックスと Natural User Interface

5.4 OpenNIによる人物の検出・トラッキングと姿勢推定

ここまで Kinectの基本機能であるカラー画像,デプス画像の取得を行ってきた.それだけでなく,NUIと

しての Kinect を特徴付けるものとして,デプス画像を基に人物を検出し,トラッキング,ジェスチャ認識,

姿勢推定など高度なユーザ認識機能がある.

人間の三次元的な姿勢の判別はアルゴリズムのみでは不可能である.そこで Kinectでは,大勢の人間にさ

まざまな姿勢をとってもらい,計測したデプス画像中での姿勢のパターンを機械学習させている.これによ

り,デプス画像中の特定のパターンから人間と思われる箇所を即座に抽出し,その三次元的な姿勢を推定する

ことを可能にしている.本演習では,人物の検出・トラッキングとユーザの姿勢推定について取り上げる.

04-userのフォルダに入っている user.cppは,デプス画像中の人物領域を検出し,色づけして表示するプロ

グラムである.このプログラムでは,まずユーザジェネレータを作成し,ユーザが検出された時,消失した時

(検出できなくなった時)に呼び出されるコールバック関数を登録しておく.

//ユーザジェネレータの作成

nRetVal = g_Context.FindExistingNode(XN_NODE_TYPE_USER,

g_UserGenerator);

// ユーザ検出時のコールバック関数

void XN_CALLBACK_TYPE User_NewUser(xn::UserGenerator& generator,

XnUserID nId, void* pCookie)

{

printf("New user: %d\n", nId);

}

// ユーザ消失時のコールバック関数

void XN_CALLBACK_TYPE User_LostUser(xn::UserGenerator& generator,

XnUserID nId, void* pCookie)

{

printf("Lost user: %d\n", nId);

}

//ユーザコールバックの登録

XnCallbackHandle hUserCallbacks;

nRetVal = g_UserGenerator.RegisterUserCallbacks(User_NewUser,

User_LostUser, NULL, hUserCallbacks);

描画ループでは UserGenerator.GetUserPixels(0, sceneMD) によりユーザデータを取得する.このデー

タを基にユーザデータが振られている領域を判定し,色分けする.認識中のユーザ数は UserGenera-

tor.GetUsers(aUsers, nUsers) を利用して取得することができる.i 番目に認識されているユーザの重心

Page 21: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

5.4 OpenNIによる人物の検出・トラッキングと姿勢推定 21

位置は UserGenerator.GetCoM(aUsers[i], com)を利用して求めることができる.

//ユーザデータの取得

g_UserGenerator.GetUserPixels(0, sceneMD);

//pLabelsが 0でない領域(ユーザが検出されている領域)に色を塗る

if (g_bDrawBackground || *pLabels != 0) {

nValue = *pDepth;

XnLabel label = *pLabels;

XnUInt32 nColorID = label % nColors;

if (label == 0) {

nColorID = nColors;

}

if (nValue != 0) {

nHistValue = pDepthHist[nValue];

pDestImage[0] = nHistValue * Colors[nColorID][0];

pDestImage[1] = nHistValue * Colors[nColorID][1];

pDestImage[2] = nHistValue * Colors[nColorID][2];

}

}

//認識中の人数の取得

g_UserGenerator.GetUsers(aUsers, nUsers);

//カメラを原点としたユーザの重心位置の取得

XnPoint3D com;

g_UserGenerator.GetCoM(aUsers[i], com);

//重心位置にラベルを描画

glRasterPos2i(com.X, com.Y);

glPrintString(GLUT_BITMAP_HELVETICA_18, strLabel);

ここまででユーザを検出することができた.続いてユーザの姿勢を推定する.05-skeltonのフォルダに入っ

ている main.cppおよび SceneDrawer.cppは,デプス画像中の人物領域を検出し,色づけして表示するだけ

でなく,人物の姿勢を推定し,スケルトン(姿勢の骨格)も表示するプログラムである.このプログラムで

は,先ほどまでのプログラムに加えて,ポーズが検出された時,キャリブレーションが開始された時,キャリ

Page 22: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

22 5 三次元コンピュータグラフィックスと Natural User Interface

図 18 user.cppを実行しデプス画像中の人物が検出されている様子

ブレーションが終了した時に呼び出されるコールバック関数も登録されている.

// ポーズ認識時のコールバック関数

void XN_CALLBACK_TYPE UserPose_PoseDetected

(xn::PoseDetectionCapability& /*capability*/,

const XnChar* strPose, XnUserID nId, void* /*pCookie*/)

// キャリブレーション開始時のコールバック関数

void XN_CALLBACK_TYPE UserCalibration_CalibrationStart

(xn::SkeletonCapability& /*capability*/,

XnUserID nId, void* /*pCookie*/)

// キャリブレーション終了時のコールバック関数

void XN_CALLBACK_TYPE UserCalibration_CalibrationComplete

(xn::SkeletonCapability& /*capability*/, XnUserID nId,

XnCalibrationStatus eStatus, void* /*pCookie*/)

スケルトンがトラッキング中かどうかは UserGenerator.GetSkeletonCap().IsTracking(aUsers[i]) で判別

できる.これを利用し,スケルトンが確からしくトラッキングされている時だけスケルトンを描画する.スケ

ルトンから関節位置を取得するには,UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(player,

eJoint, joint)によって推定された関節位置を取得した後,その関節位置の推定の確からしさを判別し,ある程

度確からしければその位置を関節位置として描画する.eJointには関節ごとに割り当てられた番号(たとえば

頭:XN SKEL HEAD = 1 など)が入る.同様の方法で関節位置間のボーン(骨)についても描画している.

Page 23: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

5.4 OpenNIによる人物の検出・トラッキングと姿勢推定 23

//スケルトンのトラッキング中かどうかの判定

if (g_bDrawSkeleton &&

g_UserGenerator.GetSkeletonCap().IsTracking(aUsers[i])) {

//playerの eJointの情報を jointに入れる

XnSkeletonJointPosition joint;

g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition

(player, eJoint, joint);

//jointが確からしく検出されているかを確認

if (joint.fConfidence < 0.5) {

return;

}

//jointの位置情報を得て関節位置に球を描画

XnPoint3D pt;

pt = joint.position;

g_DepthGenerator.ConvertRealWorldToProjective(1, &pt, &pt);

drawCircle(pt.X, pt.Y, 2);

図 19 05-skeltonのプログラムを実行し,人物のスケルトンが推定されている様子

Page 24: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

24 5 三次元コンピュータグラフィックスと Natural User Interface

◇ 課題 5 ◇� �1. 04-userのフォルダに入っている user.cppを実行し,動作を確認せよ.

2. 05-skelton のフォルダに入っているプログラムを実行し,動作を確認せよ.glutKeyboard

を参照し,実行中にキーボードのボタンを押すことでどのように表示が変わるかを確認せよ.

3. 06-head-teapotのフォルダに入っているプログラムを完成させ,ユーザを認識するとユーザ

の頭の位置に teapotを描画するようにせよ.

4.(オプション)06-head-teapotのフォルダに入っているプログラムの背景をデプス画像では

なく実写画像に変更し,実際のユーザの顔を teapotで置き換えるプログラムに変更せよ.

� �◇ 課題 6(オプション) ◇� �

1. 本日の演習で習得したWiiリモコン,Kinectの使用方法と,イメージプロセッシング,コン

ピュータグラフィックス,リアルワールド認識等の演習で学んだ手法を組み合わせたアプリ

ケーションを作成してみよ.例えば Kinectと画像処理・CGの組み合わせだけでも,人物領

域にだけモザイクをかける,人物だけを抽出して背景画像と置き換えることで光学迷彩(物

体を透明にする技術)を実現する,人物領域のみを切り出して CGの背景と合成する,ポー

ズをとることで必殺技が出せる,等が考えられる.

� �

図 20 06-head-teapotのプログラムを実行し,人物の頭部に teapotが表示されている様子の例

Page 25: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

25

◇ 課題メール ◇� �1. 自分の名前と学籍番号を書く.

2. 課題 2-3の実行結果をスクリーンキャプチャしてメールに貼付せよ.メールにファイル名も

記述せよ.ファイル名を kadai2.pngあるいは kadai2.jpgなどのようにせよ.どのように変

更を加えたのか,簡便に記述せよ.

3. 課題 5-3 の実行結果をスクリーンキャプチャしてメールに貼付せよ.スケルトンをトラッ

キングしつつキャプチャを行うのは一人では難しいため,友人らと協力することを薦める.

メールにファイル名も記述せよ.ファイル名を kadai5.pngあるいは kadai5.jpgのようにせ

よ.どのように変更を加えたのか,簡便に記述せよ.

4. オプション課題を実行していた場合,それらについても上記と同様に実行結果のスクリーン

キャプチャを添付し,工夫点を記述せよ.

5.「メディアインタフェース」の授業の感想と意見があれば意見をメールにて送付せよ.

� �6 参考文献

伊藤邦朗,福田隆宏,”Wiiリモコン”,日本機械学会誌,2007.12, Vol.110, No.1069, pp.6-7,2007.

Page 26: インタフェースデバイスと NUItani/class/mech_enshu/enshu...1 機械情報工学科演習 メディアインタフェース(2) インタフェースデバイスとNUI

26 6 参考文献

メモ