Оценка позы камеры (OpenCV PnP)
Я пытаюсь получить глобальную оценку позы по изображению четырех опорных точек с известными глобальными позициями, используя мою веб-камеру.
Я проверил много вопросов об обмене стека и несколько статей, и я не могу найти правильное решение. Номера позиций, которые я получаю, повторяются, но никоим образом не линейно пропорциональны движению камеры. К вашему сведению, я использую C++ OpenCV 2.1.
По этой ссылке изображены мои системы координат и данные испытаний, использованные ниже.
% Input to solvePnP():
imagePoints = [ 481, 831; % [x, y] format
520, 504;
1114, 828;
1106, 507]
objectPoints = [0.11, 1.15, 0; % [x, y, z] format
0.11, 1.37, 0;
0.40, 1.15, 0;
0.40, 1.37, 0]
% camera intrinsics for Logitech C910
cameraMat = [1913.71011, 0.00000, 1311.03556;
0.00000, 1909.60756, 953.81594;
0.00000, 0.00000, 1.00000]
distCoeffs = [0, 0, 0, 0, 0]
% output of solvePnP():
tVec = [-0.3515;
0.8928;
0.1997]
rVec = [2.5279;
-0.09793;
0.2050]
% using Rodrigues to convert back to rotation matrix:
rMat = [0.9853, -0.1159, 0.1248;
-0.0242, -0.8206, -0.5708;
0.1686, 0.5594, -0.8114]
Пока кто-нибудь может увидеть что-то не так с этими числами? Я был бы признателен, если бы кто-нибудь зарегистрировал их, например, в MatLAB (код выше подходит для m-file).
С этого момента я не уверен, как получить глобальную позу от rMat и tVec. Из того, что я прочитал в этом вопросе, получить позу от rMat и tVec просто:
position = transpose(rMat) * tVec % matrix multiplication
Однако из других источников я подозреваю, что это не так просто.
Что мне нужно сделать, чтобы получить положение камеры в координатах реального мира? Поскольку я не уверен, является ли это проблемой реализации (хотя, скорее всего, проблемой теории), я бы хотел, чтобы кто-то, кто успешно использовал функцию solvePnP в OpenCV, ответил на этот вопрос, хотя любые идеи тоже приветствуются!
Большое спасибо за уделенное время.
3 ответа
Я решил это некоторое время назад, извинения за задержку года.
В Python OpenCV 2.1, который я использовал, и в более новой версии 3.0.0-dev я проверил, что, чтобы получить позу камеры в глобальном кадре, вы должны:
_, rVec, tVec = cv2.solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs)
Rt = cv2.Rodrigues(rvec)
R = Rt.transpose()
pos = -R * tVec
Теперь pos - это позиция камеры, выраженная в глобальном кадре (тот же кадр, в котором выражены точки объекта). R - это DCM-матрица ориентации, которая является хорошей формой для сохранения ориентации. Если вам требуются углы Эйлера, то вы можете преобразовать углы DCM в углы Эйлера, используя последовательность вращения XYZ, используя:
roll = atan2(-R[2][1], R[2][2])
pitch = asin(R[2][0])
yaw = atan2(-R[1][0], R[0][0])
Если вы имеете в виду с глобальной позой матрицу позы камеры 4x4, которую можно использовать в OpenGL, я делаю это так
CvMat* ToOpenGLCos( const CvMat* tVec, const CvMat* rVec )
{
//** flip COS 180 degree around x-axis **//
// Rodrigues to rotation matrix
CvMat* extRotAsMatrix = cvCreateMat(3,3,CV_32FC1);
cvRodrigues2(rVec,extRotAsMatrix);
// Simply merge rotation matrix and translation vector to 4x4 matrix
CvMat* world2CameraTransformation = CreateTransformationMatrixH(tVec,
extRotAsMatrix );
// Create correction rotation matrix (180 deg x-axis)
CvMat* correctionMatrix = cvCreateMat(4,4,CV_32FC1);
/* 1.00000 0.00000 0.00000 0.00000
0.00000 -1.00000 -0.00000 0.00000
0.00000 0.00000 -1.00000 0.00000
0.00000 0.00000 0.00000 1.00000 */
cvmSet(correctionMatrix,0,0,1.0); cvmSet(correctionMatrix,0,1,0.0);
...
// Flip it
CvMat* world2CameraTransformationOpenGL = cvCreateMat(4,4,CV_32FC1);
cvMatMul(correctionMatrix,world2CameraTransformation, world2CameraTransformationOpenGL);
CvMat* camera2WorldTransformationOpenGL = cvCreateMat(4,4,CV_32FC1);
cvInv(world2CameraTransformationOpenGL,camera2WorldTransformationOpenGL,
CV_LU );
cvReleaseMat( &world2CameraTransformationOpenGL );
...
return camera2WorldTransformationOpenGL;
}
Я думаю, что переключение системы координат необходимо, потому что OpenCV и OpenGL/VTK/ и т.д. использовать разные системы координат, как показано на рисунке. Системы координат OpenGL и OpenCV
Ну, это работает так, но у кого-то может быть лучшее объяснение.
Положение камеры будет {- transpose( r) * t } . Вот и все.
И вы все сделали правильно, за исключением того, что cv::solvePnp дает (4 x 1) вектор для перевода, если я правильно помню, вам придется делить x, y, z с координатой w.