OpenCV :вектор поворота/перевода в матрицу представления модели OpenGL

Я пытаюсь использовать OpenCV для создания базовой дополненной реальности. Я собираюсь использовать findChessboardCornersдля получения набора точек из изображения с камеры. Затем я создаю трехмерный четырехугольник вдоль плоскости z = 0 и использую solvePnP, чтобы получить гомографию между изображенными точками и плоскими точками. От этого,Я полагаю, что должен иметь возможность настроить матрицу просмотра модели, которая позволит мне визуализировать куб с правильной позой поверх изображения.

В документации для solvePnPговорится, что он выводит вектор вращения, «который (вместе с [вектором перемещения] )переносит точки из системы координат модели в систему координат камеры. " Я думаю, что это противоположно тому, чего я хочу; поскольку мой четырехугольник находится на плоскости z = 0, мне нужна матрица просмотра модели, которая преобразует этот четырехугольник в соответствующую трехмерную плоскость.

Я думал, что, выполняя противоположные повороты и перемещения в противоположном порядке, я смогу вычислить правильную матрицу представления модели, но, похоже, это не сработало. В то время как визуализированный объект (куб )действительно движется вместе с изображением камеры и кажется примерно правильным поступательно, вращение вообще не работает; это по нескольким осям, когда он должен вращаться только по одной, а иногда и в неправильном направлении. Вот что я делаю до сих пор:

std::vector 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 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 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 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(0,0) = f_x;
  cameraMatrix.at(0,1) = 0.0;
  cameraMatrix.at(0,2) = c_x;
  cameraMatrix.at(1,0) = 0.0;
  cameraMatrix.at(1,1) = f_y;
  cameraMatrix.at(1,2) = c_y;
  cameraMatrix.at(2,0) = 0.0;
  cameraMatrix.at(2,1) = 0.0;
  cameraMatrix.at(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(0, 0);
  _rv[1] = rvec.at(1, 0);
  _rv[2] = rvec.at(2, 0);
  _tv[0] = tvec.at(0, 0);
  _tv[1] = tvec.at(1, 0);
  _tv[2] = tvec.at(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 кажется более или менее тем, что я ищу. Однако я попробовал и сравнил результаты со своим методом, и матрицы, к которым я пришел в обоих случаях, оказались одинаковыми. Я чувствую, что этот ответ правильный, но я упускаю важную деталь.

6
задан Community 23 May 2017 в 12:31
поделиться