web-dev-qa-db-ja.com

4つの共面点に基づくホモグラフィマトリックスを使用したカメラポーズの計算

ビデオ(または画像)に4つの(同一の正方形または長方形である必要はありません)を表す4つの同一平面上のポイントがあり、それらの上部に仮想キューブを表示できるようにしたいビデオクワッドの。

点は同一平面上にあるため、単位正方形(つまり[0,0] [0,1] [1,0] [1,1])の角と四角形のビデオ座標との間のホモグラフィを計算できます。

このホモグラフィから、正しいカメラポーズ、つまり[R | t]を計算できるはずです。ここで、Rは3x3回転行列で、tは3x1の平行移動ベクトルであるため、仮想キューブはビデオクワッド上にあります。

私は多くのソリューション(SOでそれらのいくつか)を読み、それらを実装しようとしましたが、いくつかの「単純な」ケース(ビデオクワッドが正方形の場合など)でのみ動作するようですが、ほとんどの場合は動作しません。

私が試した方法は次のとおりです(それらのほとんどは同じ原理に基づいており、翻訳の計算のみがわずかに異なります)。 Kをカメラからの組み込み行列、Hをホモグラフィとしましょう。計算します:

A = K-1 * H

A1、a2、a3をAの列ベクトルとし、r1、r2、r3を回転行列Rの列ベクトルとします。

r1 = a1 / ||a1||
r2 = a2 / ||a2||
r3 = r1 x r2
t = a3 / sqrt(||a1||*||a2||)

問題は、ほとんどの場合、これが機能しないことです。結果を確認するために、RとtをOpenCVのsolvePnPメソッドで取得したものと比較しました(次の3Dポイント[0,0,0] [0,1,0] [1,0,0] [1,1 、0])。

キューブを同じように表示するため、すべての場合でsolvePnPが正しい結果を提供するのに気付きましたが、ホモグラフィから取得したポーズはほとんど間違っています。

理論上、私のポイントは同一平面上にあるため、ホモグラフィから姿勢を計算することは可能ですが、Hから姿勢を計算する正しい方法を見つけることができませんでした。

私が間違っていることに関する洞察はありますか?

@ Jav_Rockのメソッドを試してから編集

こんにちはJav_Rock、あなたの答えをどうもありがとう、多かれ少なかれ大丈夫だと思われるあなたのアプローチ(および他の多くも同様)を試しました。それにもかかわらず、4つの同一平面上の点に基づいてポーズを計算するときに、まだいくつかの問題があります。結果を確認するために、solvePnPの結果と比較します(反復再投影エラー最小化アプローチにより、はるかに改善されます)。

以下に例を示します。

cube

  • 黄色のキューブ:PNPを解く
  • ブラックキューブ:Jav_Rockのテクニック
  • シアン(およびパープル)キューブ:まったく同じ結果が得られる他のテクニック

ご覧のとおり、黒い立方体は多かれ少なかれ大丈夫ですが、ベクトルは正規直交に見えますが、バランスが取れているようには見えません。

EDIT2:(正規直交性を強制するために)計算後にv3を正規化し、いくつかの問題も解決するようです。

44
JimN

ホモグラフィがある場合は、次のようなものでカメラポーズを計算できます。

void cameraPoseFromHomography(const Mat& H, Mat& pose)
{
    pose = Mat::eye(3, 4, CV_32FC1);      // 3x4 matrix, the camera pose
    float norm1 = (float)norm(H.col(0));  
    float norm2 = (float)norm(H.col(1));  
    float tnorm = (norm1 + norm2) / 2.0f; // Normalization value

    Mat p1 = H.col(0);       // Pointer to first column of H
    Mat p2 = pose.col(0);    // Pointer to first column of pose (empty)

    cv::normalize(p1, p2);   // Normalize the rotation, and copies the column to pose

    p1 = H.col(1);           // Pointer to second column of H
    p2 = pose.col(1);        // Pointer to second column of pose (empty)

    cv::normalize(p1, p2);   // Normalize the rotation and copies the column to pose

    p1 = pose.col(0);
    p2 = pose.col(1);

    Mat p3 = p1.cross(p2);   // Computes the cross-product of p1 and p2
    Mat c2 = pose.col(2);    // Pointer to third column of pose
    p3.copyTo(c2);       // Third column is the crossproduct of columns one and two

    pose.col(3) = H.col(2) / tnorm;  //vector t [R|t] is the last column of pose
}

この方法は私から機能します。幸運を。

30
Jav_Rock

Jav_Rockによって提案された答えは、3次元空間でのカメラポーズの有効なソリューションを提供しません。

ホモグラフィによって引き起こされる木次元の変換と回転を推定するために、複数のアプローチが存在します。 そのうちの1つ は、ホモグラフィを分解するための閉じた式を提供しますが、非常に複雑です。また、ソリューションは決してユニークではありません。

幸いなことに、OpenCV 3はすでにこの分解を実装しています( decomposeHomographyMat )。ホモグラフィと正確にスケーリングされた組み込み行列が与えられると、この関数は4つの可能な回転と平行移動のセットを提供します。

9
Emiswelt

誰かが必要とする場合に備えてpython @Jav_Rockによって書かれた関数の移植:

def cameraPoseFromHomography(H):
    H1 = H[:, 0]
    H2 = H[:, 1]
    H3 = np.cross(H1, H2)

    norm1 = np.linalg.norm(H1)
    norm2 = np.linalg.norm(H2)
    tnorm = (norm1 + norm2) / 2.0;

    T = H[:, 2] / tnorm
    return np.mat([H1, H2, H3, T])

私の仕事でうまくいきます。

8

ホモグラフィマトリックスからの[R | T]の計算は、Jav_Rockの答えよりも少し複雑です。

OpenCV 3.0には、cv :: decomposeHomographyMatと呼ばれる4つの潜在的なソリューションを返すメソッドがあり、そのうちの1つが正しいです。ただし、OpenCVは正しいものを選択する方法を提供しませんでした。

私は現在これに取り組んでおり、今月中にコードをここに投稿するかもしれません。

6
Yang Kui

画像にスクエアを含む平面には、カメラの消失車線エージェントがいます。この線の方程式はA x + B y + C = 0です。

飛行機の法線は(A、B、C)です!

P00、p01、p10、p11がカメラの固有パラメーターを適用した後の点の座標であり、同種の形式であるとします。例えば、p00 =(x00、y00,1)

消失線は次のように計算できます。

  • down = p00 cross p01;
  • 左= p00クロスp10;
  • 右= p01クロスp11;
  • up = p10クロスp11;
  • v1 =左と右の交差。
  • v2 = up cross down;
  • vanish_line = v1 cross v2;

ここでcrossは標準ベクトル外積で

0
DejanM