2015. 7.27.
2015. 8. 1.  プログラム上で、「視野マップ」→「視差マップ」、出力結果も変更
        図12のためのスペックルフィルタの条件を追加
2015.10.10. 「視差マップ」と「深度マップ」を明確に区別
石立 喬

OpenCVとVisual C++による画像処理と認識(20)

----- Tsukuba標準画像その他を使って視差マップ(disparity map)を作成する -----

 二つの視点から撮影した二次元画像の間には、被写体の遠近に応じて若干のズレがある。このズレを利用して、三次元物体の深度(depth)を求めることができる。ズレの量を直接画像化したものを視差マップ(depth map)と呼び、深度情報との間に反比例の関係があるので、深度の代わりに用いられることもある。ここでは、まず、著名な標準であるTsukuba画像について、OpenCVの二つのクラスを用いて、色々な条件で視差マップを求め、視差マップのカラー化や、その他の画像の使用についても紹介する。

視差マップ(disparity map)
 左右の二つのカメラ画像の部分的な横方向のズレを表したもので、ズレの大きい部分を白く、小さい部分を黒く、段階的に表示する。ズレが大きいことは、その部分が近距離(手前)にあることを意味し、被写体の遠近情報を表す。深度マップ(depth map)と似ているが、表現している内容は異なる。視差と深度は、反比例の関係にある。用途としては、ロボットの物体位置把握、ジェスチャの認識、撮影後のout of focus処理などがある。
◎視差(disparity)と深度(depth)の関係
 図1に示すように、二台のカメラCameraLとCameraRが水平に配置され、向き(principal ray)が平行になっているとすると、視差xl + xr から、被写体までの距離dが求まる。ただし、基線長l(baseline length) と焦点距離f(focal length)が必要である。視差と焦点距離はピクセル数で表す。

図1 視差から距離を求める方法


◎精度上の問題点
 35mmフィルムの場合、フィルム上の画像サイズは、幅36mm、高さ24mmであった。カメラレンズの焦点距離を35mm(準広角)とすると、画像の幅と焦点距離を同一と考えても良い。
 したがって、320ピクセルx240ピクセルの画像を、一般的なレンズで撮影したものとすると、焦点距離は320ピクセルと考えられる。二つのカメラ間の距離(baseline)を20cm(0.2m)とし、被写体までの距離を10mとすると、
   画像上の視差は、 320ピクセル x 0.2m / 10m = 6.4ピクセル となる。
 つまり、サブピクセルオーダーの精度が必要になる。このことは、画像サイズが大きい方が好ましいことを意味し、事前のカメラ特性補正や、マッチング探索においてのサブピクセル処理の重要性を示唆している。

マッチング点の探索方法(stereo matching algorithms)
 視差を求めるには、二つの画像上の、どの点とどの点を対応させるかが問題である。繰り返しのある部分や、テクスチャの無い部分、さらには遮蔽(occlusion)部分もある。また、話を単純にするために、画像は、あらかじめ、カメラ固有の特性が較正(calibration)されていて、位置補正(rectification)されていることを前提とする。、
 探索方法には、大別して、高速処理が可能なローカル法と、精度は良いが時間がかかるグローバル方がある。現在のOpenCVは、リアルタイム応用を考えて高速性を重んじ、ローカル法を中心にしている。StereoBM(ブロックマッチング)クラスは、ローカル法の一つであるブロックマッチングを標準的に使用し、StereoSGBM(セミグローバル・ブロックマッチング)クラスは、ブロックマッチングの形式を採りながらも、評価方法を変え、グローバルな情報を加味して、グローバル法並の性能を得ている。
 結論として、高速性を追求するならStereoBMを、照明変化や遮蔽にも強いことを望むならばStereoSGBMになる。

