Позвольте мне поместить некоторый контекст. Рассмотрим следующую картину (от https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html):
К камере «прикреплена» жесткая система отсчета (Xc, Yc, Zc). Успешная калибровка , которую вы успешно выполнили, позволяет преобразовать точку (Xc, Yc, Zc) в ее проекцию на изображении (u, v) и точку (u, v) на изображении в луч в (Xc, Yc, Zc) (вы можете получить его только с коэффициентом масштабирования).
На практике вы хотите поместить камеру во внешнюю «мировую» систему отсчета, назовем ее (X, Y, Z). Затем происходит жесткое преобразование, представленное матрицей вращения R и вектором перевода T , таким что:
|Xc| |X|
|Yc|= R |Y| + T
|Zc| |Z|
Это внешняя калибровка (которую можно записать также в виде матрицы 4x4, это то, что вы называете внешней матрицей).
Теперь ответ. Чтобы получить R и T , вы можете сделать следующее:
Исправьте свою систему отсчета мира, например, земля может быть плоскостью (x, y), и выберите для нее начало координат.
Установите некоторые точки с известными координатами в этой системе отсчета, например, точки в квадратной сетке в полу.
Сделайте снимок и получите соответствующие координаты 2D-изображения.
Используйте solvePnP для получения поворота и перемещения со следующими параметрами:
- objectPoints: трехмерные точки в системе отсчета мира.
- imagePoints: соответствующие 2D точки на изображении в том же порядке , что и objectPoints.
- cameraMatris: встроенная матрица, которую вы уже имеете.
- distCoeffs: коэффициенты искажения, которые у вас уже есть.
- rvec , tvec : это будут выходы.
- useExtrinsicGuess: false
- flags: вы можете использовать CV_ITERATIVE
Наконец, получите R от rvec с функцией Родригес .
Вам понадобится как минимум 3 неколлинеарных точки с соответствующими 3D-2D координатами, чтобы решение executePnP ( link ), но чем больше, тем лучше. Чтобы получить очки хорошего качества, вы можете напечатать большой рисунок шахматной доски, положить его ровно на пол и использовать в качестве сетки. Важно то, что рисунок не слишком мал на изображении (чем больше, тем стабильнее будет ваша калибровка).
И, очень важно : для внутренней калибровки вы использовали шахматную фигуру с квадратами определенного размера, но вы сказали алгоритму (который выполняет тип executePnP для каждого шаблона), что размер каждого квадрата составляет 1 . Это не является явным, но выполняется в строке 10 примера кода, где сетка построена с координатами 0,1,2, ...:
objp [:,: 2] = np.mgrid [0: 7,0: 6] .T.reshape (-1,2)
И масштаб мира для внешней калибровки должен соответствовать этому, поэтому у вас есть несколько возможностей:
Используйте тот же масштаб, например, используя ту же сетку или измеряя координаты вашей "мировой" плоскости в том же масштабе. В этом случае ваш «мир» не будет в правильном масштабе.
Рекомендуется: повторить внутреннюю калибровку с правильной шкалой, что-то вроде:
objp [:,: 2] = (size_of_a_square * np.mgrid [0: 7,0: 6]). T.reshape (-1,2)
Где size_of_a_square - это реальный размер квадрата.
(Не сделал этого, но теоретически возможно, сделайте это, если вы не можете сделать это 2) Повторно используйте внутреннюю калибровку, масштабируя fx и fy. Это возможно, потому что камера видит все с точностью до масштабного коэффициента, и заявленный размер квадрата только изменяет fx и fy (и T в позе для каждого квадрата, но это другая история). Если фактический размер квадрата равен L , замените fx и fy на L fx и L fy перед вызовом solvePnP.