【问题标题】:OpenCV: rotation/translation vector to OpenGL modelview matrixOpenCV:旋转/平移向量到 OpenGL 模型视图矩阵
【发布时间】:2012-05-05 23:35:12
【问题描述】:

我正在尝试使用 OpenCV 来做一些基本的增强现实。我要解决的方法是使用findChessboardCorners 从相机图像中获取一组点。然后,我沿 z = 0 平面创建一个 3D 四边形,并使用solvePnP 获得成像点和平面点之间的单应性。由此,我想我应该能够设置一个模型视图矩阵,它允许我在图像顶部以正确的姿势渲染一个立方体。

solvePnPdocumentation 表示它输出一个旋转向量“(与 [平移向量] 一起)将点从模型坐标系带到相机坐标系。”我认为这与我想要的相反;因为我的四边形在平面 z = 0 上,所以我想要一个模型视图矩阵,它将将该四边形转换为适当的 3D 平面。

我认为通过以相反的顺序执行相反的旋转和平移,我可以计算出正确的模型视图矩阵,但这似乎不起作用。虽然渲染的对象(一个立方体)确实随着相机图像移动并且在平移上似乎大致正确,但旋转根本不起作用;当它应该只在一个轴上旋转时,它在多个轴上,有时在错误的方向上。以下是我目前正在做的事情:

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 工作方式不同?

This question 似乎与我的非常相似,特别是 coder9 的答案似乎或多或少是我正在寻找的。但是,我尝试了它并将结果与​​我的方法进行了比较,两种情况下我得到的矩阵都是相同的。我觉得这个答案是正确的,但我错过了一些关键细节。

【问题讨论】:

标签: ios opengl-es opencv opengl-es-2.0


【解决方案1】:

您必须确保轴朝向正确的方向。特别是在 OpenGL 和 OpenCV 中,y 和 z 轴朝向不同的方向,以确保 x-y-z 基础是直接的。您可以在此blog post 中找到一些信息和代码(使用 iPad 摄像头)。

-- 编辑-- 喔好吧。不幸的是,我使用这些资源反过来(opengl ---> opencv)来测试一些算法。我的主要问题是图像的行顺序在 OpenGL 和 OpenCV 之间颠倒了(也许这有帮助)。

在模拟相机时,我遇到了可以在heregeneralized projection matrix paper 中找到的相同投影矩阵。博文 cmets 中引用的This paper 也显示了计算机视觉和 OpenGL 投影之间的一些联系。

【讨论】:

  • 感谢您的链接。不幸的是,我以前看过那个帖子。我尝试或多或少地逐字使用他的代码,并得到了基本相同的结果。我认为该帖子也缺少关键细节,因为它没有显示他如何计算单应性,这可能很重要。我也知道 y/z 轴的差异,但我已经多次检查了我的代码,据我所知我正在处理。
【解决方案2】:

我不是 IOS 程序员,所以这个答案可能会产生误导! 如果问题不在于应用旋转和平移的顺序,则建议使用更简单且更常用的坐标系。

corners 向量中的点的原点 (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 步骤。请告诉我进展如何。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-06
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 2014-06-10
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    相关资源
    最近更新 更多