Tsukuba標準画像
 OpenCVで視差マップを作成する場合に、有名な画像がある。これは、日本の筑波大学が作成し、提供しているtsukuba画像「Head and Lanp」のtsukuba画像で、OpenCVの提供するファイルにも含まれている。単純にカメラで撮影した自然画像ではなく、人為的に作られているため、コンピュータービジョンの研究に欠かせない。世界的に、多くの論文が、これを用いて成果を発表している標準画像である。
 グレイスケール画像は、opencv/sources/samples/cpp/tsukuba_l.pngとtsukuba_r.pngに、カラー画像は、opencv/sources/samples/gpu/tsucuba_left.png と tsucuba_right.png にある(名称がtsucubaになっているのに注意)。サイズは、いずれも、348 x 288である。

Tsukuba標準画像を使用して、StereoBMとStreoSGBMでの最適条件を探索する
 OpenCVの二つのクラス、StereoBMとStereoSGBMについて、デフォルト設定条件はそのままに尊重し、最大視差ピクセル数とブロックサイズのみをいろいろと設定して、それらの効果を調べた。
◎StereoBMの場合
 図2はStereoBMクラスによる場合のプログラムで、下記から成る。
 1)tsukuba_l.pngとtsukuba_r.pngのグレイスケール画像を読み込む。グレイスケールに変換しないと、エラーになる。
 2)最大視差ピクセル数とブロックサイズを、それぞれ3種類選んで視差マップを表示させる。
   ・StereoBMクラスのインスタンスを生成する。
   ・operator()で、CV_16S型のdisparity_dataを求める。
   ・disparity_dataの最小値と最大値を求める
   ・disperity_dataの最小値が0に、最大値が255になるように線形変換して、CV_8UC1型のdisparity_mapにする。
   ・disparity_mapを表示する。
 図3は得られた結果で、ブロックサイズが小さいと細部までマッチングが取れるが、ノイズが増大する。最大視差ピクセル数を大きくすると、画面左側に、マッチングの取れない領域が増えてくる。この画像の場合は、最大視差ピクセル数を最小にして良い結果が得られた。
◎StereoSGBMの場合
 プログラムの図示は省略するが、変更部分を下記に示す。
 1)tsucuba_left.pngとtsucuba_right.pngのカラー画像を読み込む。
 2)最大視差ピクセル数とブロックサイズを、それぞれ3種類(StereoBMの場合と若干異なる)選んで視差マップを表示させる。
   ・StereoSGBMクラスのインスタンスを生成する。
     StereoSGBM ssgbm = StereoSGBM(0, 16 * (i + 3), 9 + j * 4);
 図4は得られた結果で、ブロックサイズの影響はStereoBMより少なく、最大視差ピクセル数を大きくしても、画面左側に、マッチングの取れない領域が増えない。一方、最大視差ピクセル数を減らすと、視差の大きい部分が、かえって小さくなるエラーが発生した(下記参照)。
◎Tsukuba画像の不思議
 理由が良く分からないが、グレイスケールのtsukuba画像と、カラーのtsucuba画像には大きな違いがあった。StereoBM(グレイスケール化して使用)でも、StereoSGBMでも、tsukuba画像は最大視差ピクセル数を16とするのが良く、tsucuba画像は16では全くダメで、StereoBMでも、StereoSGBMでも、48~64にする必要があった。ブロックサイズは、同じで良かった。

使用したOpenCV関数の説明
 特記しないものは、calib3d/Camera Calibration and 3D Reconstructionにある。
◎StereoBMクラス
 ブロックマッチング法で視差マップを求めるためのクラスで、コンストラクタに用いるパラメータには、
  preset ---------------- 別途紹介する各種パラメータを一括してセットするのに使用する
  ndisparities = 0 --------- 探索したいdisparitiesの最大値を、16の倍数で指定する
  SADWindowSize = 21----- Sum of Absolute Differencesを計算するウィンドウのサイズ、最大21の奇数
があり、実行メソッドにoperator()がある。
 presetには、
  BASIC_PRESET ----- 一般的なレンズのカメラ用
  FISH_EYE_PRESET --- 広角レンズのカメラ用
  NARROW_PRESET --- 望遠レンズのカメラ用
