6

私は opencv と openframeworks (つまり、opengl) を使用して、画像 (および後で三角測量のためのいくつかの画像) からカメラ (世界の変換行列と投影行列) を計算しています。

opencv の目的上、「フロア プラン」は、世界の中心が 0,0,0 のオブジェクト (つまり、チェス盤) になります。世界/床の位置はわかっているので、投影情報 (歪み係数、fov など) とカメラの外部座標を取得する必要があります。

2D 入力座標

これらのフロアプラン ポイントのビュー位置を、正規化されたビュー空間の 2D イメージにマッピングしました ([0,0] は左上、[1,1] は右下)。

オブジェクト(フロアプラン/ワールドポイント)はxz平面、-yアップ上にあるため、平面である必要があるため、opencvのxy平面に変換します(zアップが負か正かはわかりません...)

ofMatrix4x4 gWorldToCalibration(
    1, 0, 0, 0,
    0, 0, 1, 0,
    0, 1, 0, 0,
    0, 0, 0, 1
    );

ImageSize として 1,1 を calibrationCamera に渡します。フラグがCV_CALIB_FIX_ASPECT_RATIO|V_CALIB_FIX_K4|CV_CALIB_FIX_K5 calibrateCamera正常に実行され、エラーが少なくなります (通常は約0.003)。

を使用するcalibrationMatrixValuesと、通常は約 50 度の適切な FOV が得られるため、固有のプロパティが正しいと確信しています。

ここで、カメラの外部ワールド空間変換を計算します... オブジェクトが 1 つしかないので、使用する必要はないと思いsolvePnPます (ただし、以前にこれをすべて試して、同じ結果で戻ってきました)。

//  rot and trans output...
cv::Mat& RotationVector = ObjectRotations[0];
cv::Mat& TranslationVector = ObjectTranslations[0];

//  convert rotation to matrix
cv::Mat expandedRotationVector;
cv::Rodrigues(RotationVector, expandedRotationVector);

//  merge translation and rotation into a model-view matrix
cv::Mat Rt = cv::Mat::zeros(4, 4, CV_64FC1);
for (int y = 0; y < 3; y++)
   for (int x = 0; x < 3; x++) 
        Rt.at<double>(y, x) = expandedRotationVector.at<double>(y, x);
Rt.at<double>(0, 3) = TranslationVector.at<double>(0, 0);
Rt.at<double>(1, 3) = TranslationVector.at<double>(1, 0);
Rt.at<double>(2, 3) = TranslationVector.at<double>(2, 0);
Rt.at<double>(3, 3) = 1.0;

これで、回転と変換の行列が得られましたが、それは列優先です (転置しないとオブジェクトが完全に歪んでいると思います。上記のコードは列優先に見えます)。

//  convert to openframeworks matrix AND transpose at the same time
ofMatrix4x4 ModelView;
for ( int r=0;  r<4;    r++ )
    for ( int c=0;  c<4;    c++ )
        ModelView(r,c) = Rt.at<double>( c, r ); 

前の逆行列を使用して、平面を座標空間 (y を上) に戻します。

//  swap y & z planes so y is up
ofMatrix4x4 gCalibrationToWorld = gWorldToCalibration.getInverse();
ModelView *= gCalibrationToWorld;

これを行う必要があるかどうかわかりません...キャリブレーションに入れるときに飛行機を無効にしませんでした...

//  invert y and z planes for -/+ differences between opencv and opengl
ofMatrix4x4 InvertHandednessMatrix(
    1,  0,  0, 0,
    0,  -1, 0, 0,
    0,  0,  -1, 0,
    0,  0,  0,  1
    );
ModelView *= InvertHandednessMatrix;

そして最後に、モデルビューはオブジェクト相対カメラであり、カメラ相対オブジェクト(0,0,0)になるように反転したい

ModelView = ModelView.getInverse();

出力 3D ビュー

これにより、カメラが間違った場所に配置され、間違った回転が行われます。それほど離れていません。カメラは Y 平面の右側にあり、変換は大幅にずれていません。正しい方法だと思います....まだ正しくありません。ペイントで描かれた青い円は、カメラがあると予想される場所です。

私はたくさんのSO回答、ドキュメントを何十回も調べましたが、正しいものは何も見つかりませんでした。スペース変換に関して必要なすべてをカバーしたと確信していますが、明らかな何かを見逃している可能性があります? それとも間違った順序で何かをしていますか?

更新 1 - ワールド空間平面... openCV の入力と一致するように、ワールド空間のフロア平面を XY(Z アップ) に変更しました。(gWorldToCalibration は恒等行列になりました)。回転はまだ間違っており、投影出力は同じですが、翻訳は正しいと思います (確かにマーカーの正しい側にあります) XY 平面上の 3D ビュー

Update2 - 実際の画像サイズ カメラのキャリブレーションに入る画像サイズで遊んでいます。正規化された 1,1 を使用していますが、imageSize パラメーターは整数であるため、これは重要であると思いました...そして、そうであると思います (赤いボックスは、投影されたビュー空間ポイントが z と交差する場所です) =0 床面) 歪み補正なしの結果は次のとおりです (変更されたのは、画像サイズが 1,1 から 640,480 に変更されただけです。正規化された入力ビュー空間の座標にも 640,480 を掛けます) ここに画像の説明を入力 歪みを追加してみます完全に並んでいるかどうかを確認するための修正...

4

3 に答える 3

0

今のところ、少なくとも Edit 2 (ImageSize は 1,1 よりも大きい必要があります) を修正として扱っています。

現時点では逆さまになっているかもしれませんが、これはかなり良い結果を生み出しています。

于 2013-03-26T19:36:59.493 に答える
0

最初に確認することは、推定された内因性および外因性のカメラ行列が与えられたときに、マーカーが画像に正しく再投影されていることを確認することです。次に、グローバル フレームでカメラの位置を見つけ、それがマーカーの位置と一致するかどうかを確認できます。(OpenCV のように座標系を使用します。) これが完了すると、問題が発生する可能性はほとんどありません。ポイントを xz 平面上に配置する必要があるため、必要な座標変換は 1 回だけです。ご覧のとおり、gWorldToCalibration マトリックスでそれを行います。次に、変換をマーカーとカメラ位置の両方に適用し、マーカーが正しい場所にあることを確認します。その後、カメラの位置も正しくなります (座標系の利き手に何か問題があった場合を除きますが、簡単に修正できます)。

于 2013-03-20T23:19:09.383 に答える
0

gWorldToCalibrationの逆をとるべきではないと思います

ofMatrix4x4 gCalibrationToWorld = gWorldToCalibration.getInverse();

ここにコードを投稿しました。これは、多かれ少なかれOpenCV-to OpenGL COS を実行しています。これは C ですが、C++ でも似ているはずです。

于 2013-12-04T12:19:45.463 に答える