ステレオデプスの設定

私たちのステレオデプスノードは非常に細かく設定できます。この資料では、ベストな結果を得るための設定とトラブルシューティングについて説明します。

以下、6つの章に分かれています。

  1. ステレオデプスの基本

  2. ノイズの多い深度の修正

  3. 深度精度の向上

  4. 近距離ステレオ深度

  5. 長距離ステレオ深度

  6. ノイズの多い点群の修正

1. ステレオデプスの基本

ステレオデプスビジョンは、わずかに異なる点から撮影された2つの画像間の視差を計算することで動作します。

ステレオビジョンは、私たちの目とよく似た働きをします。私たちの脳は(無意識のうちに)、左目が見ているものと右目が見ているものとの差に基づいて、物体や景色の深度を推定します。OAK-Dカメラでもまったく同じで、(ステレオカメラペアの)左右のカメラによって、OAKデバイス上で視差マッチングを行い、物体や風景の深度を推定します。

視差とは、ステレオペアの左右の画像の対応する2点間の距離のことです。

視差からの深度

深度は以下の公式によって得られます:

\[depth[mm] =f_{x}[px] \cdot baseline[mm]/disparity[px]\]

例えば、OAK-D(ベースライン7.5cm OV9282)を使用し、解像度400P、視差50ピクセルの場合、

\[depth = 441.25 \cdot 7.5/50 = 66.19[cm]\]

となります。

RVC2ベースのカメラの視差探索範囲は0~95であり、それは最小の深度認識を制限します。ベースラインはステレオカメラペアの2台のカメラ間の距離です。カメラの焦点距離 $f_{x}$ (ピクセル単位)はキャリブレーションから読み取ることができます(チュートリアルはこちら)。

視差と深度は反比例の関係にあります。視差が小さくなると、深度はベースラインと焦点距離に応じて指数関数的に増加します。つまり、視差の値がゼロに近い場合、視差のわずかな変化が深度に大きな変化を生みます。同様に、視差の値が大きければ、視差が多少変化しても深度の大きな変化にはつながりません(精度が向上)。

以下は、OAK-D(基線距離7.5cm)の800Pでの視差と深度の関係を表したグラフです:

詳細なグラフはこちら

深度データの値はuint16で保存され、0は距離が無効/不明であることを意味します。

ベースラインの距離と焦点距離が深度に与える影響

上の深度を算出する公式を見ると、ベースラインの距離が大きいか、焦点距離が大きいほど、同じ視差でも深度が遠くなり、深度の精度が良くなることがわかります。 焦点距離とは、カメラレンズとイメージセンサー間の距離のことです。焦点距離が大きいほど、FOVは狭くなります。

したがって、遠距離の深度認識を得るためには、ベースラインの距離を長くするか、FOVを狭くすれば良いことになります。

注:FOV が広いと、(精度の低下が目立たない)短い距離でも深度の精度が悪くなります。

2. ノイズの多い深度の修正

ステレオの深度品質に関連する、いくつかのトピックを紹介します:

  • 風景のテクスチャ
  • ステレオ深度信頼閾値
  • ステレオカメラペアノイズ
  • ステレオ後処理フィルタ

風景のテクスチャ

ステレオマッチングアルゴリズムが機能する方法上、パッシブステレオデプスは、風景に良好なテクスチャがあることが必要であり、そうでない場合、深度はノイズ/無効となります。すなわち、壁や床など、視覚的関心の低いサーフェス(テクスチャがほとんどない空白のサーフェス)の場合です。

解決策:プロバージョンのOAKカメラにはIRレーザードットプロジェクターが搭載されており、これは風景上に何千もの小さなドットを投影し、風景により多くのテクスチャを加えるため、ステレオマッチングアルゴリズムに役立ちます。

私たちが使用している技術はASV(Conventional Active Stereo Vision)と呼ばれ、ステレオマッチングはデバイス上でパッシブステレオのOAK-Dと同じように実行されます。

ステレオ深度信頼度閾値

