Imaginary Code

from kougaku-navi.net

Processingでオクルージョン表現のあるARを作る(ARマーカ編)

 ARにおいて,現実の世界に3次元CGが違和感なく存在しているように見せるための条件の1つに,オクルージョンの実現があります.オクルージョンとは隠れのことで,実物体の背後にCGがあるときにCGの一部またはすべてが隠れて見えなくなっている状態をきちんと表現しようというものです.

 今回はこういうもの↓に挑戦してみましょう.

しくみ

 TV番組や映画の制作で用いられているクロマキー合成の技法を使います.まず,シーンの背景色を緑色に設定し,実物体と同形状の緑色のCGと,重畳したいCGを一緒に描画します.これによりCGが実物体でマスクされた画像を得ることができます.このデータをいったんバッファに保存します.次にカメラ画像を描画し,バッファ中の緑色でないピクセルだけを画面上に描画していけば,合成完了です.


実装してみる

 ProcessingとNyAR4psg(Processing版のARToolKit)を使って作ります.実物体の形状は既知(45mmサイズの立方体)とし,ARマーカを貼り付けて位置姿勢のトラッキングを行います.

 ソースはこんな感じです.実行させるにはNyAR4psgに同梱されているpatt.hiroとcamera_para.datも必要です.

import jp.nyatla.nyar4psg.*;  // ARToolKit
import processing.video.*;    // ビデオライブラリ

Capture cam;    // キャプチャ
MultiMarker ar; // ARマーカに関する処理をするオブジェクト
int id;         // マーカに割り当てられるID番号

color[] pixelBuffer = null;            // 描画内容を一時保存しておくためのバッファ
color   key_color = color(0, 255, 0);  // クロマキー合成用の背景色
float   marker_size = 40;              // マーカサイズ [mm]
float   box_size = 45;                 // 立方体のサイズ [mm]
float   angle = 0;                     // 回転角度

void setup() {
  size(640, 480, P3D);
  
  // マーカ認識の準備
  cam = new Capture(this, width, height);
  ar = new MultiMarker(this, width, height, "camera_para.dat", NyAR4PsgConfig.CONFIG_PSG);
  id = ar.addARMarker("patt.hiro", marker_size);
  
  // バッファの準備
  pixelBuffer = new color[width * height];
}

void draw() {
  if (cam.available()==false) return;
  cam.read();                         // カメラ画像の読み込み
  ar.detect(cam);                     // マーカ認識
  background(key_color);              // クロマキー合成用の背景色を設定
  
  // マーカが認識されていたら
  if ( ar.isExistMarker(id) ) {
    ar.beginTransform(id);    
      translate(0, 0, -box_size/2); // 立方体の中心に原点を移動

      // 実物体と同サイズのオブジェクトを描画
      noLights();                   // 照明OFF
      noStroke();                   // 輪郭線なし
      fill(key_color);              // クロマキー合成用の背景色で描画
      box(box_size);                // 実物体と同じ大きさの立方体を描画

      // 立方体の周りを回転する球体の描画
      lights();                     // 照明ON
      fill(255,0,0);                // 球体の色
      rotateY(angle);               // 座標系の回転
      translate(70,0,0);            // 座標系の移動
      sphere(15);                   // 球体を描画
      noLights();                   // 照明OFF
      
    ar.endTransform();
  }

  // 描画したデータをバッファに一時退避
  loadPixels();                    // pixelsに画面データをロード
  arrayCopy(pixels, pixelBuffer);  // バッファにコピー

  // クロマキー合成処理
  background(0);                    // 画面の初期化
  ar.drawBackground(cam);           // 背景画像の描画
  loadPixels();                     // pixelsに画面データをロード  

  for (int i = 0; i < width * height; i++) {
    if (pixelBuffer[i] != key_color) {
      pixels[i] = pixelBuffer[i];   // キーカラーでないピクセルだけ書き換え
    }
  }
  updatePixels();                   // pixelsのデータを画面に反映
  
  angle += 0.1; // 球の回転角度の更新
}

この話の最先端は?

 事前に形がわかっていない物体や,手のように形状が逐次変化する物体に対してオクルージョン表現を行うためには,リアルタイムに物体の形状を再構成する必要があります.

 画像から物体の3次元再構成を行う方法はコンピュータビジョンの分野で熱心に研究されています.ステレオカメラやデプスセンシングカメラなどの特殊なカメラを使うアプローチもあれば,普通の単眼のカメラを使ってシーンの動き情報から3次元形状を復元するアプローチもあります.写真から3Dモデルを生成するようなものは既に実用化されていますが,それをリアルタイムにできて,なおかつ移動物体や変形物体に対しても適用できるようにすることが現在のミッションです.

Interactive Modelling for AR Applications

 上の動画は普通の単眼カメラを使った手法の例です.その場でインタラクティブに3次元モデルを生成しています.オクルージョン表現はもちろんのこと,キャプチャしたモデルを変形させたりたくさんコピーしたりできるところが面白いです.この研究は2010年にAR/MRのトップカンファレンスであるISMARでベストペーパーに輝きました.カメラの位置姿勢を計測するのにPTAMを組み合わせていますね(余談ですが,PTAMもISMAR2007でベストペーパーをとっています).

KinectFusion

 最近はKinectを使ったもの(KinectFusion)が注目されていますね.こちらはISMAR2011でベストペーパーに輝いています.家庭用のゲームデバイスでここまでできてしまうのはなんとも夢があります.スマートフォンにもいずれデプスカメラが載るかもしれないですね.

やることは山積み

 現実世界に違和感なくCGを溶け込ませるためには,オクルージョンの他にも,CG物体が現実世界に落とす影の表現,鏡面反射するCG物体への周辺の映り込み,現実の鏡に映り込むCG物体,現実の風にあおられて揺れるCGキャラクタの髪,実物体の材質に応じて変化するCGの物理的挙動など,実はまだまだやることはたくさんあります.今後はこの方向がどんどん面白くなっていくでしょう.


【2012/10/16追記Kinect編を書きました.こちらもどうぞ↓