2016.10.30.
石立 喬

OpenCV3.1.0とVisual C++ 2015による画像処理と認識(20)

----- tsukuba画像とaloe画像を使って視差マップ(disparity map)を作成する -----

 二つの視点から撮影した二次元画像の間には、被写体の遠近に応じて若干のズレがある。このズレを利用して、三次元物体の深度(depth)を求めることができる。ズレの量を直接画像化したものを視差マップ(depth map)と呼び、StereoBMクラスやStereoSGBMクラスのメソッドで取得できる。
 視差マップの詳細については、「OpenCVとVisual C++による画像処理と認識(20)」に詳しく述べてあるので、ここでは、OpenCV3.1.0になって変わった部分を中心に紹介する。

OpenCV3.1.0で変わったところ
 ここで紹介するクラスは、Camera Calibration and 3D Reconstructionモジュールに属する。
◎StereoMatcher基底クラスができた
 従来のStereoBMクラスとStreoSGBMクラスが、この基底クラスを継承する形になった。視差マップの作成には、従来、StereoBMとStereoSGBMにあった個別のoperator()メソッドを用いていたが、OpenCV3.1.0では、共通してStereoMatcher::compute()を使うことになった。継承関係にあるので、子クラスで、compute()を使用できる。
 従来、StereoSGBM::operator()ではカラー画像が使用できたが、OpenCV3.1.0では、グレイスケールのみのStereoMatcher::compute()を共用するため、使えなくなった。
◎StereoBMクラス
 型がPtr<StereoBM>に変わり、create(生成)メソッドからpresetパラメータが消えた(OpenCV2.4では、presetで、カメラの画角を表すBASIC_PRESETなどを設定していた)。
◎StereoSGBMクラス
 型がPtr<StereoBM>に変わり、create(生成)メソッドで、従来のSADWindowSizeがblockSizeに、fullDPがmodeに変わった。内容的には同じものである。
◎tsukubaステレオ画像が無くなった
 従来、OpenCV2.4では、opencv/sources/samples/cpp/にtsukuba_l.pngとtsukuba_r.pngがあったが、OpenCV3.1.0では、opencv/sources/samples/data/にこれが無くなった。ここでは、ダウンロード済のOpenCV2.4の前記tsukuba画像を使用したが、
   http://s1.bitdownload.ir/Software/Development%26Programing/opencv/doc/pics/
などからダウンロードすることができる。
◎OpenCV3.1.0に備わっているステレオ画像
 OpenCV3.1.0には、ステレオ画像として使用できるものに、opencv/source/samples/data/の下のaloeL.jpgとaloeR.jpg、および、rubberwhale1.pngとrubberwhal2.pngがある。これらは、OpenCV2.4では、opencv/sources/samples/gnu/にあったものである。aloeLとaloeR.jpgは、サイズが1282 x 1110と大きく、ここでは30%に縮小して使用した。rubberwhale1.pngとrubberwhale2.pngは、584 x 388であるが、視差が小さすぎるのか、あまり良い視差マップが得られなかった。

tsukubaステレオ画像を使用して、StereoBMとStreoSGBMで視差マップを作成する
 OpenCV3.1.0の二つのクラス、StereoBMとStereoSGBMについて、デフォルト設定の場合と、最大視差ピクセル数numDisparitiesとブロックサイズblockSizeなどを最適状態に設定した場合の視差マップを求めた。図1はそのプログラムで、下記から成る。
 1)tsukuba_l.pngとtsukuba_r.pngをグレイスケール画像として読み込み、左の画像を原画像として表示する。
 2)StereoBMをデフォルトで用いて視差マップを作成し、表示する。
   ・sbmをデフォルト条件で生成する。
   ・sbm->computeでdisparity_dataを得る。
   ・minMaxLoc関数でdisparity_dataの最小値と最大値を求める
   ・convertTo関数でdisperity_dataの最小値が0に、最大値が255に対応するように線形変換してdisparity_mapを得る。
   ・disparity_mapを表示する(図3左)。
 3)StereoBMのnumDisparotiesとblockSizeを試行錯誤で最適値に設定し、同様な方法で視差マップを表示する(図3右)。
 4)StereoSGBMのnumDisparotiesとblockSizeを、StereoBMの場合と同じに設定し、他はデフォルトで生成し、視差マップを表示する(図4左)。
 5)StereoSGBMで、スペックルフィルタ関連パラメータを試行錯誤で追加設定し、視差マップを表示する(図4右)。

使用したメソッド(OpenCV3.1.0で変わったもののみ)
◎StereoBMクラス
 この生成には下記を使用する。
  StereoBM::create(
    numDisparities = 0 --- int、0はデフォルト値ではなく、デフォルトの意。求める視差の最大値を16の倍数で指定する
                   デフォルト値は48以上と推定される
    blockSize = 21 ------ int、Sum of Absolute Differencesを計算するウィンドウのサイズ、奇数であること、
                   資料には3〜11とあるが、5以上でないとエラーになる、
                   大きいと広範囲で平均化され、小さいと細かくなるが、ノイズに弱くなる。
  )
 blockSizeは、OpenCV2.4ではSADWindowSize(SAD = Sum of Absolute Differences)と呼ばれていたものである。
