Ios OpenCV:旋转/平移向量到OpenGL modelview矩阵

Ios OpenCV:旋转/平移向量到OpenGL modelview矩阵,ios,opengl-es,opencv,opengl-es-2.0,Ios,Opengl Es,Opencv,Opengl Es 2.0,我试图用OpenCV做一些基本的增强现实。我要做的是使用findChessboardCorners从相机图像中获取一组点。然后,我沿z=0平面创建一个3D四边形,并使用solvePnP获得成像点和平面点之间的单应性。因此,我想我应该能够设置一个modelview矩阵,它将允许我在图像顶部渲染一个具有正确姿势的立方体 forsolvePnP表示它输出一个旋转向量“与[平移向量]一起将点从模型坐标系带到相机坐标系。”我认为这与我想要的相反;因为我的四边形位于平面z=0上,所以我需要一个modelvi

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

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

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

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);
}
我正在渲染的顶点围绕原点创建一个单位长度的立方体(即沿每条边从-0.5到0.5)。我知道,使用OpenGL转换函数,会以“相反顺序”执行转换,因此上面应该沿z、y、x轴旋转立方体,然后对其进行转换。然而,它似乎是先被翻译然后被旋转的,所以也许苹果的
GLKMatrix4
的工作原理不同


看起来和我的非常相似,尤其是coder9的答案似乎或多或少就是我想要的。然而,我尝试了它,并将结果与我的方法进行了比较,我在两种情况下得出的矩阵是相同的。我觉得这个答案是对的,但我遗漏了一些关键的细节

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

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


在模拟摄影机时,我遇到了相同的投影矩阵,可以在中找到。这篇博文中引用的评论也显示了计算机视觉和OpenGL投影之间的一些联系。

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

角向量中的点的原点(0,0)位于图像的左上角,y轴朝向图像的底部。通常从数学的角度来看,我们习惯于认为坐标系的原点在中心,y轴朝向图像的顶部。从你推到木板上的坐标来看,我猜你也犯了同样的错误。如果是这种情况,则很容易通过以下方式变换角点的位置:

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

用于(i=0;我正在研究如何做到这一点。我看到了这篇关于坐标系差异的帖子。感谢链接。不幸的是,我以前看过那篇帖子。我尝试过或多或少地逐字使用他的代码,得到了基本相同的结果。我认为那篇帖子也缺少关键的细节,因为它没有显示他如何计算单应性,这可能很重要。我也知道y/z轴的差异,但我已经检查了我的代码好几次,据我所知,我正在处理这个问题。
for (i=0;i<corners.size();i++) {
  corners[i].x -= width/2;
  corners[i].y = -corners[i].y + height/2;
}