Structure from Motion とは
structure from motion (SfM) は、一連の 2 次元イメージから 3 次元シーンの構造を推定するプロセスです。SfM は、3 次元スキャン、拡張現実、および Visual simultaneous localization and mapping (vSLAM) など、多くのアプリケーションで使用されています。
SfM は多くの異なる方法で計算することができます。問題に取り組む方法は、使用するカメラの台数やタイプ、イメージが順序付けられているかどうかなど、さまざまな要素によって異なります。キャリブレーションされた単一のカメラでイメージが撮影される場合、"スケールに沿った" 3 次元構造とカメラの動きのみを復元できます。"スケールに沿った" とは、構造とカメラの動きの大きさを再スケーリングしながら、測定値をそのまま維持できることを意味します。たとえば、カメラをオブジェクトの近くに置くと、オブジェクトを拡大してカメラを遠ざけたときと同じイメージを確認できます。構造と動きの実際のスケールをワールド単位で計算するには、以下のような追加情報が必要になります。
シーンにおけるオブジェクトのサイズ
別のセンサーからの情報 (たとえば走行距離計など)
2 つのビューからの structure from motion
2 つの静止カメラまたは 1 つの移動カメラからの構造という単純なケースでは、1 つのビューがカメラ 1、もう一方のビューがカメラ 2 と見なされます。このシナリオでは、カメラ 1 が原点にあり、その光学軸は z 軸に沿っているとアルゴリズムによって仮定されます。
SfM は、イメージ間の点の対応関係を必要とします。イメージ 1 からイメージ 2 へと、特徴のマッチングまたは点の追跡を行って対応点を見つけます。Kanade-Lucas-Tomasi (KLT) アルゴリズムなどの特徴追跡手法は、各カメラの位置が近い場合にうまく機能します。カメラの位置が遠くなるにつれ KLT アルゴリズムは機能しなくなり、代わりに特徴のマッチングが使用できるようになります。
カメラ間の距離 (ベースライン) 点の対応関係の判定手法 例 遠い matchFeatures
を使用した特徴のマッチ自動特徴マッチングを使用したイメージの回転とスケールの検出 近い vision.PointTracker
を使用した特徴の追跡KLT アルゴリズムを使用した顔の検出と追跡 カメラ 1 に対するカメラ 2 の姿勢を求めるには、基礎行列を計算しなければなりません。前の手順で見つけた対応点を使用して計算します。基礎行列は 2 つのカメラのエピポーラ幾何を記述します。これにより、一方のカメラでの点がもう一方のカメラのエピポーラ線に関連付けられます。関数
estimateFundamentalMatrix
を使用して基礎行列を推定します。基礎行列を関数
estrelpose
に入力します。estrelpose
は、カメラ 1 の座標系におけるカメラ 2 の姿勢を返します。スケールに沿った位置のみが計算できるため、2 つのカメラ間の距離は 1 に設定されます。つまり、カメラ間の距離が 1 単位になるように定義されます。triangulate
を使用して、マッチする点の 3 次元での位置を決定する。姿勢はスケールに沿うため、構造を計算すると形状は正しくなりますが、実際のサイズは得られません。関数
triangulate
では 2 つのカメラ行列を使用しますが、これは関数cameraProjection
を使って計算できます。pcshow
またはpcplayer
を使用して、再構成を表示します。plotCamera
を使用して、カメラの姿勢を視覚化します。
再構成のスケールを復元するには追加情報が必要です。スケールを復元する 1 つの手法は、シーン内でサイズが既知のオブジェクトを検出することです。2 つのビューからの structure from motionの例では、シーンの点群で既知サイズの球体を検出してスケールを復元する方法を説明します。
複数のビューからの structure from motion
ロボティクスや自動運転など、ほとんどのアプリケーションにおいて SfM は 3 つ以上のビューを使用します。
2 つのビューからの SfM で使用したアプローチは、複数のビューへと拡張できます。SfM で使用する複数のビューのセットには、順序を付けることも付けないことも可能です。ここでのアプローチでは、ビューのシーケンスが順序付けられていると仮定します。複数のビューからの SfM では、"トラック" と呼ばれる、複数のイメージにわたる点の対応関係が必要です。一般的な手法では、ペアごとの点の対応関係からトラックを計算します。imageviewset
を使用してペアごとの対応関係を管理し、トラックを求めることができます。各トラックは、そのシーンにおける 3 次元点に対応します。トラックから 3 次元点を計算するには triangulateMultiview
を使用します。3 次元点は、worldpointset
オブジェクトに保存できます。worldpointset
オブジェクトは、カメラ ビュー全体の 3 次元の点と 2 次元イメージ ポイントの間の対応についても保存します。
2 つのビューからの SfM におけるアプローチを使用して、カメラ 1 に対するカメラ 2 の相対的な姿勢を求めることができます。このアプローチを複数のビューの場合へと拡張するには、カメラ 2 に対するカメラ 3 の相対的な姿勢を求め、他のカメラについても同様にします。相対的な姿勢は、共通の座標系に変換しなければなりません。通常は、すべてのカメラの姿勢をカメラ 1 に対して計算し、すべての姿勢が同じ座標系のものとなるようにします。imageviewset
を使用してカメラの姿勢を管理できます。imageviewset
オブジェクトは、ビューおよびビュー間の接続を格納します。
各カメラの姿勢の推定には、1 つのビューと次のビューとの間で誤差が含まれます。その誤差は、イメージ内の点の不正確な位置情報、ノイズを含んだ一致および不正確なキャリブレーションから生じます。これらの誤差はビューの数が増えるにつれて累積され、"ドリフト" 効果と呼ばれています。ドリフトを減らす 1 つの方法は、カメラの姿勢と 3 次元点の位置を調整することです。関数 bundleAdjustment
によって実装される "バンドル調整" と呼ばれる非線形最適化アルゴリズムを使用して調整することが可能です。bundleAdjustmentMotion
を使用して、3 次元点の位置を修正し、カメラの姿勢のみを調整できます。また、bundleAdjustmentStructure
を使用して、カメラの姿勢を修正し、3 次元点の位置のみを調整することもできます。
ドリフトを減らす別の方法は、imageviewset
オブジェクトに対して "姿勢グラフの最適化" を使用することです。ループ閉じ込みが検出されたら、imageviewset
オブジェクトに新しい接続を追加し、関数 optimizePoses
を使用して、相対姿勢によって制約されたカメラの姿勢を調整します。
2 つのビューからの structure from motionの例では、2 次元ビューのシーケンスから 3 次元のシーンを再構成する方法を説明しています。この例ではカメラ キャリブレーターアプリを使用して、ビューを撮影するカメラのキャリブレーションを行います。imageviewset
オブジェクトを使用して各ビューに関連付けられたデータの格納と管理を行います。
単眼の Visual Simultaneous Localization and Mappingの例では、単眼カメラのイメージ データを処理して、屋内環境のマップを作成し、カメラの動きを推定する方法を説明します。
参考
アプリ
関数
bundleAdjustment
|bundleAdjustmentStructure
|bundleAdjustmentMotion
|estrelpose
|cameraProjection
|triangulateMultiview
|estimateFundamentalMatrix
|matchFeatures