Я пытаюсь использовать 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 кажется более или менее тем, что я ищу. Однако я попробовал и сравнил результаты со своим методом, и матрицы, к которым я пришел в обоих случаях, оказались одинаковыми. Я чувствую, что этот ответ правильный, но я упускаю важную деталь.