Pinhole camera model
ピンホールカメラは、SLAMで使われるほとんどのカメラの標準モデルである。3次元点からの光は小さな穴(光学中心)を通過し、画像平面に投影される。このモデルは画像投影(image projection)、すなわち3次元世界の点が2次元ピクセルにどのように対応付けられるかを記述する。
座標系
以下の4つの座標系が関わる:
- ワールド座標系 :固定された基準座標系。
- カメラ座標系 : は光学軸(前方を向く)。
- 画像平面 :画像平面上のメトリック座標。
- ピクセル座標系 :離散的なピクセル座標。
一般的な慣例は が右向き、 が下向き、 が前向きであり、これはピクセル座標 (右)と (下)に対応し、原点は画像の左上隅にある。
投影パイプライン
ステップ1:ワールド座標からカメラ座標へ。 剛体変換(外部パラメータ)がワールド座標点をカメラ座標系に変換する:
ステップ2:カメラ座標から画像平面へ(透視除算)。
この深度による除算が透視効果の源であり ── そしてビジョン幾何学を興味深くしている非線形性の源でもある。座標 は**正規化座標(normalized coordinates)**と呼ばれる:これは内部パラメータを取り除いた後に残るものであり、多くの幾何学的な導出(基本行列、三角測量)はこの座標系で最もシンプルになる。
ステップ3:画像平面からピクセルへ(内部パラメータ)。
ここで はピクセル単位の焦点距離、 は主点である。ピクセル焦点距離は物理的な焦点距離 (mm単位)とピクセルサイズを関連付ける: であり、これがピクセルが正方形でない場合に となる理由である。
行列形式
すべてのステップを斉次座標でまとめると:
行列 は**カメラ内部パラメータ行列(camera intrinsic matrix)であり、 は のカメラ投影行列(camera projection matrix)**である。一般的な場合、 にはスキュー(skew)パラメータが含まれる(現代のカメラでは通常ゼロ)。
このパイプラインをそのままNumPyに翻訳したもの:
import numpy as np
def project(K, R, t, X_w):
X_c = R @ X_w + t # world -> camera
x_n = X_c[:2] / X_c[2] # perspective division (normalized coords)
u = K[0, 0] * x_n[0] + K[0, 2]
v = K[1, 1] * x_n[1] + K[1, 2]
return np.array([u, v])
逆投影:逆写像はレイになる
投影は1次元の情報を失う:1つのピクセルは3次元点を一意に決定せず、1本の**レイ(ray)**のみを決定する。ピクセル が与えられると、カメラ座標系における可能な3次元点のレイは
失われた深度 を復元することこそが、三角測量(複数視点)、ステレオ(もう1台のキャリブレーション済みカメラ)、あるいは深度センサーが提供するものである。視野角も同じ幾何学から導かれる:画像幅 に対して となる。
よくある落とし穴
- 軸の慣例:コンピュータビジョンでは が前方 / が下方だが、ロボティクス(ROS)のボディ座標系では が前方 / が上方である。これを混同することは、カメラをロボットに組み込む際の典型的な最初のバグである。
- 主点は画像中心ではない: は に近いが、キャリブレーションによって求める必要があり、仮定してはならない。
- 手動で投影を実装する際に透視除算を忘れる ── の斉次出力は、その第3成分で除算しなければならない。
- 歪んだピクセルにモデルを適用する:実際の画像はまず歪み補正を行う必要がある(あるいは歪みモデルを に含める)。純粋なピンホールの方程式は理想的な座標にのみ成り立つ。
SLAMにおける意義
このモデルで定義される投影関数 は、すべてのvisual SLAMシステムの核心にある:バンドル調整で最小化される再投影誤差 は、「ピンホールモデルでマップ点を投影し、測定されたピクセルと比較する」ということに他ならない。三角測量、PnP、エピポーラ幾何はすべて同じ方程式から導出されるため、このパイプラインをゼロから導出することは、このレベルで最も価値のある演習である。