Определить внешнюю камеру с помощью opencv для opengl с объектом мирового пространства

Я использую opencv и openframeworks (т.е. opengl) для вычисления камеры (матрицы преобразования мира и проекции) из изображения (а позже и нескольких изображений для триангуляции).

Для целей opencv «план этажа» становится объектом (т. Е. Шахматной доской) с 0,0,0 центром мира. Положение мира / пола известно, поэтому мне нужно получить информацию о проекции (коэффициенты искажения, fov и т. Д.) И внешние координаты камеры.

Я нанес на карту положения этих точек плана этажа на мое 2D-изображение в нормализованном пространстве вида ([0,0] вверху слева. [1,1] внизу справа).

Объект (план этажа / мировые точки) находится в плоскости xz, -y вверх, поэтому я конвертирую в плоскость xy (здесь не уверен, является ли z-up отрицательным или положительным ...) для opencv, так как он должен быть плоским

ofMatrix4x4 gWorldToCalibration(
    1, 0, 0, 0,
    0, 0, 1, 0,
    0, 1, 0, 0,
    0, 0, 0, 1
    );

Я передаю 1,1 как ImageSize для калибровки камеры. флагиCV_CALIB_FIX_ASPECT_RATIO|V_CALIB_FIX_K4|CV_CALIB_FIX_K5 calibrateCamera работает успешно, дает мне низкую ошибку (обычно около0.003).

с помощьюcalibrationMatrixValues Я получаю разумное поле зрения, обычно около 50 градусов, поэтому я почти уверен, что внутренние свойства верны.

Теперь, чтобы вычислить внешнее преобразование мира-пространства камеры ... Я не думаю, что мне нужно использоватьsolvePnP поскольку у меня есть только один объект (хотя я пробовал все это раньше и вернулся с теми же результатами)

//  rot and trans output...
cv::Mat& RotationVector = ObjectRotations[0];
cv::Mat& TranslationVector = ObjectTranslations[0];

//  convert rotation to matrix
cv::Mat expandedRotationVector;
cv::Rodrigues(RotationVector, expandedRotationVector);

//  merge translation and rotation into a model-view matrix
cv::Mat Rt = cv::Mat::zeros(4, 4, CV_64FC1);
for (int y = 0; y < 3; y++)
   for (int x = 0; x < 3; x++) 
        Rt.at<double>(y, x) = expandedRotationVector.at<double>(y, x);
Rt.at<double>(0, 3) = TranslationVector.at<double>(0, 0);
Rt.at<double>(1, 3) = TranslationVector.at<double>(1, 0);
Rt.at<double>(2, 3) = TranslationVector.at<double>(2, 0);
Rt.at<double>(3, 3) = 1.0;

Теперь у меня есть матрица вращения и преобразования, но это основной столбец (я полагаю, что объект полностью перекошен, если я не транспонирую, а код выше выглядит для меня главным столбцом)

//  convert to openframeworks matrix AND transpose at the same time
ofMatrix4x4 ModelView;
for ( int r=0;  r<4;    r++ )
    for ( int c=0;  c<4;    c++ )
        ModelView(r,c) = Rt.at<double>( c, r ); 

Поменяйте местами мои плоскости обратно в пространство моей координаты (y вверх), используя обратную матрицу.

//  swap y & z planes so y is up
ofMatrix4x4 gCalibrationToWorld = gWorldToCalibration.getInverse();
ModelView *= gCalibrationToWorld;

Не уверен, что мне НУЖНО сделать это ... Я не отрицал самолеты, когда помещал их в калибровку ...

//  invert y and z planes for -/+ differences between opencv and opengl
ofMatrix4x4 InvertHandednessMatrix(
    1,  0,  0, 0,
    0,  -1, 0, 0,
    0,  0,  -1, 0,
    0,  0,  0,  1
    );
ModelView *= InvertHandednessMatrix;

И, наконец, вид модели - это объект-относительно камеры, и я хочу инвертировать его, чтобы он был относительно камеры-объекта (0,0,0)

ModelView = ModelView.getInverse();

Это приводит к тому, что камера находится не в том месте и вращается неправильно. Это неслишком далеко, камера - правая сторона плоскости Y, перевод не дикий, и я думаю, что это верный путь ... просто еще не правильно. Я ожидаю, что камера будет находиться в нарисованном краской синем круге.

Я прошел десятки SO-ответов, документацию десятки раз, но не нашел ничего правильного, я уверен, что охватил все, что мне нужно для преобразования пространства, но, возможно, я упустил что-то очевидное ? Или делать что-то не в том порядке?

Обновление 1 - мир космического самолета ... Я изменил свою плоскость мирового пространства на XY (Z вверх), чтобы соответствовать входу для openCV. (gWorldToCalibration теперь является единичной матрицей). Поворот по-прежнему неправильный, и результат проецирования такой же, но я думаю, что перевод сейчас правильный (это, безусловно, на правильной стороне маркеров)

Update2 - реальный размер изображения Я играю с размером изображения, идущим в калибровку камеры; видя, как я использую 1,1, который нормализован, но параметр imageSize указан в целых числах, я подумал, что это может быть значительным ... И я предполагаю, что это так (красный прямоугольник - это то, где проекционные точки пространства обзора пересекаются с z = 0 плоскость пола) Без какой-либо коррекции искажения, вот результат (Единственное, что изменилось, это размер изображения от 1,1 до 640,480. Я также умножил свои нормализованные координаты пространства ввода-просмотра на 640,480) Я собираюсь попробовать добавить коррекцию искажения, чтобы увидеть, если она выстраиваетсяв совершенстве...

Ответы на вопрос(3)

Ваш ответ на вопрос