プロジェクト
モバイル用のテクスチャ追跡プロジェクトに取り組んでいます。平面サーフェスのみを追跡するため、openCV の cv::FindHomography() を使用して 2 つのフレーム間のホモグラフィを計算しています。ただし、その関数は非常に遅く実行され、パイプラインの主要なボトルネックです。フレーム間のホモグラフィの変化は非常に小さいため、ホモグラフィの初期推定を行うことができるアルゴリズムははるかに高速に実行されると判断しました。また、私の外れ値の割合は非常に小さいため、堅牢な方法はオプションです。残念ながら、私の知る限り、Open CV には初期推定を行うホモグラフィ ファインダーが含まれていません。ただし、シーンの元の 3 次元ワールド座標、現在の 2 次元画像座標、カメラ マトリックス、歪みパラメーター、および最も重要な初期推定値を取得する solvePnP() は含まれています。FindHomography を solvePnP に置き換えようとしています。私はパイプライン全体で 2D 座標のみを使用し、solvePnP は 3D 座標を要求するので、2d->3d->3d_transform->2d_transform から移動しようとしています。現在、そのプロセスは、適切な初期推測が与えられていても問題がある場合、FindHomography() よりも 6 倍速く実行されます。
問題
変換方法に問題があります。私の理論では、ホモグラフィを見つけるためにカメラ行列は必要ないため、最終的にホモグラフィに含まれる情報のみが必要なため、このプロセスには必要ないはずです。また、最終的にすべての z 情報を破棄するため、z を初期化する方法は問題ではないと想定しました。私のプロセスは次のとおりです
最初に、最初の 2 次元座標をすべて 3 次元に変換します。これには、z pos に 1 を指定します。元の座標は xy 平面上で平らであると仮定できます。それで
cv::Mat rot_mat; //3x3 rotation matrix
cv::Mat pnp_rot; //3x1 rotation vector
cv::Mat pnp_tran; //3x1 translation vector
cv::Matx33f camera_matrix(1,0,0,
0,1,0,
0,0,1);
cv::Matx41f dist(0,0,0,0);
cv::solvePnP(original_cord, current_cord, camera_matrix, dist, pnp_rot, pnp_tran,true);
//Rodrigues converts from a rotation vector to a rotation matrix
cv::Rodrigues(pnp_rot, rot_mat);
cv::Matx33f homography(rot_mat(0,0),rot_mat(0,1),pnp_tran(0),
rot_mat(1,0),rot_mat(1,1),pnp_tran(1),
rot_mat(2,0),rot_mat(2,1),pnp_tran(2)+1);
ここでのホモグラフィへの変換は簡単です。ホモグラフィの最初の 2 列は 3x3 回転行列からのもので、最後の列は平行移動ベクトルです。1 つのトリックは、ホモグラフィ(2,2) がスケールに対応し、pnp_tran(2) が z 軸の動きに対応することです。z 座標を 1 に初期化すると、スケールは z_translation + 1 になります。このプロセスは、6 つの自由度のうち 4 つに対して完全に機能します。Translation_x、translation_x、スケール、および z に関する回転はすべて機能します。ただし、x と y を中心とした回転では、重大なエラーが表示されます。これは、ポイントを z = 1 で初期化したことが原因だと思いますが、修正方法がわかりません。
質問
偽のカメラ マトリックスと初期 z 座標を使用して、solvePnP から良い結果を得ることができるという私の仮定は正しかったですか? もしそうなら、x と y の回転を機能させるには、カメラ マトリックスと z 座標をどのように設定すればよいですか? また、最初の推測を取り、2次元でのみ機能するホモグラフィ検索アルゴリズムをどこで入手できるか、または自分で作成するためのテクニックに関する情報を誰かが知っている場合は、非常に役立ちます。これが機能するようになったら、おそらくその方向に進むでしょう。
アップデート
ホモグラフィを取得し、そのホモグラフィから同一平面上のポイントのセットを生成し、指定されたホモグラフィを復元するために solvePnP を介してポイントを実行するテスト プログラムを自分で作成しました。これを行う過程で、私はホモグラフィーがどのように構築されるかの一部を根本的に誤解していることに気付きました. ホモグラフィは次のように構成されると仮定しています。
hom(0,2) = x translation
hom(1,2) = y translation
hom(2,2) = scale, I can divide the entire matrix by this to normalize
最初の 2 列は、3x3 回転行列の最初の 2 列であると想定しました。これは基本的に、3x4 変換を実行して column(2) を破棄することになります。しかし、これは真実ではないことを発見しました。私のやり方の誤りを示すテストケースは、点をy軸の周りに小さな角度で回転させるホモグラフィを作ろうとしていた。
//rotate by .0175 rad about y axis
rot_mat = (1,0,.0174,
0,1,0,
-.0174,0,1);
//my conversion method to make this a homography gives
homography = (1,0,0,
0,1,0,
-.0174,0,1);
上記の同形異義語はまったく機能しません。x > 58 の点 x,y,1 を例にとります。結果は x,y,some_negative_number になります。同次座標からデカルト座標に戻すと、x 値と y 値の両方で符号が反転します。
つまり、すべてを解決できると思われる、はるかに単純な質問ができました。x 軸と y 軸を中心にある角度だけポイントを回転させるホモグラフィを作成するにはどうすればよいですか?