6

OpenCV を使用して基本的な拡張現実を実行しようとしています。私が行っている方法はfindChessboardCorners、カメラ画像から一連のポイントを取得するために使用しています。次に、z = 0 平面に沿って 3D 四角形を作成し、これを使用solvePnPして、画像化された点と平面点の間のホモグラフィを取得します。そこから、画像の上に適切なポーズで立方体をレンダリングできるモデルビュー マトリックスを設定できるはずだと思います。

ドキュメントsolvePnPは、「([並進ベクトル]と一緒に)モデル座標系からカメラ座標系にポイントをもたらす」回転ベクトルを出力すると書かれています。それは私が望んでいることの反対だと思います。私のクワッドは平面 z = 0 にあるので、そのクワッドを適切な 3D 平面に変換するモデルビュー マトリックスが必要です。

反対の回転と平行移動を反対の順序で実行することで、正しいモデル ビュー マトリックスを計算できると考えましたが、うまくいかないようです。レンダリングされたオブジェクト (立方体) はカメラ イメージと共に移動し、平行移動はおおよそ正しいように見えますが、回転はまったく機能しません。1 つのみで回転する必要があるときに複数の軸で回転し、場合によっては間違った方向に回転します。これが私がこれまでにやっていることです:

std::vector<Point2f> corners;
bool found = findChessboardCorners(*_imageBuffer, cv::Size(5,4), corners,
                                      CV_CALIB_CB_FILTER_QUADS |
                                      CV_CALIB_CB_FAST_CHECK);
if(found)
{
  drawChessboardCorners(*_imageBuffer, cv::Size(6, 5), corners, found);

  std::vector<double> distortionCoefficients(5);  // camera distortion
  distortionCoefficients[0] = 0.070969;
  distortionCoefficients[1] = 0.777647;
  distortionCoefficients[2] = -0.009131;
  distortionCoefficients[3] = -0.013867;
  distortionCoefficients[4] = -5.141519;

  // Since the image was resized, we need to scale the found corner points
  float sw = _width / SMALL_WIDTH;
  float sh = _height / SMALL_HEIGHT;
  std::vector<Point2f> board_verts;
  board_verts.push_back(Point2f(corners[0].x * sw, corners[0].y * sh));
  board_verts.push_back(Point2f(corners[15].x * sw, corners[15].y * sh));
  board_verts.push_back(Point2f(corners[19].x * sw, corners[19].y * sh));
  board_verts.push_back(Point2f(corners[4].x * sw, corners[4].y * sh));
  Mat boardMat(board_verts);

  std::vector<Point3f> square_verts;
  square_verts.push_back(Point3f(-1, 1, 0));                              
  square_verts.push_back(Point3f(-1, -1, 0));
  square_verts.push_back(Point3f(1, -1, 0));
  square_verts.push_back(Point3f(1, 1, 0));
  Mat squareMat(square_verts);

  // Transform the camera's intrinsic parameters into an OpenGL camera matrix
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  // Camera parameters
  double f_x = 786.42938232; // Focal length in x axis
  double f_y = 786.42938232; // Focal length in y axis (usually the same?)
  double c_x = 217.01358032; // Camera primary point x
  double c_y = 311.25384521; // Camera primary point y


  cv::Mat cameraMatrix(3,3,CV_32FC1);
  cameraMatrix.at<float>(0,0) = f_x;
  cameraMatrix.at<float>(0,1) = 0.0;
  cameraMatrix.at<float>(0,2) = c_x;
  cameraMatrix.at<float>(1,0) = 0.0;
  cameraMatrix.at<float>(1,1) = f_y;
  cameraMatrix.at<float>(1,2) = c_y;
  cameraMatrix.at<float>(2,0) = 0.0;
  cameraMatrix.at<float>(2,1) = 0.0;
  cameraMatrix.at<float>(2,2) = 1.0;

  Mat rvec(3, 1, CV_32F), tvec(3, 1, CV_32F);
  solvePnP(squareMat, boardMat, cameraMatrix, distortionCoefficients, 
               rvec, tvec);

  _rv[0] = rvec.at<double>(0, 0);
  _rv[1] = rvec.at<double>(1, 0);
  _rv[2] = rvec.at<double>(2, 0);
  _tv[0] = tvec.at<double>(0, 0);
  _tv[1] = tvec.at<double>(1, 0);
  _tv[2] = tvec.at<double>(2, 0);
}

次に、描画コードで...

GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Translate(modelViewMatrix, -tv[1], -tv[0], -tv[2]);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -rv[0], 1.0f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -rv[1], 0.0f, 1.0f, 0.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -rv[2], 0.0f, 0.0f, 1.0f);

私がレンダリングしている頂点は、原点の周りに単位長さの立方体を作成します (つまり、各エッジに沿って -0.5 から 0.5 まで)。OpenGL 変換関数で変換が「逆順」で実行されることを知っているので、上記は立方体をz 軸、y 軸、x 軸の順に移動し、それを平行移動します。ただ、最初に翻訳してから回転させているように見えるので、Apple のGLKMatrix4動作は異なるのでしょうか?

この質問は私のものと非常に似ているようで、特に coder9 の回答は、多かれ少なかれ私が探しているもののようです。しかし、私はそれを試してみて、結果を私の方法と比較したところ、どちらの場合も到達した行列は同じでした. その答えは正しいと思いますが、重要な詳細がいくつか欠けています。

4

2 に答える 2

2

軸が正しい方向を向いていることを確認する必要があります。特に、y 軸と z 軸は OpenGL と OpenCV で異なる方向を向いており、xyz 基底が直接であることを保証します。このブログ投稿で、いくつかの情報とコード (iPad カメラを使用) を見つけることができます。

-- 編集 -- わかりました。残念ながら、これらのリソースを使用して、逆に (opengl ---> opencv) いくつかのアルゴリズムをテストしました。私の主な問題は、画像の行の順序が OpenGL と OpenCV の間で逆になっていることでした (これが役立つかもしれません)。

カメラをシミュレートするとき、ここ一般化された射影行列の論文にあるのと同じ射影行列に出くわしました。ブログ投稿のコメントで引用されているこの論文は、コンピューター ビジョンと OpenGL プロジェクションの間のリンクも示しています。

于 2012-04-27T10:47:25.770 に答える
0

私は IOS プログラマーではないので、この回答は誤解を招く可能性があります。問題が回転と平行移動の適用順序にない場合は、より単純で一般的に使用される座標系を使用することをお勧めします。

コーナー ベクトルのポイントは、画像の左上隅に原点 (0,0) があり、y 軸は画像の下方向にあります。多くの場合、数学から、原点が中心にあり、y 軸が画像の上部にある座標系を考えるのに慣れています。board_verts にプッシュしている座標から、同じ間違いをしていると思います。その場合、次のような方法で角の位置を簡単に変換できます。

for (i=0;i<corners.size();i++) {
  corners[i].x -= width/2;
  corners[i].y = -corners[i].y + height/2;
}

次に、solvePnP() を呼び出します。これをデバッグするのはそれほど難しくありません。四隅の位置と推定された R と T を出力して、意味があるかどうかを確認してください。その後、OpenGL のステップに進むことができます。それがどうなるか教えてください。

于 2012-04-30T16:42:22.997 に答える