ステレオ整列(rectification)

ステレオ整列(rectification)は、キャリブレーション済みステレオペアの2枚の画像を、あたかも2台の理想的で平行なカメラから撮影されたかのように見えるようワープする処理である。画像平面は同一平面上に、光軸は平行に、行(row)は整列される。整列後は、左画像内の任意の画素のエピポーラ線は、単純に右画像の同じ行になる。

なぜこれが成立するのか: 任意のカメラ位置のペアについて、エピポーラ幾何は左画像の点のマッチ先を右画像内の1次元曲線(ピンホールカメラの場合は直線)に制約する。整列は、両方のエピポールを水平軸に沿って無限遠に写し、すべてのエピポーラ線を水平かつ垂直に整列させる、画像に適用されるホモグラフィのペアHL,HRH_L, H_Rである。

整列変換の計算方法

キャリブレーション済みの内部パラメータKL,KRK_L, K_R、レンズ歪み、2台のカメラ間の外部パラメータ変換(R,t)(R, t)が与えられたとき、OpenCVのstereoRectifyが使用する古典的な(Bouguetの)構成は以下のように進む。

  1. 相対回転を分割する。 各カメラをRRの「半分」だけ回転させ、両画像へのゆがみを最小限にしつつ、両方の光軸が平行になるようにする。
  2. ベースラインに合わせる。 新しいxx軸がベースラインベクトルttに沿うよう、共通の回転を適用する。これで両方のエピポールは無限遠に位置し、エピポーラ線は水平になる。
  3. 共通の仮想内部パラメータを選ぶ。 両ビューに対して単一の新しいカメラ行列KnewK_{\text{new}}(同じff、同じ主点の行)を選び、整列済みペアがZ=fB/dZ = fB/dのために単一の焦点距離と単一のベースラインを持つようにする。
  4. リマップ表を焼き込む。 カメラごとのワープH=KnewRrectKold1H = K_{\text{new}} R_{\text{rect}} K_{\text{old}}^{-1}は、レンズの歪み補正モデルと組み合わされてルックアップテーブルに事前計算されるため、各フレームの整列コストは単一の画像リマップに帰着する。
R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(K1, D1, K2, D2, size, R, T)
mapLx, mapLy = cv2.initUndistortRectifyMap(K1, D1, R1, P1, size, cv2.CV_32FC1)
mapRx, mapRy = cv2.initUndistortRectifyMap(K2, D2, R2, P2, size, cv2.CV_32FC1)
rectL = cv2.remap(imgL, mapLx, mapLy, cv2.INTER_LINEAR)
rectR = cv2.remap(imgR, mapRx, mapRy, cv2.INTER_LINEAR)

返されるQQ行列は、整列済み画素とディスパリティの組(u,v,d)(u, v, d)を直接3Dへ再投影する — ディスパリティから深度への変換を行列形式で表したものである。

何が得られるか

整列品質の確認方法

簡単な健全性チェック: 整列済み画像間で特徴をマッチングし、垂直ディスパリティvLvRv_L - v_Rを確認する。整列が良好なペアでは、これは1画素の小さな割合であるべきである。系統的なオフセットや画像全体にわたる勾配は、外部パラメータのキャリブレーションがドリフトしたことを意味する。ロボットの稼働寿命にわたって垂直ディスパリティが上昇していくのは、リグがぶつかった、あるいは熱でたわんでいることの典型的な症状である。

実践上の注意点

SLAMにおける意義

ORB-SLAM2のキーポイントごとのステレオマッチング、S-PTAM、Kimeraにおける密なSGMベースのマッピングなど、ほぼすべてのステレオSLAMフロントエンドは整列済み入力を前提としている。なぜなら、走査線探索はリアルタイムのフレームごとの深度を得る唯一の方法だからである。整列の仕組みを理解することは、ステレオパイプラインがどこで破綻するかも教えてくれる。悪いキャリブレーション、同期していないシャッター、魚眼光学系はすべて、SLAMコードが動く前に整列済みモデルへの違反となる。

関連ノート