Найти 3D-позицию и ориентацию моей камеры в соответствии с 2D-маркером

В настоящее время я создаю приложение дополненной реальности и застрял на проблеме, которая кажется довольно простой, но очень сложной для меня... Проблема заключается в следующем:

Камера моего устройства откалибрована и обнаруживает 2D-маркер (например, QRCode). Я знаю фокусное расстояние, положение датчика, расстояние между моей камерой и центром маркера, реальный размер маркера и координаты 4 углов маркера и его центра на 2D-изображении, которое я получил от камера. См. следующее изображение:

иллюстрация

На изображении мы знаем расстояния a,b,c,d и координаты красных точек.

Что мне нужно знать, так это положение и ориентацию камеры в соответствии с маркером (как показано на изображении, начало координат находится в центре маркера).

Есть ли простой и быстрый способ сделать это? Я попробовал какой-то метод, придуманный мной (используя формулы Аль-Каши), но это закончилось слишком большим количеством ошибок :(. Может ли кто-нибудь указать способ, как избавить меня от этого?


person Cocottier    schedule 14.01.2015    source источник
comment
Обычно это решается с помощью так называемого алгоритма PnP (см., например, эту статью). Какой язык программирования/библиотеку вы используете?   -  person BConic    schedule 14.01.2015
comment
Я знал об этом решении, но оно слишком сложное для меня, моих знаний недостаточно, чтобы полностью его понять. Я использую C и рисую с помощью OpenGL (и ничего больше). У меня есть полностью работающее приложение AR, которое я развиваю, чтобы использовать маркеры (до этого мы использовали библиотеку под названием Vuforia). Осталось только получить эту чертову позицию камеры :( Есть ли способ проще?   -  person Cocottier    schedule 14.01.2015
comment
Это не простая проблема, я не думаю, что есть более простой способ... Но, возможно, вы сможете найти какой-нибудь код или легкую библиотеку для использования.   -  person BConic    schedule 14.01.2015
comment
Я поищу это (вроде уже сделал, но обычно функции не так много комментируются, поэтому их все еще трудно понять, и использовать то, что я не понимаю, как это работает, мне немного не нравится). Я мог бы найти тот, который поможет мне лучше понять проблему!   -  person Cocottier    schedule 15.01.2015


Ответы (2)


Вы можете найти пример кода для алгоритма EPnP на этой веб-странице. Этот код состоит из одного заголовочного файла и одного исходного файла, а также одного файла для примера использования, поэтому включить его в код не составит труда.

Обратите внимание, что этот код выпущен только для целей исследования/оценки, как указано на этой странице.

ИЗМЕНИТЬ:

Я только что понял, что для работы этого кода требуется OpenCV. Кстати, хотя это добавит довольно большую зависимость в ваш проект, текущая версия OpenCV имеет встроенную функцию solvePnP, которая делает то, что вы хотите.

person BConic    schedule 15.01.2015
comment
Я поищу их обоих и буду держать вас в курсе, спасибо за вашу помощь! - person Cocottier; 15.01.2015
comment
Итак, я смотрел на функциюsolvePnP из OpenCV, но ни один из методов, вызываемых в функции, недоступен (PnP(), P3Psolver(),...) и не упоминается в заголовке (поэтому нет внешней библиотеки). Как это возможно? О_о - person Cocottier; 15.01.2015
comment
Они являются внутренними для библиотеки. Вы должны использовать функцию solvePnP напрямую. Есть документация по этой функции. К вашему сведению, PnP и P3PSolver являются экземплярами функторов типов epnp и p3p (см. строки 64 и 76 файлаsolvepnp.cpp), которые определены в p3p.h/cpp и epnp.h/cpp. - person BConic; 15.01.2015
comment
Хорошо, поэтому я немного больше изучаю, как решить мою проблему благодаря вам и OpenCV, но я застрял на этой строке: /modules/core/src/lapack.cpp#L1764" rel="nofollow noreferrer">github.com/Itseez/opencv/blob/ Каков его эффект? Я, хотя он вызвал конструктор, которого я тоже не понимаю: L288" rel="nofollow noreferrer">github.com/Itseez/opencv/blob/ Есть идеи? - person Cocottier; 15.01.2015
comment
Опять же, это функтор: svd является экземпляром класса cv::SVD, который перегружает operator(). Следовательно, выполнение svd(...) похоже на вызов функции. Подробнее о функторах см. в этой публикации. - person BConic; 15.01.2015
comment
Я понял, но что делает эта функция? Я имею в виду, что в примере, который вы мне дали, мы создали новый экземпляр функтора (это то, что мы делаем с cv::SVD, а затем используем этот функтор svd(...)), но здесь функция, стоящая за функтором, не появляется: operator ()(m, flags);. Он вообще ничего не делает? Я имею в виду, что тело функтора заменяется на ; ... Я легко понимаю поведение того, что в примере int operator()(int y) { return x + y; }. Но на этом примере тот, что с СВД, кажется явно ничего не делает, я должен ошибаться, потому что не было бы смысла ничего называть... - person Cocottier; 15.01.2015
comment
Поскольку cv::SVD — это класс, тело operator() может быть определено в другом месте, как и любая другая функция-член. Обычно вы объявляете функции-члены в файлах заголовков и определяете их тело в файлах cpp, то же самое верно и для операторов. В данном конкретном случае cv::SVD::operator() определяется в строке 1614 файла lapack.cpp. Это вычисляет SVD (т. е. разложение по единственному значению) матрицы a, которая затем используется в оставшаяся часть функции через svd.u svd.vt и svd.w. - person BConic; 15.01.2015
comment
Поскольку я не понимаю, как это работает, я просто использую OpenCV для решения своей проблемы. Большое спасибо за твою помощь. Возможно, когда-нибудь я пересмотрю его еще раз, но сейчас меня это устраивает. Еще раз спасибо за то, что научили меня, что такое функторы :) - person Cocottier; 19.01.2015

Вы можете вычислить гомографию между точками изображения и соответствующими точками мира. Затем из гомографии вы можете вычислить вращение и перемещение, отображающее точку из системы координат маркера в систему координат камеры. Математика описана в статье о калибровке камеры. Чжан.

Вот пример в MATLAB с использованием набора инструментов Computer Vision System Toolbox, который делает большую часть того, что вам нужно. Он использует функцию extrinsics, которая вычисляет трехмерное вращение и перевод из совпадающих точек изображения и мира. Очки не обязательно должны браться с шахматной доски.

person Dima    schedule 15.01.2015
comment
Здравствуйте, спасибо за указание на этот метод. Поскольку у меня намного меньше очков, чем на шахматной доске, как вы думаете, я мог бы использовать этот метод? Если да, то можно ли найти источник внешней функции? - person Cocottier; 15.01.2015
comment
@ user2342594, вам нужно как минимум 4 неколлинеарные точки для вычисления гомографии, которая является двумерным проективным преобразованием. Математика для вычисления R и t по известной внутренней матрице и гомографии дана на странице 6 статьи. Это довольно просто кодировать. Если у вас установлена ​​последняя версия MATLAB с набором инструментов Computer Vision System Toolbox, вы можете просто просмотреть исходный код extrinsics(). - person Dima; 15.01.2015