がある。
 StereoBM::operator()メソッドの引数には、下記がある。
  left --------------- 左カメラの入力画像、CV_8UC1型
  right -------------- 右カメラの入力画像、CV_8UC1型
  disparity ----------- 視差マップの出力配列、入力画像と同じサイズ
  disptype = CV_16S --- 視差の出力配列の型を指定する、一般的には、このままで良い。
 クラスのパラメータを別途設定するには、Ptr<CvStereoBMState> stateを使って、sbm.state->(パラメータ名)を使用する。
 preset = BASIC_PRESETの場合の各パラメータを調べてみたところ、下記の通りであった。これらの意味については、後述のStereoSGBMで説明する。
  sbm.state->minDisparity ---------- デフォルト値は0
  sbm.state->numberOfDisparities --- コンストラクタで与えた通りになっている
  sbm.state->SADWindowSize ------- コンストラクタで与えた通りになっている
  sbm.state->preFilterCap ---------- デフォルト値は31
  sbm.state->disp12MaxDiff --------- デフォルト値は-1
  sbm.state->uniquenessRatio ------- デフォルト値は15
  sbm.state->speckleWindowSize ----- デフォルト値は0
  sbm.state->speckleRange --------- デフォルト値は0
◎StereoSGBMクラス
 セミグローバルブロックマッチング法で視差を求めるためのクラスで、コンストラクタに用いるパラメータには、
  minDisparity ------------- 最小視差値、一般には0で良い
  numDisparities ----------- 最大視差値と最小視差値の差、16の倍数にする
  SADWindowSize ---------- Sum of Absolute Differencesを計算するウィンドウのサイズ、3~11の奇数を推奨
  P1 = 0 ----------------- 値の決め方が示されているが、デフォルトのままで良かった
  P2 = 0 ----------------- 同上
  disp12MaxDiff = 0 -------- 左右の視差の許容最大値、デフォルトはチェックしない、デフォルトで良かった
  preFilterCap = 0 ---------- 事前にフィルタで大きな視差をクリップする、デフォルトで良かった
  uniquenessRatio = 0 ------ 目的関数値の次点との差の%比率、0は比較しない意、デフォルトで十分であった
  speckleWindowSize = 0 ---- 小さい斑点やノイズを消すフィルタのサイズ、0のデフォルトは使用しない意、これは
                     使って非常に効果があった。
  speckleRange = 0 -------- 上記フィルタを使用するときの、視差の最大値、1~2が推奨で、16倍される、1が良かった
  fullDP = false ------------ フルスペックのダイナミックプログラミングを行わないのがデフォルト、trueにしても大差はなかった
があり、メソッドにoperator()がある。
 上記パラメータの内、speckleWindowSizeの設定は、非常に有効であった。周期的なテクスチャによる細かい偽の視差の発生に対して、これを除去するのに役立った。推奨値は50~200とある。
StereoSGBM::operator()関数の引数には、下記がある。
  left ------------ 左カメラの入力画像、CV_8UC1型またはCV_8UC3型(カラー)
  right ----------- 右カメラの入力画像、CV_8UC1型またはCV_8UC3型(カラー)
  disp ----------- 視差マップの出力配列、入力画像と同じサイズで、CV_16S型、実際の値を16倍して整数化してある
◎minMaxLoc関数(core.The Core Functionalityにある)
 一次元配列の最小値、最大値、それらの場所を求める関数で、引数は、
  src --------------- 入力配列
  minVal ------------- 最小値の出力へのポインタ
  maxVal ------------ 最大値の出力へのポインタ
  minLoc = 0 --------- 最小値の位置へのポインタ
  maxLoc = 0 --------- 最大値の位置へのポインタ
  mask = noArray() ----  一般的には使用しない