視差を計算するとき、視差マップの各ピクセルは、ステレオマッチングアルゴリズムによって信頼値0~255を割り当てられます。この信頼度スコアは、(たとえば、ニューラルネットワークの信頼度と比較する場合)数値の大小とは反対になっています。

  • 0:最大信頼度。有効な値を有しています。
  • 255:最小信頼度。値が正しくない可能性が高いです。

最終的な視差マップでは、信頼度の閾値に基づいてフィルタリングが適用され、信頼度のスコアが閾値よりも大きいピクセルは無効にされます、つまり、それらの視差の値はゼロに設定されます。信頼度閾値は以下のAPIで設定できます。

  1. Pythonの場合
# Create the StereoDepth node
stereo_depth = pipeline.create(dai.node.StereoDepth)
stereo_depth.initialConfig.setConfidenceThreshold(threshold)

# Or, alternatively, set the Stereo Preset Mode:
# Prioritize fill-rate, sets Confidence threshold to 245
stereo_depth.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
# Prioritize accuracy, sets Confidence threshold to 200
stereo_depth.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_ACCURACY)
  1. C++の場合
// Create the StereoDepth node
auto stereo_depth = pipeline.create<dai::node::StereoDepth>();
stereo_depth->initialConfig.setConfidenceThreshold(threshold);

// Or, alternatively, set the Stereo Preset Mode:
// Prioritize fill-rate, sets Confidence threshold to 245
stereo_depth->setDefaultProfilePreset(dai::node::StereoDepth::Preset::HIGH_DENSITY);
// Prioritize accuracy, sets Confidence threshold to 200
stereo_depth->setDefaultProfilePreset(dai::node::StereoDepth::Preset::HIGH_ACCURACY);

つまり、信頼度の閾値によって、ユーザーはフィルレートや精度を優先させることができます。

ステレオカメラペアのノイズ

左右の入力画像にノイズがあると、視差マップにもノイズが入ります。そのため、良好な深度の値を得るためには、IQ(画質に関するドキュメント(翻訳済み)を参照)の高い左右のステレオ画像が前提条件となります。アクティブステレオ(OAKカメラのProバージョン)はこの問題をほとんど軽減しますが、パッシブステレオカメラの場合、ステレオカメラペアの品質を向上させるために以下を試してみてもいいでしょう。

モノ(グレースケール)カメラは、カラー(ベイヤー)フィルターがないため量子効率 (QE)が良く、ステレオカメラのペアに使用するのが望ましいです。QEが高いということは、同じ量の光(光子)に対してより多くの信号が生成されることを意味し、SNR(信号対雑音比)の向上につながります。

低照度下での性能を向上させるには、SNRを向上させるため、ゲイン(ISO)を高くする代わりに露光時間を長くすることをお勧めします(30FPSなら1/30秒、15FPSなら1/15秒といったように)。詳しくは、低照度での感度向上(翻訳済み)を参照してください。

また、クロマとルーマのデノイズやシャープネスのようなセンサーのISP設定を微調整することで改善する可能性があります。詳しくはカラーカメラのISP設定(翻訳済み)を参照してください。

ステレオ後処理フィルタ

StereoDepthノードには、デバイス上で実行されるいくつかの後処理フィルタがあり、これを有効にすることで、視差マップの品質を向上させることができます。実装(API)の詳細については、StereoDepth設定可能ブロックを参照してください。詳しくは、Depth Post-Processing の例を参照してください。

これらのフィルタはデバイス上で実行されるため、ある程度の性能コストがかかります。つまり、高解像度フレーム(1MP)では、これらがFPSのボトルネックになる可能性があります。コストを改善するには、低解像度フレーム(例えば400P)やデシメーションフィルタ(後述)の使用を検討する必要があります。付加的な処理のため、これらのフィルターはまた追加のレイテンシを引き起こします。

専門的な内容も含むため、それぞれのフィルタについては各自でよく調べられることをお勧めします。

メディアンフィルタ

これはエッジを保存しないメディアンフィルタで、ノイズを減らして深度マップを滑らかにするのに使えます。メディアンフィルタはハードウェアで実装されており、 最も高速なフィルタです。

スペックルフィルタ

