AR を作ろう
はじめに
普及してきた AR
「ポケモンGO」ではカメラの映像の中にポケモンが現れます。ニンテンドー 3DS の「AR ゲームズ」でも似たようなことができます。このように、現実世界(の映像)に CG などを重ねて表示する技術を AR(Augmented Reality; 拡張現実)といいます。「電脳コイル」や「ソードアート・オンライン」などのアニメーション作品でも AR のような描写があります。
AR はバーチャルリアリティ(Virtual Reality; VR)の一種ですが、カメラ1個で容易に実現できるため、いちはやく日常生活に普及してきました。
AR のしくみ
AR には様々な方法がありますが、基本的には、カメラがどこを向いているか(何を写しているか)を測って、特定の方向に向いていたら(特定の何かを写していたら)、カメラの映像に CG などを重ねて表示させます。
「ポケモンGO」では、スマホの GPS センサでユーザの居場所を測り、スマホのジャイロセンサや方位センサでユーザが向いている方向を測っています。ポケモンを配置した場所にユーザがいて、ポケモンがいる方向を向いていたら、ポケモンの CG を表示させます。3DS の「AR ゲームズ」では、「AR カード」という目印になる絵がカメラに写っていたら、カードの位置や向きを計算して、カードの上に CG を重ねています。
「センサ」とか「計算」とか、なんだか難しそうですが、わりと簡単に作れるんです! やってみましょう!
今回の内容
目標
まず、パソコンにつないだカメラで特定の模様(マーカ)を検出すると CG を表示する、典型的な AR を作ります。
さらに、もっと複雑な画像を検出して CG を表示する AR を作ります。
使うもの
- Windows のパソコン(Windows 7 以上)
- Web カメラ(パソコン内蔵のカメラでもできますが、外付けカメラのほうが自由が効くのでオススメ、千円台のもの(例えばコレ)で十分)
- インターネット環境(いくつかソフトウェアをダウンロードするため)
- Processing(3.0 以上、コチラを参考にインストール)
ステップ
1. カメラ映像をキャプチャする
AR にはカメラの映像が必要です。Processing で Web カメラの映像を撮る(キャプチャする)準備をします。外付けカメラを用意した場合はパソコンにつないでください。
video ライブラリの準備
Processing でカメラの映像を扱うには「video」というライブラリが必要です。これをインストールします。
まず、Processing の「スケッチ」メニュー -> ライブラリをインポート -> ライブラリを追加 を選びます。
出てきた「Contribution Manager」というウィンドウの「Libraries」タブの左上のテキストボックスに「video」と入力すると、ライブラリがいくつか表示されます。その中の「Video | GStreamer-based video library for Processing」を選択して、右下の「Install」をクリックします。するとダウンロードされ、自動的にインストールされます。
プログラムを書く
Processing に以下のコードを入力して、cam_test.pde という名前で保存しましょう。
import processing.video.*; // video ライブラリを使う Capture cam; // Capture オブジェクトの宣言 // 一度だけ実行される setup() 関数 void setup() { size(640, 480); // ウィンドウのサイズ設定 String[] cameras = Capture.list(); // 利用可能なカメラデバイスを取得 printArray(cameras); // 利用可能なカメラデバイスをコンソールに表示 cam = new Capture(this, cameras[0]); // ★ [0]の部分はあとから書き換える cam.start(); // カメラをスタート } // 繰り返し実行される draw() 関数 void draw() { if(cam.available() == false) { // カメラが利用可能な状態でなければ return; // 何もせず処理を終える } cam.read(); // 映像をキャプチャする image(cam, 0, 0); // キャプチャした画像を表示する }
入力し終えたら実行してください(▶をクリック)。この時点ではカメラの映像が映らなくても大丈夫です。
Processing の「コンソール」に利用可能なカメラの一覧が表示されます(パソコンにつないだカメラが 1台でも、解像度などのモードを複数持っているので、それぞれ別のカメラとして扱われます)。
この一覧の中から「size=640x480,fps=30」というカメラを見つけ、その左端の値を控えてください。上の画像の例では [0] です。
その値を、プログラムの 10行目の cameras[ ] の [ ] 内に書きます。
cam = new Capture(this, cameras[0]); // ★ [0]の部分はあとから書き換える
実行して、カメラの映像が映れば成功です!
2. 超シンプルな AR
ここからが本番です。
まず AR を実現するための「NyARToolkit」というライブラリをダウンロードして設定します。続いて AR のプログラミングです。
NyARToolkit のダウンロードとインストール
こちらのサイトを開き、「Latest release」というマークの右にある「Downloads」から「nyar4psg.zip」をクリックします。するとダウンロードが始まります。
ダウンロードされた「nyar4psg.zip」をダブルクリックして開き(zip を展開しないまま)、中にある「nyar4psg」というフォルダを右クリックして「コピー」を選びます。
自分の「ドキュメント」フォルダに移動します(例えば C:\Users\{ユーザ名}\Documents)。その中に「Processing」という名前のフォルダがあります。さらに中に「libraries」というフォルダがあるので開きます。そこで右クリックして「貼り付け」を選びます。これで nyar4psg がインストールされました。
もし Processing が開いていたら、いったん全て終了させてから、あらためて Processing を起動します。これで nyar4psg ライブラリが使えるようになりました。
AR のプログラミング
Processing に以下のコードを入力して、ar_box.pde という名前で保存しましょう。
それぞれのコードが何をしているのかは、コード中のコメント文を見て考えながら入力していきましょう。
import processing.video.*; // video ライブラリを使う import jp.nyatla.nyar4psg.*; // nyar4psg ライブラリを使う Capture cam; // Capture オブジェクトの宣言 MultiMarker mm; // MultiMarker オブジェクトの宣言 void setup() { // ウィンドウとカメラの設定 size(640, 480, P3D); // ウィンドウのサイズ設定(P3Dモード) String[] cameras = Capture.list(); // 利用可能なカメラデバイスを取得 printArray(cameras); // 利用可能なカメラデバイスをコンソールに表示 cam = new Capture(this, cameras[0]); // ★ cameras[ ] 内にカメラのテストで控えた数字を入れる cam.start(); // カメラをスタート // NyARToolkit の設定 mm = new MultiMarker(this, // NyARToolkit の初期設定 width, // カメラ画像の幅(ウィンドウの幅と同じ 640) height, // カメラ画像の高さ(ウィンドウの高さと同じ 480) "camera_para.dat", // カメラの校正ファイル NyAR4PsgConfig.CONFIG_PSG); // nyar4psg を Processing 用に設定する決まり文句 mm.addNyIdMarker(0, 80); // 認識するマーカを登録する (ID, マーカの幅[mm]) } void draw() { // ビデオキャプチャ if(cam.available() == false) { // カメラが利用可能な状態でなければ return; // 何もせず処理を終える } cam.read(); // 映像をキャプチャする // AR 処理の開始 mm.detect(cam); // キャプチャした画像内でマーカを探す mm.drawBackground(cam); // ウィンドウの背景にキャプチャした画像を設定 if(mm.isExist(0) == false) { // マーカ[0] が存在しなければ return; // 何もせず処理を終える } mm.beginTransform(0); // マーカ[0] の位置にもとづいて座標の投射(変換)を始める translate(0, 0, 40); // 原点の位置の調整(原点をZ軸方向に 40mm 移動) fill(255, 165, 0, 127); // CG の塗りつぶしの設定 (R, G, B, 不透明度) box(80); // 80mm 四方の箱の CG を描く mm.endTransform(); // 座標の投射(変換)を終了 // AR 処理の終了 }
すぐに実行したくなりますが、もう少し我慢です。
各種ファイルとマーカの準備
まず、さきほどインストールした nyar4psg フォルダを開いてください(ドキュメント\Processing\libraries\nyar4psg)。その中の「data」というフォルダの中で以下のファイルを見つけてください。
- camera_para.dat
いま書いたプログラム「ar_box.pde」のフォルダの中に「data」という名前のフォルダを作って、その中に「camera_para.dat」をコピーしください。これは「カメラ校正ファイル」というものですが、ここでは詳しく説明しません。
最後に、こちらのファイルをダウンロードして、プリンタで印刷してください。プリンタが無ければ、パソコンの画面に表示させておいてください。スマホで使う QR コードに似ていますが、AR 用の「マーカ」と呼ばれる図形です。
動作確認
お待たせしました! これで準備完了です。
ar_box.pde を実行し、マーカをカメラで写してください(左上の「000」のマーカ全体が入るように)。
マーカの上にオレンジ色の半透明の箱が表示されれば成功です! カメラを動かしてマーカをいろんな方向から写したら、どうなりましたか? マーカを近づけたり遠ざけたり傾けたら、どうなりましたか?(カメラやマーカを動かす時はゆっくり、また、「000」のマーカ全体が写るようにしましょう)
3. CG モデルを表示させる
上の例では単純な箱を表示しただけで、あまり面白くありませんね。box(80); のように、プログラムの中で CG を描く方法だと、あまり複雑なものは描けません。複雑な CG モデルは別のソフトウェアで作り、Processing で読み込んで表示させます。
ここでは CG モデルの作り方は解説しません。例えば Windows 10 には「3D Builder」というソフトウェアがはじめから入っています。他にも例えば、Blender、Metasequoia、Google SketchUp などが無料で使えるメジャーな CG ソフトウェアです。どれを使っても構いません。最終的に「*.obj」というファイル形式でモデルを保存すれば Processing で表示できます。
ここでは、Processing にはじめから入っている CG モデルを使って AR 表示させてみます(CG モデルのありかはのちほど解説します)。
プログラミング
Processing に以下のコードを入力して ar_obj.pde という名前で保存しましょう。さきほどの ar_box.pde を「名前をつけて保存」して、書き加えたり書き換えていくと効率的でしょう。
それぞれのコードが何をしているのか、さっきと何が違うか、コード中のコメント文を見て考えながら入力していきましょう。
import processing.video.*; // video ライブラリを使う import jp.nyatla.nyar4psg.*; // nyar4psg ライブラリを使う Capture cam; // Capture オブジェクトの宣言 MultiMarker mm; // MultiMarker オブジェクトの宣言 PShape obj; // CG を扱う PShape オブジェクトの宣言 float ry; // CG モデルを回転させるための変数 ry の宣言 void setup() { // ウィンドウとカメラの設定 size(640, 480, P3D); // ウィンドウのサイズ設定(P3Dモード) String[] cameras = Capture.list(); // 利用可能なカメラデバイスを取得 printArray(cameras); // 利用可能なカメラデバイスをコンソールに表示 cam = new Capture(this, cameras[0]); // ★ cameras[ ] 内にカメラのテストで控えた数字を入れる cam.start(); // カメラをスタート // NyARToolkit の設定 mm = new MultiMarker(this, // NyARToolkit の初期設定 width, // カメラ画像の幅(ウィンドウの幅と同じ 640) height, // カメラ画像の高さ(ウィンドウの高さと同じ 480) "camera_para.dat", // カメラの校正ファイル NyAR4PsgConfig.CONFIG_PSG); // nyar4psg を Processing 用に設定する決まり文句 mm.addNyIdMarker(0, 80); // 認識するマーカを登録する (ID, マーカの幅[mm]) // PShape の設定 obj = loadShape("rocket.obj"); // "rocket.obj" という名前の CG モデルを読み込む } void draw() { // ビデオキャプチャ if(cam.available() == false) { // カメラが利用可能な状態でなければ return; // 何もせず処理を終える } cam.read(); // 映像をキャプチャする // AR 処理の開始 mm.detect(cam); // キャプチャした画像内でマーカを探す mm.drawBackground(cam); // ウィンドウの背景にキャプチャした画像を設定 if(mm.isExist(0) == false) { // マーカ[0] が存在しなければ return; // 何もせず処理を終える } mm.beginTransform(0); // マーカ[0] の位置にもとづいて座標の投射(変換)を始める lights(); // 3D シーンに照明を追加 scale(0.3); // CG モデルのサイズを調整 translate(0, 0, 80); // 原点の位置の調整(原点をZ軸方向に 80mm 移動) rotateX(PI/2); // CG モデルを X軸まわりに 90度(π/2)回転させる rotateY(ry); // CG モデルを Y軸まわりに ry ぶん回転させる shape(obj); // CG モデルを表示 mm.endTransform(); // 座標の投射(変換)を終了 // AR 処理の終了 ry += 0.1; // rotateY(ry); で回転させる角度 ry を少し増やす }
すぐに実行したくなりますが、もう少し我慢です。
各種ファイルとマーカの準備
いま書いたプログラム「ar_obj.pde」のフォルダ内に「data」という名前のフォルダを作って、その中に、さきほども使った「camera_para.dat」(カメラ校正ファイル)をコピーしください(「ar_box.pde」を「名前をつけて保存」してから書き始めた場合は、既に入っているかもしれません)。
次に、CG モデルを用意します。Processing.exe のあるフォルダを開いてください。そこから、modes -> java -> examples -> Basics -> Shape -> LoadDisplayOBJ -> data とフォルダをたどってください。以下の三つのファイルがあります。
- rocket.obj … CG モデル本体
- rocket.mtl … 質感設定ファイル(マテリアル)
- rocket.png … CG モデルに貼る画像(テクスチャ)
これら三つすべてを「ar_box.pde」のフォルダ内の「data」の中にコピーしてください。
最後に、さきほどと同じマーカも準備してください。
動作確認
お待たせしました! これで準備完了です。
ar_obj.pde を実行し、カメラでマーカを写してください(左上の「000」のマーカ全体が入るように)。
以下のように、マーカの上にロケットが表示され、くるくる回っていれば成功です!
この CG がポケモンだったら、「ポケモンGO」みたいですね!(あくまで「みたい」ではありますが)
4. 絵をマーカにする
ここまでは白黒の四角いマーカを使ってきました。AR を試すぶんにはこれでなんの問題もありませんが...。例えば絵本をカメラで写したら絵が飛び出す 3D 絵本を作るとしましょう。やさしい画風の絵本にこの無機質なマーカが貼ってあったら、なんだか興ざめしてしまいます。
安心してください。NyARToolkit は白黒の四角いマーカだけでなく、絵や写真などの複雑な図柄もマーカに使うことができます。絵本のページそのものをマーカにすることができるんです。専門的には「自然特徴点追跡(NFT; Natural Feature Tracking)といいます。
そのための手順は以下です。順を追ってやってみましょう。
- 絵や写真の画像ファイルを用意する
- 画像の特徴点ファイルを作る
- プログラミング
絵や写真の画像ファイルを用意する
マーカとして使いたい画像ファイルを用意します。写真でもイラストでも構いませんが、できるだけ複雑な画像が向いています(さっぱりした画像だと特徴を見つけにくいのです)。ファイル形式は jpg または png 形式がよいです。さらに、解像度があまり高いとこの後の処理で時間がかかるので、「ペイント」などのソフトウェアで 640x480 ピクセルくらいにしておきます。
よいものがすぐに見つからなければこの画像をダウンロードして使ってください。
画像の特徴点ファイルを作る
Processing を起動して、「ファイル」メニューから「サンプル」を選んでください。すると以下のような小さなウィンドウが出ます。「Contributed Libraries」の中の「nyar4psg」を開きます。ここにある nftFileGen をダブルクリックします。
開いたプログラムを実行すると、NyAR NftFileGenerator というウィンドウが開きます。
「Import」メニューから「Load image」を選び、出てきたダイアログで、上で準備した画像ファイルを選びます。
右のほうにある「Source DPI」欄に、読み込んだ画像の DPI 値を入れます。DPI 値の調べ方は...。Windows の画面で画像ファイルを右クリックして「プロパティ」を選びます。開いたウィンドウの「詳細」タブの中にある「水平方向の解像度」の値を調べます。以下の例では 72 DPI でした。この値を「Source DPI」欄に入力します。
NftFileGenerator の「Make Feature Set」ボタンをクリックします。すると、画像の中から特徴的な部分(自然特徴点)を探し始めます。
しばらく待つと、以下のように特徴的な場所に赤や青の印が示され、右下に様々な値が出ます。これらの特徴点をカメラの映像から探してマーカ代わりにします。なお、これらの赤や青の印ができるだけ画像内にまんべんなくあるほうがカメラで検出しやすい画像です。あまりにも印が少なかったり、どこかに偏っていたら、違う画像を使うことも検討しましょう。
最後に、「Export」メニューの「Save FeatureSet Files」を選ぶと、ファイル保存ダイアログが開きます。適当な名前で保存してください。なお、ここでは拡張子(.jpg など)は入力しません。例えば launchpad という名前で保存すると以下のような三つのファイルができます。これらを後から使います。
- launchpad.fset
- launchpad.fset3
- launchpad.iset
プログラミング
ar_obj.pde を「名前をつけて保存」で ar_nft.pde という名前で保存します。そこに以下のコードを入力しましょう。それぞれのコードが何をしているのか、さっきと何が違うか、コード中のコメント文を見て考えながら入力していきましょう。
22行目の "launchpad" の部分は、上で作った特徴点ファイルの名前を指定します。
import processing.video.*; // video ライブラリを使う import jp.nyatla.nyar4psg.*; // nyar4psg ライブラリを使う Capture cam; // Capture オブジェクトの宣言 MultiNft nft; // ★ MultiNft オブジェクトの宣言 PShape obj; // CG を扱う PShape オブジェクトの宣言 int pz; // ★ CG モデルを動かすための変数 pz の宣言 void setup() { // ウィンドウとカメラの設定 size(640, 480, P3D); // ウィンドウのサイズ設定(P3Dモード) String[] cameras = Capture.list(); // 利用可能なカメラデバイスを取得 printArray(cameras); // 利用可能なカメラデバイスをコンソールに表示 cam = new Capture(this, cameras[0]); // ★ cameras[ ] 内にカメラのテストで控えた数字を入れる cam.start(); // カメラをスタート // NyARToolkit の設定 nft = new MultiNft(this, // ★ NyARToolkit の初期設定 width, // カメラ画像の幅(ウィンドウの幅と同じ 640) height, // カメラ画像の高さ(ウィンドウの高さと同じ 480) "camera_para.dat", // カメラの校正ファイル NyAR4PsgConfig.CONFIG_PSG); // cnyar4psg を Processing 用に設定する決まり文句 nft.addNftTarget("launchpad", 145); // ★ 認識するターゲット画像を登録 (ファイル名, 画像の幅[mm]) // PShape の設定 obj = loadShape("rocket.obj"); // "rocket.obj" という名前の CG モデルを読み込む } void draw() { // ビデオキャプチャ if(cam.available() == false) { // カメラが利用可能な状態でなければ return; // 何もせず処理を終える } cam.read(); // 映像をキャプチャする // AR 処理の開始 nft.detect(cam); // ★ キャプチャした画像内でマーカを探す nft.drawBackground(cam); // ★ ウィンドウの背景にキャプチャした画像を設定 if(nft.isExist(0) == false) { // ★ ターゲット[0] が存在しなければ return; // 何もせず処理を終える } nft.beginTransform(0); // ★ ターゲット[0] の位置にもとづいて座標の投射(変換)を始める lights(); // 3D シーンに照明を追加 scale(0.15); // ★ CG モデルのサイズを調整 translate(-500, 300, pz); // ★ 原点の位置の調整 rotateX(PI/4); // ★ CG モデルを X軸まわりに 45度(π/4)回転させる shape(obj); // CG モデルを表示 nft.endTransform(); // ★ 座標の投射(変換)を終了 // AR 処理の終了 pz += 20; // ★ CG を動かす値を増やす if(pz > 1000) { // ★ もし pz が 一定値以上なら pz = 0; // ★ 元の位置に戻す } }
すぐに実行したくなりますが、もう少し我慢です。
各種ファイルとターゲット画像の準備
いま書いたプログラム「ar_nft.pde」のフォルダ内に「data」という名前のフォルダを作って、その中に、さきほども使った「camera_para.dat」(カメラ校正ファイル)をコピーしください(「ar_obj.pde」を「名前をつけて保存」してから書き始めた場合は、既に入っているかもしれません)。
次に、さきほども使った CG モデルを用意します。以下の三つのファイルを「data」の中にコピーしてください(これらも「ar_obj.pde」を「名前をつけて保存」してから書き始めた場合は、既に入っているかもしれません。もし無ければ... Processing.exe のあるフォルダを開き、modes -> java -> examples -> Basics -> Shape -> LoadDisplayOBJ -> data とフォルダをたどって見つけてください)。
- rocket.obj … CG モデル本体
- rocket.mtl … 質感設定ファイル(マテリアル)
- rocket.png … CG モデルに貼る画像(テクスチャ)
さらに、さきほど作った三つの特徴点ファイル(*.fset, *.fset3, *.iset)も「data」の中に入れてください。
最後に、さきほど用意した画像ファイルをプリンタで印刷してください。プリンタが無ければ、パソコンの画面に表示させておいてください。
動作確認
お待たせしました! これで準備完了です。
ar_nft.pde を実行し、ターゲット画像を写してください。
以下のように、ターゲット画像の上にロケットが表示され、飛んでいけば成功です!
これで、四角いマーカを使わなくても、飛び出す絵本などができますね!
まとめ
AR のプログラミング、いかがでしたか?
プログラミング以外の作業が少し多いですが、プログラム自体は実質 40行くらいでした。AR を作ること自体はとても簡単なのです(親切な方々が簡単にしてくれているのです)。これからは「AR を使って何をする?」というのが大切な視点です。ぜひいろんなアイデアを試してみましょう。
例えば ar_box.pde を改造して...
- もっといろいろな形や色を表示させてみる
- CG を回転させてみる
- 別のマーカで表示させてみる
例えば ar_obj.pde を改造して...
- いろいろな obj ファイルをネットでダウンロードして表示させてみる
- Windows 10 の 3D Builder に入っている CG モデルを obj 形式で保存して、表示させてみる
- Blender などのソフトウェアで自分で CG モデルを作って表示させてみる
例えば ar_nft.pde を改造して...
- いろいろなターゲット画像を使ってみる
- 飛び出す AR 絵本を作ってみる
- いろいろな場所の写真を撮って、それをターゲット画像にしたら、実際にその場所に行ってカメラで写したら AR できるか実験してみる
などなど、改造して遊びながら、楽しい応用を考えてみましょう。
補足
上で作ったコードはすべてこちら(GitHub)に置いてありますから、参考にしてください。
ほかにも、NyARToolkit に付属しているサンプル(ドキュメント\Processing\libraries\nyar4psg\examples の中)を開いていろいろ試してみてください。
慣れてきたらリファレンス(ドキュメント\Processing\libraries\nyar4psg\reference の中)も見ると、いろいろ改造・応用のヒントが思い浮かぶかもしれません。