で、戻り値はない。
◎Mat::convertTo関数(core.The Core Functionalityにある)
 元の配列の各要素をalpha倍して、betaを加算する関数で、引数は、
  m --------------- 出力配列
  rtype ------------ 出力配列の型、負数にすると入力配列と同じになる
  alpha = 1.0 -------- 入力値に対する倍数、スケールファクタ
  beta = 0.0 --------- 入力値に対するバイアス
であり、戻り値はない。


図2 StereoBMで、設定値の目安をつけるためのプログラム


 図3は得られた結果で、視差の最大値が16で、ブロックサイズが15の場合が総合的に良かった。

ndisparities
= 16
ndisparites
= 32
ndisparities
= 48
  左から、SADWindowSize = 9、15、21の順           

図3 StereoBMで設定を変えた結果


num
Disparities
= 48
num
Disparities
= 64
num
Disparities
= 80
  左から、SADWindowSize = 9、13、17の順   

図4 StereoSGBMで設定を変えた結果


StereoBMとStereoSGBMのデフォルト以外の設定
 これらの二つのクラスでは、最大視差ピクセル数とブロックサイズをコンストラクタで設定するが、それ以外のパラメータは、個別に設定する。
 StereoBMの場合には、StereoBMクラスのsbmに対して、
   sbm state->spackleWindowSize = 100;
 StereoSGBMの場合には、StereoSGBMクラスのssgbmに対して、
   ssgbm.speckleWindowSize = 100;
のように記述する。
 デフォルト設定されている多くのパラメータは、大体そのままでも十分であったが、スペックル(speckle、斑点)フィルタを使うと、ノイズが顕著に改善されるので、speckleWindowSizeとspeckleRangeを別途設定した。

視差マップのヒストグラム等化(平坦化)とカラー表示
 視差マップを一層見やすくするために、以下の処理を追加した。
◎ヒストグラムの等化
 視差マップでは、視差のズレを濃度0(黒)から255(白)の間で表すのが一般的である。しかし、ズレの分布は一様でなく、集中している付近では分離が悪い。そこで、視差のズレに忠実な表現を犠牲にして、equalizeHist関数を使ってヒストグラムを等化(平坦化)し、見やすくした。
◎カラー表示
 視差のズレを、グレイスケールの濃淡ではなく、カラーの違いで表現した。ズレを表す濃度の255(白)~0(黒)を色相(hue)の0(赤)~127(青)に対応させ、彩度(saturation)と明度(value)は255に固定してHSV画像hsv_mapを作成し、
   cvtColor(hsv_map, rgb_map, CV_HSV2BGR);
でRGBカラー画像rgb_mapに変換した。
 視差と色の関係は、以下のようになる。
    大   ←   視差   →   小
    近い  ←   距離   →  遠い
    赤 → 黄 → 緑 → シアン → 青
 この処理は、図5に示すように、changeToHueColorメソッドとしてプログラム化した。  図5の22行で求めるdは、視差の最小値に対して0、最大値に対して255になるので、23行の右辺で、視差の最小値に対しては 色相 = 127(青)、最大値に対しては 色相 = 0(赤)になるように換算する。


図5 カラー表示のメソッド


Tsukuba標準画像を使用して、StereoBMとStreoSGBMで視野マップをカラー表示する
 OpenCVの二つのクラス、StereoBMとStereoSGBMについて、最適と思われる条件設定を行い、スペックルフィルタでノイズを除去し、ヒストグラム等化とカラー化を行った
◎StereoBMの場合
 図6はStereoBMクラスによる場合のプログラムで、下記から成る。
 1)tsukuba_l.pngとtsukuba_r.pngのグレイスケール画像を読み込む。
 2)StereoBMクラスのインスタンスを生成する。
 3)sbm.state->speckleWindowSizeなどで、スペックルフィルタを設定する。
 4)operator()で、CV_16S型のdisparity_dataを求める。
 5)disparity_dataの最小値と最大値を求める
 6)disperity_dataの最小値が0に、最大値が255になるように線形変換して、CV_8UC1型のdisparity_mapにする。
 7)disparity_mapのヒストグラムを等化する。
 8)changeToHueColor()で、カラー化する。
 9)disparity_mapを表示する。

 図7は得られた結果である。


