アルゴリズムは3つのフェイズに分けられる。
まず、与えられた球の画像から光源ベクトルを計算する。estimate_light_direction
に実装した。
この関数は与えられたグレースケールの球画像から、球の直径ともっとも光っている部分の中心を取得し、
Z 方向を加味した光源ベクトルを求める。
球の光っている部分は明度が高い点をとったが、入力が離散値であるためおなじ明るさの点が連続して現れることになった。 そこでおなじ明るさの点の座標を x, y について平均し、中心点として扱うことにした。
次に法線ベクトルを計算する。この方法について、[1]、[2]を参考にした。
この実装では与えられた4つの画像の組をすべてつかうことにした。
calc_normal
は光源 3x4 の光源行列と、題のそれぞれの画像上の点の明度を要素とする 4 要素のベクトルを受け取り、
単位ベクトル化された法線ベクトルを計算する。
最後に、画像の各点にたいして求められた法線から勾配を計算し、それを線積分してある点を起点にした高さを求める。 今回の課題では相対的な高さに重きが置かれているので、高さの調整はおこなわなかった。
高さの計算にはいくつかのアルゴリズムを比較した。
ひとつは独自に考えた方法で、はじめに x=0 および y=0 の行と列の部分を、 (0,0) から勾配を足していくことで求める。 つぎに (x-1,y) と (x,y-1) の座標と、各点から (x,y) への勾配をもとに (x,y) の高さを計算し、平均をとる。
この方法の利点は単純な四則演算を画像全体にたいして1度おこなうだけで計算が完了することである。 復元された画像の出来もそれなりに良く、 hint.txt との比較でも十分な一致を示した。
問題点は、左斜め上で発生した誤差をひきずることである。 右手のブレスレットはおおきく隆起しているが、その後の地の部分がブレスレットの右下だけ不自然にもりあがっている。
これを解決するために左上および右下から同様の方法で計算し、最も低い点を 0 として平均するという方法を試した。 このアルゴリズムではピークが相殺されてつぶれてしまう一方、前のアルゴリズムで見られた問題は解決できず、実用的ではなかった。
次に文献[3]で提案されている手法を試した。基本的には複数の線積分を行い、平均をとるという手法である。 具体的には、ある点を起点とし、そこから x 方向に u まで積分してから y 方向に v まで積分した値と、y 方向に v まで積分してから x 方向に u まで積分した値の平均をとった。 この方法は行、列ごとで値を積算するので、 x が大きくなると、 y = v の行と y = v+1 の行の高さの差がおおきくなる。 ギザギザの激しい出力となり、これ以前に示した手法よりも劣悪な結果になった。
これまでの手法はどれも、法線ベクトルからもとめた勾配の線積分に基礎づいている。 積分の性質として誤差がつみかさなっていくので、全体の高さをもとめると周囲から影響をうけるのであった。
最後に[4]で提案されているフーリエ変換をもちいてペナルティ関数の最小値をもとめるアプローチを試した。 提出したプログラムはこの方法で実装している。 この方法ではたしかに全体的に誤差のすくない、凹凸にとんだ結果がえられた。 hint.txt との比較でも、一部に関係のない揺れがあるものの、ピークの位置はよくあっていることが確認できた。
しかし、何箇所か問題のある箇所があり、アルゴリズムが複雑なため、それをピンポイントで修復することができなかった。
具体的には右足の膝より下が輪郭だけ立上ってほかの部分が平らになってしまっていることや、全体が波打っていることが指摘される。
後者は実際には小さな値である出力を normalize
によって拡大しているためだろうが、前者については原因がわからなかった。
Ubuntu 12.04 32bit で動作を確認。
dist
ディレクトリを作成し、配布物にふくまれる bmp 画像と hint.txt をいれる。make
でコンパイルする。OpenCV2、OpenGL、GLUT が必要。./solver
で実行すると、result.txt
が作成される。
-
行列やベクトルをつかった演算をくりかえし行う必要があるので、ライブラリを使用した。 画像の読み書きなどにも便利な OpenCV2 を C++ から利用した。
-
出力がひとめで確認できるように、求めた法線ベクトルおよび座標をプログラムの最後で表示する機能を OpenGL で実装し、組み込んだ。 この機能はコマンドライン引数をなにかひとつ渡して実行することで有効になる。
-
gnuplot を利用し、行ごとに与えられたヒントと自分のプログラムの出力を比較した。 これによりピークの位置がずれていないか、大体の推移が合致しているかなどを容易に確認できた。 生成スクリプトは
compare.rb
として同梱している。
この課題にとりくむうえで最も困難だったのは、照度差ステレオ法によって取得された精度が十分でない法線ベクトルから、 実際に面の高さを積分する過程だった。 この問題を解決するために次のような方法が考えられる。
-
別の装置によって信頼できる高さを測定する。 法線ベクトルによってそれを補完することで、画像全体で誤差が積算されることが回避できる。
-
より高度な高さを計算するアルゴリズムを採用する。 いくつかの論文を調査したが、今回採用した FT を利用するものよりはるかに性能が高そうなものはなかった。 しかし、被写体や画像によっていくつかの手法を選択したり、組み合わせることは効果的であろう。
-
高さではなく、法線ベクトルを利用する。 たとえば目的が撮影された物体を描画することならば、法線ベクトルのみから陰影のついたテクスチャを生成することができる。 バンプマッピングされた物体とおなじく、横からみると平たくなってしまうが、もともと集みのないレリーフのようなものであれば、 誤差の多い高さを求めるよりも効果的な場合もある。
画像認識や統計解析の分野では常であるが、実際に照度差ステレオ法を適用する場合には、 その出力をなにに利用するかを考えて実装法を検討する必要がある。
- 川嶋宏彰 "コンピュータビジョン 第9回 Photometric stereo 他" http://vision.kuee.kyoto-u.ac.jp/~hiroaki/computervision/2009_1204_computervision.pdf
- "Computer Vision: Photometric Stereo" http://pages.cs.wisc.edu/~lizhang/courses/cs766-2008f/syllabus/10-09-shading/shading.pdf
- ZHONGQUAN Wu AND LINGXIAO Lx "A Line-Integration Based Method for Depth Recovery from Surface Normals" Pattern Recognition, 1988., 9th International Conference on , vol., no., pp.591,595 vol.1, 14-17 Nov 1988.
- Tiangong Wei, Reinhard Klette "Depth Recovery from Noisy Gradient Vector Fields Using Regularization" Computer Analysis of Images and Patterns Lecture Notes in Computer Science Volume 2756, 2003, pp 116-123 2003.
また、次のサイトをプログラム実装のさいに参考にした。
Welcome to opencv documentation! — OpenCV 2.4.5.0 documentation opencv: Main Page GLUTによる「手抜き」OpenGL入門