◎StereoSGBMクラス
 この生成には下記を使用する。
  StereoSGBM::create(
    minDisparity ----------- int、最小視差値、シフト(平行移動)のない場合には0で良い
    numDisparities --------- int、最大視差値と最小視差値の差、16の倍数にする
    blockSize ------------- int、OpenCV2.4では、SADWindowSizeと呼ばれていた、3〜11の奇数、
                        StereoBMと異なり、3から使用できる
    P1 = 0 -------------- int、デフォルトのままで良かった
    P2 = 0 --------------- int、 同上
    disp12MaxDiff = 0 ------ int、 左右の視差の許容最大値、デフォルトはチェックなし、デフォルトで良かった
    preFilterCap = 0 ------- int、 事前にフィルタで大きな視差をクリップする、デフォルトで良かった
    uniquenessRatio = 0 ---- int、目的関数値の次点との差の%比率、0は比較しない意、デフォルトで十分であった
    speckleWindowSize = 0 -- int、小さい斑点やノイズを消すフィルタのサイズ、デフォルトの0は使用しない意、
                        これは使って非常に効果があった。
    speckleRange = 0 ------ int、上記フィルタを使用するときの、視差の最大値、1〜2が推奨で、16倍される、1が良かった
    mode = StereoSGBM::MODE_SGBM ---- int、OpenCV2.4では、fullDP = falseとされていたもの、
          フルスケールの2パス・ダイナミックプログラミングを実行させるには、StereoSGBM::MODE_HHを使用
  )
◎StereoMatcher基底クラス
 このcomputeメソッドを使って、StereoBMやStereoSGBMで視差マップを求めるには、下記メソッドを使用する。
  StereoMatcher::compute(
    left -------- InputArray、左カメラの入力画像、CV_8UC1型(グレイスケール)
    right ------- InputArray、右カメラの入力画像、CV_8UC1型(グレイスケール)
    disparity ---- OutputArray、視差マップの出力配列、入力画像と同じサイズで、CV_16S型、
             実際の値を16倍して整数化してある
  )



図1 StereoBMとStereoSGBMで、tsukuba画像から視差マップを得るプログラム


tsukuba画像で得られた結果
 図2は原画像、図3はStereoBMでの結果である。図3で、左はデフォルト条件を用いたもので、左端が大きく切れており、右は、試行錯誤の結果最適と思われた numDispatities = 16、 blockSize = 15の条件を用いたものである。
 図4はStereoSGBMを使用した場合で、図の左は、StereoBMで得た最適条件の設定以外はデフォルト値を使用している。図の右は、スペックルフィルタを使うために、speckleWindowSize = 200とspeckleRange = 1をデフォルト以外に設定している。これらの値は試行錯誤で求めたものである。


図2 tsukuba_l.pngの原画像



図3 StereoBMのデフォルト(左)と最適設定(右)の結果



図4 StereoSGBMのスペックルフィルタなし(左)とあり(右)の結果


aloeステレオ画像で視差マップを作成した結果
 図1のプログラムで、画像ファイル名をaloeLS.jpgとaloeRS.jpg(それぞれ、aloeL.jpgとaloeR.jpgを30%に縮小したもの)に書き換え、デフォルト以外の設定値を試行錯誤でaloe画像用に変更した。
 図5は原画像、図6はStereoBMでの結果である。図6で、左はデフォルトで、右はnumDispatities = 48、 blockSize = 9に設定した場合てある。
 図7は、スペックフィルタを使用するにあたって、blockSizeを7に小さく設定するコードの追加を示す。blockSizeを小さくすると、ノイズが出やすいが、スペックルフィルタは、これを除去するので、総合的に良い結果が得られる。
 図8はStereoSGBMの結果で、図の左は単純な条件設定(numDisparities = 48,、blockSize = 9以外はデフォルト)の場合、右はスペックルフィルタあり(blockSize = 7に変更)の場合である。
 なお、ここで使用したステレオ画像では、スペックルフィルタの効果は顕著でなかったが、OpenCV2.4を使用した「OpenCVとVisual C++による画像処理と認識(20)」で使用した画像の例では、非常に有効であったことを付記する。


図5 aloeLS.jpgの原画像(グレイ化後)



図6 StereoBMのデフォルト(左)と詳細設定(右)の結果



図7 blockSizeを小さくするコードを追加した



図8 StereoSGBMのスペックルフィルタなし(左)とあり(右)の結果


結 論
 OpenCV3.1.0で変わったところは、StereoMatcher基底クラスができ、視差マップ作成は、このcomputeメソッドを使うことである。StereoBMクラスもStereoSGBMクラスも、この共通メソッドを使うので、StereoSGBMでカラー画像を扱えなくなった。SADWindowSizeがblockSizeに名称が変わったが、内容は同じである。
 tsukuba画像が付属しなくなり、従来gnuフォルダにあったステレオ画像二種がopencv/sources/samples/data/に移された。




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