вычисление внешней матрицы с помощью opencv

#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, вы можете выполнить следующее:

  1. Исправьте вашу мировую систему отсчета, например, земля может быть плоскостью (x, y), и выберите для нее начало координат.

  2. Установите некоторые точки с известными координатами в этой системе отсчета, например, точки в квадратной сетке на полу.

  3. Сделайте снимок и получите соответствующие координаты 2D-изображения.

  4. Используйте solvePnP для получения поворота и трансляции со следующими параметрами:

    • Точки объекта: трехмерные точки в мировой системе отсчета.
    • Точки изображения: соответствующие 2D-точки на изображении в том же порядке, что и точки объекта.
    • cameraMatris: встроенная матрица, которая у вас уже есть.
    • distCoeffs: коэффициенты искажения, которые у вас уже есть.
    • rvec, tvec: это будут выходные данные.
    • Используйте внешнее предположение: false
    • флаги: вы можете использовать CV_ITERATIVE
  5. Наконец, получите R из rvec с помощью функции Rodrigues.

Для работы solvePnP вам понадобятся как минимум 3 неколлинеарные точки с соответствующими 3D-2D координатами (ссылка), но чем больше, тем лучше. Чтобы получить точки хорошего качества, вы могли бы напечатать большой шаблон шахматной доски, расположить его плашмя на полу и использовать в качестве сетки. Важно, чтобы рисунок на изображении не был слишком маленьким (чем больше, тем стабильнее будет ваша калибровка).

И, очень важно: для внутренней калибровки вы использовали шахматный шаблон с квадратами определенного размера, но вы сообщили алгоритму (который вроде как решает проблемы для каждого шаблона), что размер каждого квадрата равен 1. Это не указано явно, но выполняется в строке 10 примера кода, где сетка строится с координатами 0,1,2,…:

objp [:,:2] = np.mgrid[0:7,0:6].Т.е.изменить форму (-1,2)

И масштаб мира для внешней калибровки должен соответствовать этому, поэтому у вас есть несколько возможностей:

  1. Используйте тот же масштаб, например, используя ту же сетку или измеряя координаты вашей «мировой» плоскости в том же масштабе. В этом случае ваш «мир» не будет в нужном масштабе.

  2. Рекомендуется: повторить внутреннюю калибровку с правильным масштабом, что-то вроде:

    objp[:,:2] = (size_of_a_square*np.mgrid[0:7,0:6]).Т.Е.изменить форму (-1,2)

    Где size_of_a_square — реальный размер квадрата.

  3. (Этого не делали, но теоретически возможно, сделайте это, если не можете выполнить 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 и внешнюю калибровку, которую вы указываете вручную, и она работает не так, как ожидалось? Так и должно быть. Возможно, вы неправильно указываете внешнюю калибровку, но без дополнительной информации трудно сказать. Не могли бы вы предоставить более подробную информацию? Может быть, вам нужно опубликовать новый вопрос?