LoginSignup
11
13

More than 5 years have passed since last update.

Hamming Color Codeを使って、プロジェクターの(幾何学的)キャリブレーション

Last updated at Posted at 2016-07-30

背景

コンピュータービジョンの分野だと、カメラの焦点距離や位置・姿勢情報を推定することをカメラキャリブレーションと呼んでいると思います(正確には幾何学的なキャリブレーション?)。
これらの情報が推定できれば、ARでCGを重畳させたり、2台以上のキャリブレーション済みのカメラを使って、撮影シーンの3次元情報を推定したり色々できるようです。

また、世の中にはOpenCVというライブラリがあって、このライブラリを使えは、ゼロからカメラキャリブレーションのプログラムを実装する必要もなさそうです。

一方で、プロジェクターの幾何学的キャリブレーションとなると、カメラキャリブレーションと比べてネット上での情報が少ないと思いました。

というわけで、プロジェクターの幾何学的キャリブレーションをやってみたので、そのメモを書きます。

プロジェクターの幾何学的キャリブレーションとは?

プロジェクターの焦点距離とか光軸の位置(画像上の位置)を求めることだと思います。
カメラは、シーンから入射してくる光を画像として受け取ります。一方でプロジェクターは入力画像をシーンに出射します。光の進行方向は逆だけど、光の経路はどちらも同じカンジ。ということはプロジェクターもカメラと同じようにキャリブレーションできる、という話だと思います。

前提知識(この記事で説明を省略する内容)

  • カメラキャリブレーション
  • ステレオカメラのキャリブレーション
  • 使用ライブラリ/ソフトのインストール方法

実行環境

  • windows 8.1(64ビット)
  • python 2.7
  • Microsoft Visual Studio Express 2013 for Windows Desktop
  • OpenCV 3.1.0
  • プロジェクター
  • カメラ

作業&処理の流れ

  1. カメラキャリブレーション用のパターンを印刷して板かなにかに貼る
  2. ハミングカラーコード画像を作る
  3. プロジェクターを使って、ハミングカラーコードを板に投影してカメラで撮影する
  4. 撮影画像をデコードする
  5. 板のパターンを検出して、検出点の座標(カメラ画像上の座標)をデコード情報に基づいてプロジェクター上の座標に変換して、その対応点セットからステレオキャリブレーションする。

上記の作業&処理の流れは、要は、どうにかしてOpenCVに既に実装されているカメラキャリブレーション関数を利用して楽したい、というカンジ。
キャリブレーション用板の画素座標(プロジェクター画像上の画素座標)さえ分かれば、後はOpenCVにお任せできるので、どうにかしてプロジェクター画像上の座標を求めたい。そのためにハミングカラーコードを使います。

1. カメラキャリブレーション用のパターンを印刷して板かなにかに貼る

OpenCVに実装されているキャリブレーションでは、処理の途中で、市松模様のコーナー点を画像上で検出して、そのコーナー点情報に基づいて焦点距離などを推定します。
まずは、そのためのパターンを印刷して板に貼ります。
今回使ったのは↓のようなものです。OpenCVをインストールすると、白黒の市松模様の画像(pdfかも)が一緒に入ってくると思います。今回は、黒色を少し明るくして灰色にしました(プロジェクター光の反射光を観測したいから)。

P7300001.JPG

2.ハミングカラーコード画像を作る

ハミングカラーコードは文献[1]に書かれている数列のようなものです。
例えば文献[1]中のFigure.1にあるような数列では、6767という数列はかならず1回しか現れません。
つまり、数列を色に変換して、その縞模様をプロジェクターからシーンに投影した場合、その色の組み合わせから、カメラ座標とプロジェクターの座標の対応が分かるというわけです。

文献[1]のFigure. 1のカラーコードを生成するプログラムは以下です。
実行すれば、カラーコード画像が生成されます。
https://github.com/kibekibe/structured_light/blob/master/hamming_color_code/generate_hamming_code.py

3. プロジェクターを使って、ハミングカラーコードを板に投影してカメラで撮影する

1.で作成した板に対して、真っ白の画像、2で作った縞模様(縦と横で計2枚)をそれぞれ投影します。

hamming_scene_cap.jpg

この3枚を1セットとして、板の向きや位置を変えながら複数セット撮影します。このとき、カメラとプロジェクターは動かさず、固定したままにします。

真っ白パターンを撮るのは、後で、市松模様のコーナー点を検出する処理があるからです。

4. 撮影画像をデコードする

文献[1]では高尚なアルゴリズムで高度なパターンマッチングを実現していますが、
レベルが高そうだったので、それは実装せずに、単純に一致するパターン列を探すだけのプログラムを書いてみました。
縦模様の画像から、画像の横軸方向の対応を探します。同様に横模様の画像から、画像の縦軸方向の対応を探します。これらの対応点探索処理は、スキャンラインごとに独立で行いました。
デコードするプログラムは以下です。
https://github.com/kibekibe/structured_light/blob/master/hamming_color_code/hamming_decode.py

実行時に引数で-in_dirオプションを付けて画像フォルダを指定します。
例えば、以下のように実行するとcap_chessboardというフォルダにある画像に対してデコード処理を行います。
python hamming_decode.py -in_dir cap_chessboard

実行すると、プロジェクターの対応座標値が格納された画像が生成されます。画像フォーマットはexr画像とpng画像の2種類です。pngはデコード結果の確認用に出力しています。
実行結果例は以下です。
左が入力画像で、右がデコード結果の画像です。プロジェクターの対応座標値が輝度値を表しています。

cap_decode_x.jpg
cap_decode_y.jpg

ちなみに上記プログラムでは、デコード結果に対してローパスフィルターを掛けています。

5. 板のパターンを検出して、検出座標をデコード情報に基づいてプロジェクター上の座標に変換して、その対応点セットからステレオキャリブレーションする。

プロジェクター画像上でコーナー点を見つけるために、まずカメラ画像上でコーナー点を探します(コーナー点を検出してくれる関数がOpenCVに実装されていて、それを呼ぶだけです)。そして、その検出したコーナー点の画像座標をデコード情報に基づいてプロジェクター画像座標上のコーナー点位置に変換します。
あとは、検出したコーナー点の対応点セットを入力としてステレオキャリブレーションします。ステレオキャリブレーション自体はOpenCVで実装されているので、然るべき関数を呼び出すだけです。

そのプログラムは以下です。
https://github.com/kibekibe/structured_light/blob/master/projcalib_from_decoded_imgs/main_projcalib.cpp

プログラム、サンプルデータセット

参考文献

[1] Hamming Color Code for Dense and Robust One-shot 3D Scanning. Shuntaro Yamazaki, Akira Nukada, Masaaki Mochimaru. Proceedings of the British Machine Vision Conference (BMVC2011), pages 96.1-96.9. BMVA Press, September 2011.

11
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
13