2015. 6. 6.
石立 喬
OpenCVとVisual C++による画像処理と認識(18)
----- 色情報と隠点消去処理を加えて、3D→2D変換を行う -----
コンピュータ・ビジョンは、多数の視点から撮影した二次元画像から、三次元情報を得る。この三次元情報を用いると、任意の方向から見た時の二次元情報に変換することができる。
三次元情報の扱いを理解するために、三次元情報を得る方法の紹介を後回しにして、ここでは、三次元情報が点群(point
cloud)で得られたとして、色情報を加味し、隠点消去処理をして、それを二次元画像に射影することを試みる。
色情報を付加する
三次元物体(点群をで表された)を二次元画像に射影するには、OpenCVのprojectPoints関数を使う。しかし、三次元物体の点群objectPointsも、投影される二次元の点群imagePointsも、色情報を持っていない。
したがって、ここでは、objectPoints点群の他に、object_color変数を用意し、対応する点群のimagePointsへの色付けを行う。
隠点消去処理をする
三次元物体を二次元画像として投影すると、隠れて見えない部分が出てくる。画像処理では、一般的に「陰線処理」として知られているが、ここでは、点を対象とするので、「隠点消去(hidden point removal)処理」となる。OpenCVのprojectPoints関数には、この機能が備わっていないので、これを自作プログラムで補うことにする。
◎回転後の深度データの取得
図1は、objectPointsから深度データを得る方法を示したもので、ベクトル化されたPoint3f型の点群objectPointsの各点につき、マトリックス演算可能なMat型のobjectPointsMatに変換し、Mat型の回転マトリックスrmatと乗算して、視野に応じて回転させられたobjectPoinsMatRotatedを得る。
objectpointsMatRotatedのZ成分が奥行きを示すので、これを抜き出してベクトル化されたfloat型のpoint_depthとする。
以上の計算を、objectPointsの全ての点に対して行う。
図1 objectPointsから、回転後の深度データを得る方法
◎二次元射影画像dst_imageに対する深度データの付加
二次元射影画像dst_image上の座標位置各点に対して、Mat型の深度値格納変数image_depthを用意し、対応する三次元点群の深度データpoint_depthを入れる。これにより、隠点消去(同じ場所に、後から点を上書きしない)を行うかどうかを判断する。
◎プログラムに沿った、隠点消去法の説明(図3を参照)
二次元射影を描画する対象画像としてdst_imageを用意した後、下記を行う。
1)すべての座標位置に対応する深度値格納スペースimage_depthをFLT_MAXで初期化する(20行)。
2)objectPoints点群のうちの射影したい点の深度データpoint_depthをdepth1に入れる(26行)。
3)対応するimagePointsの座標位置の深度値格納スペースimage_depthを読み取り、depth2に入れる(30行)。
4)depth2 > depth1なら、描画しようとする点が一番手前にあるので、それを描画する(31行)。
5)描画した場合には、その座標位置のimage_dataをdepth1で更新する(34行)。
視野角による回転マトリックスの設定
図2に示すように、X軸、Y軸、Z軸ごとの回転は、個々の回転マトリックスで表現できるので、総合的にはこれらのマトリックスを乗算して、全体的な回転マトリックスrmaxとする。図でobjectPointsとあるのは、プログラムで使用する三次元点群との位置関係を示したものである。
図2 XYZ各軸周りの回転マトリックス
作成した三次元点群に回転マトリックスを与えて、二次元画像に射影する
プログラムは、下記から成っている。
1)カメラの内部パラメータとして、理想的なcameraMatrixとdistCoeffsを作成して、用意する(図4)。
2)三次元のobjectPointsと、そのカラーデータobject_colorを設定する(図4)。
3)XYZ各軸の周りの回転角と、objectまでの距離distを設定する(図5)。
4)projectPoints関数を用いて射影を行う(図5)。
5)隠点消去処理の準備のため、objectPointsから深度データpoint_depthを得る(図6、方法は図1)。
6)別途作成したメソッドdrawImagePointsHiddenを用いて、射影された二次元点群を描画する(図6)。
作成したメソッドdrawImagePointsHiddenについては、前記「◎プログラムに沿った、隠点消去法の説明」を参照されたい。
使用したOpenCV関数の説明
calib3d/Camera Calibration and 3D Reconstructionにある。
◎Rodrigues関数
回転マトリックス(3 x 3)と回転ベクトル(3要素)の相互変換を行い、引数は、
src ----------------- 入力として与える回転マトリックス(3 x 3)または回転ベクトル(3)
dst ----------------- 出力として得られる回転ベクトル(3)または回転マトリックス(3
x 3)
jacobian = noArray() --- 出力として得られる差分マトリックスであるが、一般にはデフォルトで良い
であり、戻り値はない。
◎projectPoints関数
三次元物体の点群objectPointsを、二次元画像の点群imagePointsに射影する関数で、引数は、
objectPoints -------- vector<Point3f>型などの、入力する点群の配列
rvec --------------- 3要素の回転ベクトル(回転マトリックスではない)
tvec --------------- 3要素の並進ベクトル
cameraMatrix ------- 焦点距離、中心座標のカメラマトリックス
distCoeffs ---------- 半径方向、接線方向の歪係数マトリックス
imagePoints -------- vector<Point2f>型などの、出力される点群の配列
jacobian = noArray() - 一般的にはデフォルトで良い
aspectRatio = 0 ----- 一般的にはデフォルトで良い
であり、戻り値はない。
図3 隠点消去をしながら二次元画像に射影する自作メソッド
図4 理想的な内部パラメータを作成し、objectPointsとカラーデータを設定する
図5 各軸の回転角と距離を与えて、rvecとtvecを作成し、射影する
図6 隠点消去処理をして結果を描画する
プログラムの実行結果
以下の説明は、図2を参照すると分かり易い。図7はobjectPointsを真横から見た場合で、回転角は、XYZ各軸ともに0である。この場合は、隠点消去の必要がない(しても同じ結果になる)。
図8は、隠点消去をしない場合の結果で、図3のメソッドの32行において、if(true)に書き換えて求めたものである。Y軸、Z軸は回転させず、X軸のみを回転させた。左の図は、θx
= -30で、手前に回転させて上から見た状態、右の図は、θx = 30で、向こう側に回転して下(裏)から見た状態である。隠点消去をしていないので、不自然である。
図9は、同じ条件で隠点消去をした場合で、自然である。
図10は、θx = -30、θy = 30、θz = 5で、XYZ軸ともに回転させて隠点消去した場合で、色々な角度で射影できることが分かる。
図11は、距離を近くして大きく射影した画像の一部を示したもので、点群が荒くなると、隠点消去の効果が得られない。これは、今後に残された問題である。
図7 三次元点群objectPointsを真横から見たところ
図8 隠点消去をしない場合は不自然である
図9 隠点消去をすると、それらしく見える
図10 隠点消去して、XYZ軸全部を回してみた

図11 距離を近づけて点間隔が粗くなると隠点消去が不完全になる
結 論
OpenCVで三次元点群を二次元画像として射影するには、projectPoints関数が用いられる。しかし、これには、元となるobjectPointsに色情報がなく、カラーまたはグレイスケールでの射影ができない。また、隠点消去処理がないため、三次元物体をそれらしく表現することができない。そこで、これらを補うために、色情報を付加し、隠点消去を用いて描画する関数を用意して、自然な射影が得られた。
残された問題は、点群の密度である。密度が低いと隙間ができ、そこでは隠点消去処理ができない。密度を上げると、情報量が大になり、計算時間が増大する。今後の課題として、点群を低密度のままにして、点と点の間を補間で埋める方法を考える必要がある。
「Visual C++の勉強部屋」(目次)へ