web-dev-qa-db-ja.com

cv :: solvePnPのワールド座標でのカメラ位置

キャリブレーションされたカメラ(固有のマトリックスと歪み係数)があり、画像内のいくつかの3dポイントとそれに対応するポイント(2dポイント)を知っているカメラの位置を知りたいです。

そんなこと知ってる cv::solvePnPは私を助けることができ、 thisthis を読んだ後、私はsolvePnP rvectvecの出力が回転であることを理解していますカメラ座標系でのオブジェクトの移動。

そのため、世界座標系でカメラの回転/平行移動を調べる必要があります。

上記のリンクから、Pythonでのコードは簡単なようです:

found,rvec,tvec = cv2.solvePnP(object_3d_points, object_2d_points, camera_matrix, dist_coefs)
rotM = cv2.Rodrigues(rvec)[0]
cameraPosition = -np.matrix(rotM).T * np.matrix(tvec)

私はPython/numpyのものを知りません(私はC++を使用しています)が、これは私にはあまり意味がありません:

  • rvec、solvePnPからのtvec出力は3x1行列、3要素ベクトルです
  • cv2.Rodrigues(rvec)は3x3行列です
  • cv2.Rodrigues(rvec)[0]は3x1行列、3要素ベクトルです
  • cameraPositionは、3x3マトリックスである3x1 * 1x3マトリックス乗算です。簡単なglTranslatefおよびglRotate呼び出しでopenglでこれを使用するにはどうすればよいですか
48
nkint

「世界座標」で「オブジェクト座標」を意味する場合、pnpアルゴリズムによって与えられた結果の逆変換を取得する必要があります。

変換行列を反転させるトリックがあります。これにより、通常は高価な反転演算を保存でき、Pythonのコードを説明できます。変換_[R|t]_が与えられると、そのinv([R|t]) = [R'|-R'*t]が得られます。ここで_R'_はRの転置です。したがって、コーディングできます(テストされていません):

_cv::Mat rvec, tvec;
solvePnP(..., rvec, tvec, ...);
// rvec is 3x1, tvec is 3x1

cv::Mat R;
cv::Rodrigues(rvec, R); // R is 3x3

R = R.t();  // rotation of inverse
tvec = -R * tvec; // translation of inverse

cv::Mat T = cv::Mat::eye(4, 4, R.type()); // T is 4x4
T( cv::Range(0,3), cv::Range(0,3) ) = R * 1; // copies R into T
T( cv::Range(0,3), cv::Range(3,4) ) = tvec * 1; // copies tvec into T

// T is a 4x4 matrix with the pose of the camera in the object frame
_

更新:後で、OpenGLでTを使用するには、カメラフレームの軸がOpenCVとOpenGLで異なることに注意する必要があります。

OpenCVは、コンピュータービジョンで通常使用される参照を使用します。Xは右を指し、Yは下を指し、Zは正面を指します( this image のように)。 OpenGLのカメラのフレームは次のとおりです。Xは右を指し、Yは上を指し、Zは後ろを指します( this image の左側のように)。したがって、X軸を中心に180度の回転を適用する必要があります。この回転行列の式は wikipedia にあります。

_// T is your 4x4 matrix in the OpenCV frame
cv::Mat RotX = ...; // 4x4 matrix with a 180 deg rotation around X
cv::Mat Tgl = T * RotX; // OpenGL camera in the object frame
_

これらの変換は常に混乱を招き、あるステップで間違っている可能性があります。

最後に、OpenCVの行列はメモリの行優先順、OpenGLの列は列優先順で格納されることを考慮してください。

49
ChronoTrigger

カメラの位置を指定する標準の4x4ポーズマトリックスに変換する場合。 rotMを左上の3x3の正方形、tvecを右の3つの要素、0,0,0,1を下の行として使用します

pose = [rotation   tvec(0)
        matrix     tvec(1)
        here       tvec(2)
        0  , 0, 0,  1]

それを反転します(世界のポーズの代わりにカメラのポーズを取得するため)

4
Hammer