背景
OpenCV3.1.0(?)からstructured-lightというコードが追加されたようです。
これは、2台のカメラと1台のプロジェクターからなる3Dスキャン用のプログラムだと思いました。
これを改造して1台のカメラと1台のプロジェクターで3次元復元できるようなプログラムを作ってみました。
(ただし、撮影処理自体はプログラムに含まれていません。あらかじめ撮影された画像に対して処理するプログラムです。)
前提知識(この記事で説明を省略する内容)
- カメラキャリブレーション
- プロジェクターのキャリブレーション
- グレーコードのエンコード/デコード
- 三角測量
- 使用ライブラリ/ソフトのインストール方法
実行環境
- windows 8.1(64ビット)
- Microsoft Visual Studio Express 2013 for Windows Desktop
- OpenCV 3.1.0
- プロジェクター
- カメラ
作業&処理の流れ
- カメラとプロジェクターのキャリブレーション
- グレーコードパターンを対象物体に投影して撮影する
- 撮影画像をデコード
- デコード結果とキャリブレーション結果から三角測量
1. カメラとプロジェクターのキャリブレーション
キャリブレーションは以下のページの方法で行いました。
http://qiita.com/nn_tok/items/852e1a7d4d9a1e7d5075
2. グレーコードパターンを対象物体に投影して撮影する
グレーコードパターンはバイナリ―パターン光をちょっと賢くしたくらいの認識です。
バイナリ―パターン光について雑に説明すると白黒の縞模様です。パターンは複数種類あります。
全パターンを投影して、光が当たったか当たってないかで0、1のビット列を生成して、
そのビット列に基づいてプロジェクターのどの画素座標と対応しているかを計算します。
全パターンを投影して撮影するので、デコード画像を生成するには、複数枚の画像を撮影する必要があります。
グレーコードパターンを生成するプログラムは以下です。
(グレーコードパターンのエンコードもデコードもOpenCVで実装されている関数を呼び出しているだけです)
https://github.com/kibekibe/structured_light/blob/master/gray_code/main_encode.cpp
実行すると様々な縞模様が出力されます。
これらのパターンを被写体に投光します。
以下は撮影画像の一例。
3. 撮影画像をデコード
デコードするプログラムは以下です。
https://github.com/kibekibe/structured_light/blob/master/gray_code/main_decode.cpp
実行時の引数例は以下です。
test_img_list.txt 512 384 -white_thresh=1 -black_thresh=5
第1引数に撮影画像列を1行ごとに記述したテキストファイルを指定します。
第2、第3引数にプロジェクターの画像幅と画像高さをそれぞれ指定します。
オプションの-white_threshは光が当たっているときと当たっていないときの輝度値の差の閾値です。説明を省きましたが、グレーコードパターンには、白黒のビットパターンを反転した画像が含まれています。このビット反転画像と輝度値の差が十分あるかをチェックしています。
オプションの-black_threshはそもそもちゃんと光が届いているかをチェックするための閾値です。真っ白パターンを投影しているときと真っ黒パターンを投影しているときでちゃんと輝度値に差があるかを閾値判定によってチェックします。
実行するとデコード結果の画像が出力されます。
画像フォーマットはexr画像とpng画像の2種類です。pngはデコード結果の確認用に出力しています。
以下の図は、左から被写体、x座標のデコード結果の可視化画像、y座標のデコード結果の可視化画像です。デコード画像は明るい画素ほど、プロジェクター座像座標値が大きいことを表しています。
4. デコード結果とキャリブレーション結果から三角測量
デコード画像が得られたら、後はOpenCVで実装されている三角測量の関数を呼び出すだけです。原理が良く分かっていなくてもできちゃう、便利(^o^)
プログラムは以下です。
https://github.com/kibekibe/structured_light/blob/master/procam_triangulation/main_procam_triangulation.cpp
実行時の引数例は以下です。
-xMap=x.exr -yMap=y.exr -mask=x.png -cam=camera_data.yml -proj=proj_data.yml -rt=extrinsics.yml -texture=cap_target/DSC04088.JPG
-xMapオプション、-yMapオプションにそれぞれx座標、y座標のデコード結果画像を指定します。-maskに指定する画像は、3次元復元する画素を指定するマスク画像です。
-cam、-projにはキャリブレーションによって得られたカメラ内部パラメーター、プロジェクター内部パラメーターを指定します。フォーマットはOpenCVのymlかxmlのフォーマットです。
-rtはカメラ、プロジェクター間の外部パラメーターです。
-textureは復元される3次元点群の色を付けるための画像を指定します。
サンプルデータ
https://github.com/kibekibe/structured_light/tree/master/sample_data
サンプルデータを実行すると以下のようなポイントクラウドが手に入ります(ビューアーはMeshLab http://meshlab.sourceforge.net/ を使用)