Вычисление позы камеры с матрицей гомографии на основе 4 копланарных точек - PullRequest
44 голосов
/ 19 января 2012

У меня есть 4 копланарных точки в видео (или изображении), представляющих квад (не обязательно квадрат или прямоугольник), и я хотел бы иметь возможность отображать виртуальный куб поверх них, где углы куба стоят точнопо углам квадрата видео.

Так как точки копланарны, я могу вычислить гомографию между углами единичного квадрата (то есть [0,0] [0,1] [1,0] [1, 1]) и видео координаты квад.

Из этой гомографии я должен быть в состоянии вычислить правильную позу камеры, то есть [R | t], где R - это матрица вращения 3x3, а t - вектор трансляции 3x1, так что виртуальный куб лежит на видеокадре..

Я прочитал много решений (некоторые из них на SO) и попытался реализовать их, но они, кажется, работают только в некоторых «простых» случаях (например, когда квадратик видео является квадратом), но не работают вбольшинство случаев.

Вот методы, которые я попробовал (большинство из них основаны на тех же принципах, только вычисления перевода немного отличаются).Пусть K - матрица внутренних характеристик камеры, а H - гомография.Мы вычисляем:

A = K-1 * H

Пусть a1, a2, a3 - векторы столбцов A, а r1, r2, r3 - векторы столбцов матрицы вращения R.

r1 = a1 / ||a1||
r2 = a2 / ||a2||
r3 = r1 x r2
t = a3 / sqrt(||a1||*||a2||)

Проблемаявляется то, что это не работает в большинстве случаев.Чтобы проверить мои результаты, я сравнил R и t с результатами, полученными с помощью метода executePnP OpenCV (используя следующие трехмерные точки [0,0,0] [0,1,0] [1,0,0] [1,1, 0]).

Поскольку я отображаю куб одинаковым образом, я заметил, что во всех случаях solvePnP дает правильные результаты, в то время как поза, полученная из омографии, в основном неверна.

ВТеория, так как мои точки копланарны, можно вычислить позу по омографии, но я не смог найти правильный способ вычислить позу из H.

Есть какие-нибудь идеи о том, что я делаю неправильно?

Редактировать после попытки метода @ Jav_Rock

Привет, Jav_Rock, большое спасибо за ваш ответ, я попробовал ваш подход (и многие другие), который кажется более или менееХОРОШО.Тем не менее, у меня все еще есть некоторые проблемы при вычислении позы, основанной на 4 копланарной точке.Чтобы проверить результаты, я сравниваю их с результатами solvePnP (что будет намного лучше благодаря подходу минимизации ошибок повторного проецирования).

Вот пример:

cube

  • Желтый куб: Решить PNP
  • Черный куб: техника Jav_Rock
  • Голубой (и фиолетовый) куб (ы): некоторые другие методы дают точно такие же результаты

Как вы можете видеть, черный куб более или менее в порядке, но не выглядит хорошо пропорциональным, хотя векторы кажутся ортонормированными.

EDIT2: Я нормализовал v3после его вычисления (для обеспечения ортонормированности), и это, похоже, также решает некоторые проблемы.

Ответы [ 6 ]

30 голосов
/ 28 мая 2012

Если у вас есть гомография, вы можете рассчитать позу камеры следующим образом:

void cameraPoseFromHomography(const Mat& H, Mat& pose)
{
    pose = Mat::eye(3, 4, CV_32FC1);      // 3x4 matrix, the camera pose
    float norm1 = (float)norm(H.col(0));  
    float norm2 = (float)norm(H.col(1));  
    float tnorm = (norm1 + norm2) / 2.0f; // Normalization value

    Mat p1 = H.col(0);       // Pointer to first column of H
    Mat p2 = pose.col(0);    // Pointer to first column of pose (empty)

    cv::normalize(p1, p2);   // Normalize the rotation, and copies the column to pose

    p1 = H.col(1);           // Pointer to second column of H
    p2 = pose.col(1);        // Pointer to second column of pose (empty)

    cv::normalize(p1, p2);   // Normalize the rotation and copies the column to pose

    p1 = pose.col(0);
    p2 = pose.col(1);

    Mat p3 = p1.cross(p2);   // Computes the cross-product of p1 and p2
    Mat c2 = pose.col(2);    // Pointer to third column of pose
    p3.copyTo(c2);       // Third column is the crossproduct of columns one and two

    pose.col(3) = H.col(2) / tnorm;  //vector t [R|t] is the last column of pose
}

Этот метод работает от меня. Удачи.

9 голосов
/ 09 июля 2015

Ответ, предложенный Jav_Rock, не обеспечивает правильного решения для поз камеры в трехмерном пространстве.

Для оценки трехмерного преобразования и поворота, вызванного гомографией, существует несколько подходов. Один из них предоставляет закрытые формулы для разложения гомографии, но они очень сложны. Кроме того, решения никогда не бывают уникальными.

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

8 голосов
/ 26 ноября 2014

На всякий случай, если кому-то понадобится портирование на python функции, написанной @Jav_Rock:

def cameraPoseFromHomography(H):
    H1 = H[:, 0]
    H2 = H[:, 1]
    H3 = np.cross(H1, H2)

    norm1 = np.linalg.norm(H1)
    norm2 = np.linalg.norm(H2)
    tnorm = (norm1 + norm2) / 2.0;

    T = H[:, 2] / tnorm
    return np.mat([H1, H2, H3, T])

Прекрасно работает в моих задачах.

6 голосов
/ 14 мая 2015

Вычисление [R | T] из матрицы гомографии немного сложнее, чем ответ Jav_Rock.

В OpenCV 3.0 есть метод с именем cv :: degposeHomographyMat, который возвращает четыре потенциальных решения, одно из которыхверно.Однако OpenCV не предоставил метод, чтобы выбрать правильный.

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

0 голосов
/ 18 июля 2016

На самолете, в котором находится ваш Квадрат на изображении, присутствуют исчезающие полосные агенты вашей камеры.Уравнение этой линии: A x + B y + C = 0.

Нормаль вашей плоскости равна (A, B, C)!

Пусть p00, p01, p10, p11 - координаты точки после применения внутренних параметров камеры и в однородной форме, например, p00 = (x00, y00,1)

Линия исчезновения может быть рассчитана как:

  • вниз = р00 кросс р01;
  • влево = крест p00 p10;
  • вправо = крест p01 p11;
  • up = p10 cross p11;
  • v1 = левый крест вправо;
  • v2 = вверх крест вниз;
  • vanish_line = v1 cross v2;

Где cross в стандартном векторном перекрестном произведении

0 голосов
/ 09 марта 2015

Вот версия python, основанная на версии, предоставленной Дмитрием Волошиным, которая нормализует матрицу вращения и переносит результат в 3x4.

def cameraPoseFromHomography(H):  
    norm1 = np.linalg.norm(H[:, 0])
    norm2 = np.linalg.norm(H[:, 1])
    tnorm = (norm1 + norm2) / 2.0;

    H1 = H[:, 0] / norm1
    H2 = H[:, 1] / norm2
    H3 = np.cross(H1, H2)
    T = H[:, 2] / tnorm

    return np.array([H1, H2, H3, T]).transpose()
...