#opencv #camera-calibration #coordinate-transformation
#opencv #калибровка камеры #преобразование координат
Вопрос:
Я использую opencv для калибровки моей веб-камеры. Итак, что я сделал, это прикрепил мою веб-камеру к установке, чтобы она оставалась статичной, и я использовал шаблон калибровки шахматной доски, переместил его перед камерой и использовал обнаруженные точки для вычисления калибровки. Итак, это то, что мы можем найти во многих примерах opencv (https://docs.opencv.org/3.1.0/dc/dbb/tutorial_py_calibration.html )
Теперь это дает мне внутреннюю матрицу камеры и компонент поворота и трансляции для отображения каждого из этих видов шахматной доски из пространства шахматной доски в мировое пространство.
Однако меня интересует глобальная внешняя матрица, т. Е. Как только я уберу шахматную доску, я хочу иметь возможность указать точку в изображении сцены, т. е. x, y и ее высоту, и это даст мне положение в мировом пространстве. Насколько я понимаю, для этого мне нужны как внутренняя, так и внешняя матрицы. Как следует приступить к вычислению внешней матрицы отсюда? Могу ли я использовать измерения, которые я уже собрал на этапе калибровки шахматной доски, для вычисления внешней матрицы?
Ответ №1:
Позвольте мне указать некоторый контекст. Рассмотрим следующую картинку, (из 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|
Это внешняя калибровка (которая также может быть записана в виде матрицы 4×4, это то, что вы называете внешней матрицей).
Теперь ответ. Чтобы получить R и T, вы можете выполнить следующее:
-
Исправьте вашу мировую систему отсчета, например, земля может быть плоскостью (x, y), и выберите для нее начало координат.
-
Установите некоторые точки с известными координатами в этой системе отсчета, например, точки в квадратной сетке на полу.
-
Сделайте снимок и получите соответствующие координаты 2D-изображения.
-
Используйте solvePnP для получения поворота и трансляции со следующими параметрами:
- Точки объекта: трехмерные точки в мировой системе отсчета.
- Точки изображения: соответствующие 2D-точки на изображении в том же порядке, что и точки объекта.
- cameraMatris: встроенная матрица, которая у вас уже есть.
- distCoeffs: коэффициенты искажения, которые у вас уже есть.
- rvec, tvec: это будут выходные данные.
- Используйте внешнее предположение: false
- флаги: вы можете использовать CV_ITERATIVE
-
Наконец, получите R из rvec с помощью функции Rodrigues.
Для работы solvePnP вам понадобятся как минимум 3 неколлинеарные точки с соответствующими 3D-2D координатами (ссылка), но чем больше, тем лучше. Чтобы получить точки хорошего качества, вы могли бы напечатать большой шаблон шахматной доски, расположить его плашмя на полу и использовать в качестве сетки. Важно, чтобы рисунок на изображении не был слишком маленьким (чем больше, тем стабильнее будет ваша калибровка).
И, очень важно: для внутренней калибровки вы использовали шахматный шаблон с квадратами определенного размера, но вы сообщили алгоритму (который вроде как решает проблемы для каждого шаблона), что размер каждого квадрата равен 1. Это не указано явно, но выполняется в строке 10 примера кода, где сетка строится с координатами 0,1,2,…:
objp [:,:2] = np.mgrid[0:7,0:6].Т.е.изменить форму (-1,2)
И масштаб мира для внешней калибровки должен соответствовать этому, поэтому у вас есть несколько возможностей:
-
Используйте тот же масштаб, например, используя ту же сетку или измеряя координаты вашей «мировой» плоскости в том же масштабе. В этом случае ваш «мир» не будет в нужном масштабе.
-
Рекомендуется: повторить внутреннюю калибровку с правильным масштабом, что-то вроде:
objp[:,:2] = (size_of_a_square*np.mgrid[0:7,0:6]).Т.Е.изменить форму (-1,2)
Где size_of_a_square — реальный размер квадрата.
-
(Этого не делали, но теоретически возможно, сделайте это, если не можете выполнить 2) Повторно выполните внутреннюю калибровку, масштабируя fx и fy. Это возможно, потому что камера видит все с точностью до масштабного коэффициента, а заявленный размер квадрата изменяет только fx и fy (и T в позе для каждого квадрата, но это уже другая история). Если фактический размер квадрата равен L, то замените fx и fy на Lfx и Lfy перед вызовом solvePnP.
Комментарии:
1. Это довольно хлопотно даже сегодня, поскольку не существует единой хорошо функционирующей программы или пакета ROS, который бы выполнял это удобно. Теоретические предпосылки в порядке, но без исполняемого файла мы все еще не можем этого сделать.
2. @Milo Можно ли откалибровать камеру без того, чтобы исходные внешние параметры были перемещены?
3. Привет @thewoz. Извините, но я не совсем понимаю вопрос. Не могли бы вы рассказать немного подробнее?
4. Привет, @Milo, функция калибровки камеры в opencv находит внутренние и внешние параметры камеры, которые минимизируют ошибку проекции. Теперь я очень точно знаю внешний параметр, но мне не хватает внутреннего. При использовании функции в opencv найденные внутренние параметры будут соответствовать внешним, найденным алгоритмом, но не «реальным».
5. @thewoz: Если я правильно понимаю, вы используете внутреннюю калибровку из OpenCV и внешнюю калибровку, которую вы указываете вручную, и она работает не так, как ожидалось? Так и должно быть. Возможно, вы неправильно указываете внешнюю калибровку, но без дополнительной информации трудно сказать. Не могли бы вы предоставить более подробную информацию? Может быть, вам нужно опубликовать новый вопрос?