5

修士論文の一環として、Structure From Motion を研究しています。H&Z bookの一部を読み、オンライン チュートリアルに従い、多くの SO 投稿を読んだ後、いくつかの有用な結果が得られましたが、いくつかの問題もあります。OpenCVSharp ラッパーを使用しています。すべての画像は同じカメラで撮影されています。

私が今持っているもの:


最初に、最初の 3d ポイント座標を計算します。私はこれらの手順でこれを行います:

  1. Farneback の密なオプティカル フローを計算します。
  2. RANSAC で Cv2.FindFundamentalMat を使用して Fundamental 行列を見つける
  3. カメラの組み込み関数 (この時点では事前に定義された組み込み関数を使用) を使用して 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]);
    
  4. 次に、ポイントを三角測量し、それらに投影行列を掛けて (Cv2.TriangulatePoints と H&Z バージョンの両方で同様の結果を試しました)、正の Z 値をチェックすることにより、両方のカメラの前でどの投影行列が最も多くの点を持っているかを確認します (から変換した後)。同種の値):

    P * point3D
    
  5. この時点で、多かれ少なかれ正しい 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?

さらにコードが必要な場合はお知らせください。質問を編集します。

ありがとう!

4

3 に答える 3

7

まず、説明した 2 つのアプローチがまったく同じ射影行列を提供する可能性が低い理由が 1 つあります。どちらも、ランダム性に基づくアルゴリズムである RANSAC を使用して結果を推定します。どちらのアプローチも、対応関係の一部をランダムに選択して、対応関係の大部分に適合するモデルを推定するため、結果は選択された対応関係に依存します。

したがって、両方のアプローチでまったく同じ射影行列を取得することは期待できません。ただし、すべてが問題なければ、かなり近いはずですが、そうではないようです。あなたが示した 2 つのマトリックスの変換は非常に異なっており、おそらくもっと深刻な問題があることを示しています。

まず、「最初の行列の翻訳は、使用する画像に関係なくまったく同じように見える」という事実は、実装にバグがある可能性があるという強力な手がかりのようです。まずはこれを詳しく調べることをお勧めします。

次に、Structure From Motion ワークフローでオプティカル フローを使用することは適切ではないと思います。実際、オプティカル フローでは、考慮される 2 つの画像が非常に近い (ビデオの 2 つの連続するフレームなど) 必要がありますが、2 つの画像の対応する点の 3D 三角測量では、正確にするために大きなベースラインが必要です。これら 2 つの要件は相反するものであり、結果に問題や不正確さをもたらす可能性があるため、2 つのアプローチの異なる結果を説明しています。

たとえば、検討する 2 つの画像が 2 つの連続するビデオ フレームである場合、ポイントを正確に三角測量することができず、手順 4 で間違った射影行列が選択される可能性があり、間違った射影行列がSolvePnP推定される可能性もあります。一方、考慮している 2 つの画像のベースラインが大きい場合、三角測量は正確ですが、オプティカル フローにはおそらく多くの不一致があり、ワークフロー全体にエラーが発生します。

問題の原因を理解するためにできることの 1 つは、既知の射影行列と 3D ポイントを含む合成データを使用することです。次に、各ステップの精度を分析し、期待どおりの結果が得られるかどうかを確認できます。

于 2014-08-30T18:26:47.680 に答える
1

私はこのパーティーに少し遅れていることを知っていますが、あなたの 2 つのアプローチの根本的な違いを指摘したいと思います。エッセンシャル マトリックスから取得したカメラ ポーズは最大スケールですが、solvePnP から取得したカメラ ポーズはワールド単位である必要があります。つまり、エッセンシャル マトリックスから得られる並進ベクトルは単位ベクトルであり、solvePnP から得られる並進ベクトルの大きさは、カメラと座標系の原点との間の実際の距離に近いはずです。

于 2015-12-22T15:36:28.630 に答える
1

この問題の解決に成功しなかったことを皆に知らせるために書いています。結果が正しくないことを知っていたにもかかわらず、基本行列の初期三角形分割を使用し、SolvePnP を使用しました。これは完全な解決策ではありませんが、うまくいく場合もあります。私のプロジェクト全体が受け入れられ、卒業するのに十分でした:)

于 2014-11-29T18:06:56.977 に答える