スペックルフィルタはスペックルノイズを低減するために使用されます。スペックルノイズは、隣接する視差/深度ピクセル間の大きなばらつきのある領域のことで、スペックルフィルタはこの領域を除外します。

テンポラルフィルタ

テンポラルフィルタは、前のフレームに基づいてピクセルごとの値を操作することにより、深度データの持続性を向上させることを目的としています。このフィルタはデータに対してシングルパスを実行し、深度値を調整すると同時にトラッキング履歴を更新します。

ピクセルデータが欠損していたり無効な場合、フィルタはユーザー定義の持続性モードを使用し、欠損値を保存されたデータで改善すべきかどうかを決定します。履歴データに依存するため、このフィルタはモーションブラーや不鮮明な画像の乱れを引き起こす可能性があることに注意してください。(静的なシーンには適しています)

空間フィルタ

空間エッジ保存フィルタは、無効な深度ピクセルを有効な隣接深度ピクセルで埋めます。再構成データの滑らかさを向上させるために、一連の水平方向と垂直方向の一次元のパスまたは反復を実行します。この研究論文に基づいています。

明るさフィルタ

明るさフィルタは、入力ステレオカメラ画像のピクセルが、設定された最小/最大明るさの閾値から外れているすべての深度ピクセルを除外(0に設定して無効にする)します。このフィルタは、明るい日の屋外など、高いダイナミックレンジのシーンがあるときや、ステレオカメラペアが光源を直視する場合に有効です:

直接光源(天井照明) - 深度ピクセルが無効になっています

また、画像の乱れの修正、特にワイドFOVレンズを使用していてalphaパラメータを適用している場合にも役立ちます。利用可能なピクセルがない場合、StereoDepthノードはデフォルトでその領域を 0(黒)に設定しますが、 stereoDepth.setRectifyEdgeFillColor(int8) で変更できます。この黒い領域は、以下のように、明るさフィルタで無効にすることができます:

深度を無効にし、画像の乱れを修正する

デシメーションフィルタ

デシメーションフィルタは深度マップをサブサンプリングし、深度シーンの複雑さを減らし、他のフィルタをより速く実行できるようにします。デシメーションファクタを2に設定すると、1280x800の深度マップを640x400にダウンスケールします。ピクセルスキッピング、中央、平均デシメーションモードのいずれかを選択でき、後者2つのモードはフィルタリングにも役立ちます。 また、点群データ(後述)にも便利です。

閾値フィルタ

閾値フィルタは、設定された最小/最大閾値外にあるすべての深度ピクセルを除外します。コントロールされた環境下で、背景がどのくらいの距離(例えば30cm~2m)離れているか正確に分かっている場合には、このフィルタを使うことをお勧めします。

3. 深度精度の向上