図6 StereoBMの最適条件でカラー表示するプログラム



図7 StereoBMによる結果


◎StereoSGBMの場合
 図8はStereoSGBMクラスによる場合で、プログラムは下記(StereoBMと異なる部分のみ記載)から成る。
 1)tsucuba_left.pngとtsucuba_right.pngのカラー画像を読み込む。
 2)StereoSGBMクラスのインスタンスを生成する。
 3)ssgbm.speckleWindowSizeなどで、スペックルフィルタを設定する。

 図9は得られた結果である。


図8 StereoSGBMの最適条件でカラー表示するプログラム



図9 StereoSGBMによる結果


Tsukuba画像以外での実行結果
 図10は、自分で撮影した画像で、「・・・による画像処理と認識(19)」で使用したものの一部である。撮影時に、高さと向きに十分注意し、位置補正(rectification)は行っていない。精度を重視するために、サイズをやや大きめの480x360ピクセルとした。
 視差マップ作製にはStereoSGBMを用い、numDisparities = 48、SADWindowSize = 5とした。後者を小さく選んだのは、細部の精度を高め、代償として生じるノイズは、スペックルフィルタで除去したためである。
 図11は、デフォルト設定のままで、スペックルフィルタを使わない場合、図12はスペックルフィルタを設定した場合(speckleWindowSize = 300、 speckleRange = 1)の結果を比較のために示す。


図10 使用した原画像(左)



図11 スペックルフィルタを使わない場合



図12 スペックルフィルタを使った場合


結 論
 OpenCVに備わっている視野マップ作成用クラスには、StereoBMとStereoSGBMの二種類があるが、後者の方が、グローバルなデータも利用しているので、明るさの変化や、遮蔽部分などの影響を受けにくく、優れている。
 視差マップは特定の被写体を認識するものではなく、それに接している等距離の物体も一体化してしまう恐れがあり、被写体の形状把握が困難である。また、テクスチャのはっきりしないもの、テクスチャがあっても周期性のあるもの、遮蔽部分のあるもの等に対しては、色々な工夫がされているものの、苦手な対象である。
 しかし、これらの障害によって生じるノイズに対しては、スペックルフィルタが効果的であった。
 あらかじめ、各画像の関連を位置補正(rectification)しておくことが推奨される。しかし、これには、まず基礎配列を取得する必要があり、通常の画像では、得られた基礎配列の信頼性が著しく低いため、正しく位置補正できなかった。結局、撮影時に、カメラ配置(高さ、前後、向きなど)の位置精度にに十分気を配ることが、最善の方法であった。



参考文献
 D.Scharstein and R.Szeloski, "A Taxonomy and Evaluation of Dense Two-Frame Stereo Correspondence Algorithms"(2002)
 http://vision.middlebury.edu/stereo/taxonomy-IJCV.pdf

 H. Hirschmueller, "Stereo Processing by Semiglobal Matching and Mutual Information"(2008)
 http://core.ac.uk/download/pdf/11134866.pdf

 S.Birchfield and C. Tomasi, "Depth Discontinuities by Pixel-toPixel Stereo"(1998)
 http://www.ces.clemson.edu/~stb/publications/p2p_iccv1998.pdf

 F.Tombari and K. Konolige, "A Practical Stereo System Based on Regularization and Texture Projection"(2009)
 http://vision.deis.unibo.it/fede/papers/icinco09.pdf

 S. Martull, M. Peris and K. Fukui, "Realistic CG Image Dataset with Ground Truth Disparity Map"(2012)
 http://ypcex.naist.jp/trakmark/workshop12/2012wsproc/pdfs/Martull.pdf


「Visual C++の勉強部屋」(目次)へ