修士論文の一環として、Structure From Motion を研究しています。H&Z bookの一部を読み、オンライン チュートリアルに従い、多くの SO 投稿を読んだ後、いくつかの有用な結果が得られましたが、いくつかの問題もあります。OpenCVSharp ラッパーを使用しています。すべての画像は同じカメラで撮影されています。
私が今持っているもの:
最初に、最初の 3d ポイント座標を計算します。私はこれらの手順でこれを行います:
- Farneback の密なオプティカル フローを計算します。
- RANSAC で Cv2.FindFundamentalMat を使用して Fundamental 行列を見つける
カメラの組み込み関数 (この時点では事前に定義された組み込み関数を使用) を使用して Essential マトリックスを取得し、それを分解します。
Mat essential = camera_matrix.T() * fundamentalMatrix * camera_matrix; SVD decomp = new SVD(essential, OpenCvSharp.SVDFlag.ModifyA); Mat diag = new Mat(3, 3, MatType.CV_64FC1, new double[] { 1.0D, 0.0D, 0.0D, 0.0D, 1.0D, 0.0D, 0.0D, 0.0D, 0.0D }); Mat Er = decomp.U * diag * decomp.Vt; SVD svd = new SVD(Er, OpenCvSharp.SVDFlag.ModifyA); Mat W = new Mat(3, 3, MatType.CV_64FC1, new double[] { 0.0D, -1.0D, 0.0D, 1.0D, 0.0D, 0.0D, 0.0D, 0.0D, 1.0D }); Mat Winv = new Mat(3, 3, MatType.CV_64FC1, new double[] { 0.0D, 1.0D, 0.0D, -1.0D, 0.0D, 0.0D, 0.0D, 0.0D, 1.0D }); Mat R1 = svd.U * W * svd.Vt; Mat T1 = svd.U.Col[2]; Mat R2 = svd.U * Winv * svd.Vt; Mat T2 = -svd.U.Col[2]; Mat[] Ps = new Mat[4]; for (int i = 0; i < 4; i++) Ps[i] = new Mat(3, 4, MatType.CV_64FC1); Cv2.HConcat(R1, T1, Ps[0]); Cv2.HConcat(R1, T2, Ps[1]); Cv2.HConcat(R2, T1, Ps[2]); Cv2.HConcat(R2, T2, Ps[3]);
次に、ポイントを三角測量し、それらに投影行列を掛けて (Cv2.TriangulatePoints と H&Z バージョンの両方で同様の結果を試しました)、正の Z 値をチェックすることにより、両方のカメラの前でどの投影行列が最も多くの点を持っているかを確認します (から変換した後)。同種の値):
P * point3D
- この時点で、多かれ少なかれ正しい 3D ポイントが得られるはずです。3D ビジュアライゼーションは非常に正確に見えます。
次に、密なオプティカル フローを再び使用して新しいフレームごとに SolvePNP を計算し、既知の前の射影行列を使用して次の 3D ポイントを計算し、それらをモデルに追加します。ここでも、3D ビジュアライゼーションは多かれ少なかれ正しいように見えます (この時点ではバンドル調整はありません)。
新しいフレームごとに SolvePNP を使用する必要があるため、基本行列を使用して最初の 2 つの画像に対して計算されたものをチェックすることから始めました。理論的には、射影行列は、最初のアルゴリズムで計算されたものと同じか、ほぼ同じになるはずです。最初の 3D ポイントと、2 番目の画像の対応する 2D ポイントを使用します。しかし、それは同じではありません。
基本行列を分解して計算したものを次に示します。
0,955678480016302 -0,0278536127242155 0,293091827064387 -0,148461857222772
-0,0710609269521247 0,944258717203142 0,321443338158658 -0,166586733489084
0,285707870900394 0,328023857736121 -0,900428432059693 0,974786098164824
そして、これが SolvePnPRansac から取得したものです。
0,998124823499476 -0,0269266503551759 -0,0549708305812315 -0,0483615883381834
0,0522887223187244 0,8419572918112 0,537004476968512 -2,0699592377647
0,0318233598542908 -0,538871853288516 0,841786433426546 28,7686946357429
どちらも正しい射影行列のように見えますが、違います。
投稿全体を読んだ辛抱強い人々に、3 つの質問があります。
1. Why are these matrices different? I know the reconstruction is up to scale, but since I have an arbitrary scale assigned in the first place the SolvePNP should keep that scale.
2. I noticed one strange thing - the translation in the first matrix seems to be exactly the same no matter what images I use.
3. Is the overal algorithm correct, or am I doing something wrong? Do I miss some important step?
さらにコードが必要な場合はお知らせください。質問を編集します。
ありがとう!