上記の章ではノイズに焦点を当てましたが、それだけが深度が不正確な理由ではありません。 深度の精度を向上させる方法はいくつかあります:

  • ノイズのある深度を修正する(前述
  • ステレオ深度信頼度の閾値を低くする(前述
  • カメラを対象物に近づける
  • ステレオサブピクセルモードを有効にする(特に、オブジェクトやシーンがカメラのMinZに近くない場合)

カメラを対象物に近づける

上術した視差からの深度のグラフを見ると、視差95ピクセル(至近距離)では、視差ピクセル間の深度変化(たとえば95→94)が最も小さく、深度精度が最も高いことが分かります。

上のグラフのように、深度の精度は、カメラからの距離によって指数関数的に低下します。ステレオサブピクセルモード(下記)を有効にすると、(より長い距離でも)より良い深度精度が得られますが、それはある程度までしか機能しないことに注意してください。

結論として、最高の深度精度を得るためには、測定するオブジェクト/シーンはカメラのMinZ(最小深度知覚)にできるだけ近い必要があります。各デバイスのMinZ仕様は、ハードウェアのドキュメントで確認できます。

ステレオサブピクセルモード

まず、ステレオサブピクセルモードとは何か、どのように機能するのかから説明します。画像サブピクセルの説明については、サブピクセルとはを参照してください。

:ステレオデプスパイプラインは非常に複雑(StereoDepthノードの内部ブロック図を参照)であるため、ここでは理解を深めるために簡略化します。実際には信頼度(stereoDepth.confidenceMap出力など)は使わず、信頼度の計算に使われるコストダンプを利用します。

視差深度を計算するとき、ステレオマッチングアルゴリズムは各視差ピクセルに「信頼度」を割り当てます。これは、深度画像の各ピクセルが96バイト(信頼度として)であることを意味します。これらすべてのコスト値に興味がある場合は、stereoDepth.debugDispCostDump出力を使用できます。ただ、非常に大きな出力(たとえば、各フレームで 1280x800x96 => 98MB)であることに注意してください。

ステレオサブピクセルモードでは、各方向に隣接する2つの視差ピクセルの信頼度を見ることによって、サブピクセル視差を計算します。上の例のグラフでは、通常モードでは、StereoDepthは最大視差=34ピクセルを取得するだけですが、サブピクセルモードでは、ピクセル35と36の信頼度もかなり高いので、もう少し多い値(たとえば34.375ピクセル)を返します。

TL;DR: ステレオサブピクセルモードは常により正確な深度を取得するはずですが、追加のHWリソースを消費します(影響についてはStereo depth FPSを参照してください)。

レイヤーのステレオサブピクセル効果

デフォルトのステレオ深度出力には0~95の視差ピクセルがあり、これは96の固有の深度値を生成します。これは特に点群表現を使用するときや、連続的ではない点の離散的な「レイヤー」がどのように存在するかを確認するときに見られます:

このレイヤー化は、レイヤー同士が指数関数的に離れている、より長い距離の場合に特に現れます。 しかし、ステレオサブピクセルモードを有効にすると、より多くの固有な値が存在可能になり、より粒度の細かい深度ステップが生成され、点群データがより滑らかになります。

# Number of unique values based on subpixel bits setting
unique_values = 94 * 2 ^ subpixel_bits + 2 [min/max value]
\[94 \cdot 2^3 + 2 = 754\] \[94 \cdot 2^4 + 2 = 1506\] \[94 \cdot 2^5 + 2 = 3010\]

stereoDepth.setSubpixelFractionalBits(int)パラメータを 3 ビット、4 ビット、5 ビットに設定することで、サブピクセルビット数を変更することができます。

4. 近距離ステレオ深度

正確な近距離深度を得るには、まず3で説明した深度精度の向上のステップに従う必要があります。ほとんどのノーマルFOVのOV9282 OAK-D カメラの場合、対象物/シーンをカメラから約70cm離すと、誤差が2%以下になる(風景のテクスチャが良好な場合)ため、誤差は±1.5cmに収まります。

しかし、より良い深度精度、例えばサブcmステレオの深度精度を得るにはどうしたらいいでしょうか?上述の「ベースラインの距離と焦点距離が深度に与える影響」で学んだように、基線距離を近くするか、FOVの狭いレンズを用意したいところです。

基線距離が2cmで800Pの解像度を持ち、1mまでの深度検知に理想的なOAK-D SRの使用をお勧めするのはそのためです。

「視差から深度」に戻ると、最小深度知覚(MinZ)は、視差を95ピクセル(視差探索の最大ピクセル数)として、以下の式で定義されます。

\[depth = focalLength \cdot baceline/disparity\] \[MinZ = focalLength \cdot baseline/95\]

MinZを低くする方法

近接オブジェクトの深度結果がおかしい場合、距離がOAKカメラのMinZ以下である可能性が高いです。OAKカメラのMinZを下げるには以下の方法があります:

  • 解像度を下げる
  • ステレオ拡張視差モードを有効にする
  • 視差シフトを使用する(MaxZがわかっているコントロールされた環境で行うことをお勧めします)

これらの最後の2つの方法は同時に有効にすることができ、最小深度を標準設定の1/4に設定することができますが、このような短い距離では、MinZは焦点距離によって制限される可能性があります。

解像度を下げてMinZを下げる

上記でMinZの計算式がありましたが、解像度を下げるということは、焦点距離を(ピクセル単位で)下げるということです。もう一度計算式を見てみましょう:

\[MinZ = focalLength \cdot baseline/95\] \[MinZ[800P] = 882.5 \cdot 7.5/95 = 70[cm]\] \[MinZ[400P] = 441 \cdot 7.5/95 = 35[cm]\]

ご覧のように、解像度を半分に下げることで、MinZも半分に下げています。この場合、画素数が少なくなるため、深度精度(cm)も低くなることに注意してください。

ステレオ視差拡張モード

解像度を下げてMinZを下げるのとよく似ていますが、拡張モードはステレオデプスパイプラインを2回実行します(したがって、より多くのHWリソースを消費します)。すなわち、StereoDepth ノードに渡されたフレームの解像度で1回、解像度を半分に縮小して1回実行し、2つの出力視差マップを結合します。

視差シフト

MaxZがあらかじめわかっているコントロールされた環境では、より近距離の深度範囲を認識するために、視差シフトを使用することをお勧めします。

視差シフトは、視差探索の開始点をずらすので、MaxZは大幅に減少しますが、MinZも減少します。視差シフトは、拡張/サブピクセル/LRチェックモードと組み合わせることができます。

左のグラフは、OAK-D(ベースライン7.5cm、解像度800P、HFOV〜70°)のデフォルト(視差シフト=0)での最小・最大視差と深度を示しています。上述の「視差からの深度」を参照してください。 ハードウェア(ステレオブロック)の視差探索は95ピクセルに固定なので、DepthAIは0ピクセル(depth=INF)から95ピクセル(depth=71cm)まで探索します。

右のグラフは同じですが、視差シフトを30ピクセルに設定した場合です。つまり、視差探索は30ピクセル(深度=2.2m)から125ピクセル(深度=50cm)までとなリます。これは、近距離では深度が非常に正確になることを意味します(理論的には深度の誤差は5mm以下)。

  • 視差と深度の間には負の相関があるため、視差シフトを大きくすると、MaxZはMinZよりも急激に減少します。したがって、必要以上に大きな視差シフトを使用しないことを推奨します。
  • この方法でMinZを減らすと、今度はMaxZより遠い距離にあるオブジェクトが見えなくなることもあります。
  • 上記の点から、MaxZが既知の場合にのみ視差シフトを使用することを推奨します。例えば、テーブルの上に取り付けられたデプスカメラがテーブルの表面を見下ろすような場合です。
  • 出力視差マップは展開されず、深度マップのみが展開されます。したがって、視差シフトが50に設定され、得られた視差値が90の場合、実際の視差は140となります。

視差拡張モードと比較すると、視差シフトは

  • 余分な計算を必要としないため、より高速で、余分な待ち時間もない
  • MaxZを(大幅に)減少させるが、視差拡張モードはMinZを減少させるだけである

なお、視差シフトは視差拡張モードと組み合わせることができます。

StereoDepthConfig &dai::StereoDepthConfig::setDisparityShift(int disparityShift)

最小の深度を増加させるために、入力フレームをピクセル数だけシフトします。例えば48だけシフトすると、有効視差探索範囲が(0,95]から[48,143]に変わります。 MinZを減らす別のアプローチです。通常、MaxZより遠くのオブジェクトが存在しないことが分かっている場合にのみ、この方法を推奨します。例えば、テーブルの上にデプスカメラを取り付け、テーブルの表面を見下ろすような場合です。

近距離での深度の制限

深度は視差から計算され、ピクセルの重なりが必要ですが、左モノラルカメラの左側と右モノラルカメラの右側は1台のステレオカメラでしか見えないため、深度を計算できない部分が必ず存在します。非常に近い距離では、上述のステレオ視差拡張モードや解像度を下げた場合でも、この無効な深度ピクセルの部分に気づくはずです。

上の画像における変数の意味:

  • BL [cm] - ステレオカメラのベースライン
  • Dv [cm] - 両方のカメラがオブジェクトを見る最小距離(したがって、深度の計算が可能)
  • W [pixels] - モノラルカメラのピクセル幅、または水平方向のピクセル数(他の計算式ではHPixelsとも表記される)
  • D [cm] - カメラ面から対象物までの距離(こちらの画像を参照)

tan関数を使うと、以下の式が得られます:

\[F = 2 \cdot D \cdot tan(HFOV/2)\] \[D_v = BL/2 \cdot tan(90 - HFOV/2)\]

Bを求めるには、再びtan関数を使うことができます(Fの場合と同じ)が、今度は単位をピクセルに変換するために、WFの比をかける必要があります。つまり、次の式が得られます:

\[B = 2 \cdot D_v \cdot tan(HFOV/2) \cdot W/F\] \[B = 2 \cdot D_v \cdot tan(HFOV/2) \cdot W/(2 \cdot D \cdot tan(HFOV/2))\] \[B[pixels] = W \cdot D_v/D\]

たとえば、HFOVが72°、ベースライン(BL)が7.5cm、解像度が640x400(400P)のOAK-Dを使用すると、W = 640となります。ここで、対象物までの距離がD = 100 cm の場合、Bは以下のように計算できます:

\[D_v = 7.5/2 \cdot tan(90 - 72/2) = 3.75 \cdot tan(54°) = 5.16[cm]\] \[B = 640 \cdot 5.16/100 = 33[pixel]\]

※この計算と画像は、コミュニティのメンバーであるgregflurryがこのフォーラムの投稿で作成したものです。

5. 長距離ステレオ深度

正確な遠距離深度を得るには、まず3の「深度精度の向上」のステップをチェックしてください。それらは遠距離深度にも適用できるからです。

また、遠距離の深度については、以下のことも考慮する必要があります:

  • FOVの狭いレンズ
  • ステレオカメラ間のベースライン距離が長い

そのため、基線距離が15cmで、デフォルトのFOVが60°のOAK-D LRを使用することをお勧めします。OAK-D LRにはM12マウントレンズがあり、ユーザーはこれをさらに狭い(または広い)FOVレンズに交換することができます。

6. ノイズの多い点群の修正

ノイズの多い点群への対応として、いくつかの手法を提案します:

  • 「2.ノイズの多い深度の修正」の章から始める。そうしないと、ノイズが点群のあちこちにさらに点を生成してしまうからです。
  • 「3.深度精度の向上」の章を続ける。 深度精度の不正確さは点群で簡単に確認することができます。
    • ステレオサブピクセルモードを有効にする。主にステレオサブピクセル効果のためです。
  • 点群用のデシメーションフィルタを使用し、より高速な処理(FPS)と追加フィルタリングを行う。(後述
  • コーナー付近のピクセルを無効にすることで、深度フレームのコーナー付近のノイズを減らす。(後述
  • ホスト側の点群フィルタリングによる追加フィルタリングを行う。(後述

点群用デシメーションフィルタ

デシメーションフィルタは点群に対して特に有用です。100万点のデータ処理は多すぎるのでやりたくないでしょう。デシメーションフィルタはこのような場合に役立ちますので、点群データを扱うときは有効にしてください。

点群にデシメーションフィルタを使うときは、中央/平均デシメーションモードを有効にしてください。また、処理するデータが少なくなるため、他のステレオ後処理フィルタの処理速度も速くなります。

コーナー付近ピクセルの無効化

コーナー付近には無効なピクセルやノイズの多いピクセルがあることが多いため、深度画像のコーナー付近の数ピクセル(例えば3ピクセル)を予防的に無効化しているユーザーも見受けられます。また、特に「画像の乱れ」の防止のために、明るさフィルタを有効にすることをお勧めします。

ホスト側の点群フィルタリング

デバイス側のステレオ後処理フィルタに加えて、ホスト側の点群フィルタリングを実行することをお勧めします(Open3DPCLライブラリなど)。

特に点群のVoxel化と統計的外れ値の除去手法を使用することをお勧めします。それらの例はこちらを参照してください。

質問がありますか? 技術サポートやその他の質問については、ディスカッションフォーラムへどうぞ。


出典 : Luxonisの資料 - Configuring Stereo Depth

https://docs.luxonis.com/projects/api/en/latest/tutorials/configuring-stereo-depth/

*このガイドはLuxonis社の許可を得て、スイッチサイエンスが翻訳しています。


◀︎一覧に戻る