1

特定の軸を中心とした回転を表すワープ行列を OpenCV で計算する必要があります。

Z 軸周り -> 簡単: 標準の回転行列を使用します

[cos(a) -sin(a) 0]
[sin(a)  cos(a) 0]
[    0       0  1]

これは他の回転ではそれほど明白ではないため、ウィキペディアで説明されているように、ホモグラフィを作成してみました。

H = R - t n^T / d

カメラと画像の間の距離が画像の高さの 2 倍であると仮定して、X 軸を中心に単純に回転させてみました。

R は標準回転行列です

[1      0       0]
[0 cos(a) -sin(a)]
[0 sin(a)  cos(a)]

n は[0 0 1]、カメラが (0, 0, z_cam) からの画像を直接見ているためです。

t は翻訳です。[0 -2h*(sin(a)) -2h*(1-cos(a))]

d は距離で、定義ごとに 2h です。

したがって、最終的なマトリックスは次のとおりです。

[1      0 0]
[0 cos(a) 0]
[0 sin(a) 1]

a = 0 の場合は単位元であり、a = pi の場合は x 軸を中心に鏡映されます。

それでも、遠近ワープにこのマトリックスを使用しても、期待どおりの結果が得られません。a の値が小さいと画像が「歪みすぎ」、すぐに消えてしまいます。

それで、私は何を間違っていますか?

(注:私はこの主題に関する多くの質問と回答を読みましたが、すべてが反対の方向に向かっています:ホモグラフィ行列を分解したくはありません3D変換と「固定" カメラまたは固定画像と移動カメラ)。

ありがとうございました。

4

1 に答える 1

5

この投稿のおかげで、最終的に方法が見つかりました: https://plus.google.com/103190342755104432973/posts/NoXQtYQThgQ

私は OpenCV に行列を計算させましたが、透視変換を自分で行っています (すべてを cv::Mat に入れるよりも実装が簡単であることがわかりました)。

float rotx, roty, rotz; // set these first
int f = 2; // this is also configurable, f=2 should be about 50mm focal length

int h = img.rows;
int w = img.cols;

float cx = cosf(rotx), sx = sinf(rotx);
float cy = cosf(roty), sy = sinf(roty);
float cz = cosf(rotz), sz = sinf(rotz);

float roto[3][2] = { // last column not needed, our vector has z=0
    { cz * cy, cz * sy * sx - sz * cx },
    { sz * cy, sz * sy * sx + cz * cx },
    { -sy, cy * sx }
};

float pt[4][2] = {{ -w / 2, -h / 2 }, { w / 2, -h / 2 }, { w / 2, h / 2 }, { -w / 2, h / 2 }};
float ptt[4][2];
for (int i = 0; i < 4; i++) {
    float pz = pt[i][0] * roto[2][0] + pt[i][1] * roto[2][1];
    ptt[i][0] = w / 2 + (pt[i][0] * roto[0][0] + pt[i][1] * roto[0][1]) * f * h / (f * h + pz);
    ptt[i][1] = h / 2 + (pt[i][0] * roto[1][0] + pt[i][1] * roto[1][1]) * f * h / (f * h + pz);
}

cv::Mat in_pt = (cv::Mat_<float>(4, 2) << 0, 0, w, 0, w, h, 0, h);
cv::Mat out_pt = (cv::Mat_<float>(4, 2) << ptt[0][0], ptt[0][1],
    ptt[1][0], ptt[1][1], ptt[2][0], ptt[2][1], ptt[3][0], ptt[3][1]);

cv::Mat transform = cv::getPerspectiveTransform(in_pt, out_pt);

cv::Mat img_in = img.clone();
cv::warpPerspective(img_in, img, transform, img_in.size());
于 2013-10-01T07:33:34.857 に答える