Вычисление позы камеры с матрицей гомографии на основе 4 копланарных точек

У меня есть 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 с результатами, полученными методом OpenCV resolvePnP (используя следующие трехмерные точки [0,0,0] [0,1,0] [1,0,0] [1,1 , 0]).

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

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

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

Отредактируйте после использования метода @Jav_Rock

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

Вот пример:

куб

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

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

РЕДАКТИРОВАТЬ2: Я нормализовал v3 после его вычисления (для обеспечения ортонормированности), и, похоже, он также решает некоторые проблемы.


person JimN    schedule 19.01.2012    source источник
comment
Итак, opencv Solvepnp дает правильные результаты, в то время как ваша реализация неверна?   -  person nav    schedule 28.01.2012
comment
Да, resolvePnP дает правильные результаты, в то время как моя реализация с использованием только омографий не дает правильных векторов вращения / перевода.   -  person JimN    schedule 30.01.2012
comment
Если вы поделитесь своим кодом, мы сможем его просмотреть и посмотреть, как его можно исправить. Одна вещь, которую вы могли забыть, - это принудительная ортонормированность матрицы вращения.   -  person fireant    schedule 26.05.2012
comment
Я считаю, что у вас есть все необходимые шаги: 1.-Получение встроенных функций камеры 2.-Определите 4-точечные соответствия и вычислите H с помощью DLT 3.-Умножьте H влево с помощью K.inv () 4.-Разложите результат, как объяснено автор: @Jav_Rock   -  person marcos.nieto    schedule 25.10.2013
comment
Я пробовал оба метода, но все время получаю неверные результаты. С SolvePnP, по крайней мере, некоторые части моего воображения проекции. Не могли бы вы взглянуть на мой вопрос, чтобы дать ответ? stackoverflow.com/a/29078048/663551   -  person Jakob Alexander Eichler    schedule 17.03.2015
comment
Привет. Может ли кто-нибудь помочь мне решить мой последний вопрос? Это что-то похожее на этот вопрос, но я не совсем уверен, как мне использовать решение, представленное ниже. Как позвонить cameraPoseFromHomography? Какой параметр - H, а какой - поза? Как нарисовать куб, как на изображении вопроса? Пожалуйста, помогите мне, потому что я не знаю, как продолжить! Приветствую, Джонас (Вы можете найти вопрос здесь: stackoverflow.com/questions/51009968/how-to -draw-cube-c)   -  person    schedule 24.06.2018


Ответы (7)


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

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
}

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

person Jav_Rock    schedule 28.05.2012
comment
Привет, Jav_Rock, большое спасибо за ответ, я попробовал ваш метод и отредактировал пост, чтобы вы могли увидеть полученные результаты. Спасибо еще раз. - person JimN; 20.06.2012
comment
Думаю изображение не видно. В любом случае, если вы хотите углубиться в теорию, вы можете прочитать этот вопрос на dsp.stackexchange dsp.stackexchange.com/q/ 2736/1473 - person Jav_Rock; 29.06.2012
comment
Либо я не понимаю (код на 100% такой же, как у вас), либо OpenCV изменил способ обработки объекта Mat с тех пор, как вы опубликовали этот ответ. Использование таких присваиваний, как ваше (p1, p2 ...), НЕ изменяет аргумент позы и приводит к результирующей позе, идентичной ее инициализации - единичной матрице 3x4. Использование copyTo () решает проблему. Похоже, нужна глубокая копия. Проверьте ответ @ Jacob на stackoverflow.com/questions/6411476/ - person rbaleksandar; 19.06.2014
comment
Я попытался перевести код на Java, но мои результаты плохие. - person Jakob Alexander Eichler; 17.03.2015
comment
Рекомендуется ли оценивать позу камеры с помощью SolvePnP или гомографии? - person Jakob Alexander Eichler; 26.03.2015
comment
Почему перед копированием первых двух столбцов необходима нормализация? - person Gaurav Fotedar; 12.05.2015
comment
@Jav_Rock, как ваш подход работает без использования встроенной камеры? - person alexburtnik; 16.05.2017
comment
Эй, ребята. Я вижу, что ответ @Jav_Rock отмечен как правильный, поэтому я почти уверен, что это рабочее решение вопроса, но, черт возьми, я действительно не могу понять, как мне использовать подход @Jav_Rock, чтобы получить трехмерный куб, как это упоминалось в вопросе. Какие параметры для cameraPoseFromHomography? Могу ли я рассчитать куб, не зная ничего, кроме четырех угловых точек прямоугольника? Любая помощь будет очень признательна. Привет - person ; 24.06.2018

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

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

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

person Emiswelt    schedule 09.07.2015
comment
Расчет выбора правильного решения из двух последних возможных решений очень сложен. Знаете ли вы какую-либо реализацию статьи, которая может вернуть одно решение из двух окончательных? - person Sanjeev Kumar; 18.02.2017
comment
@YonatanSimson Гомография описывает перспективное преобразование, задаваемое четырьмя копланарными точками. В вашем собственном ответе ниже используется матрица гомографии. В чем проблема? - person Emiswelt; 17.06.2020

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

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

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

person Yang Kui    schedule 14.05.2015
comment
Вы придумали, как выбрать правильное решение? - person Sanjeev Kumar; 18.02.2017

На всякий случай кому-то понадобится портирование на 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])

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

person Dmytriy Voloshyn    schedule 25.11.2014
comment
как это работает без внутренних параметров камеры? - person Mehdi; 03.09.2015
comment
@Mehdi Я полагаю, что гомография работает с нормализованными координатами: p '= K ^ (- 1) [p; 1]. - person Felix Goldberg; 22.08.2016

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

Нормаль вашего самолета (A, B, C)!

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

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

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

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

person DejanM    schedule 18.07.2016

Вы можете использовать эту функцию. Работает для меня.

def find_pose_from_homography(H, K):
    '''
    function for pose prediction of the camera from the homography matrix, given the intrinsics 
    
    :param H(np.array): size(3x3) homography matrix
    :param K(np.array): size(3x3) intrinsics of camera
    :Return t: size (3 x 1) vector of the translation of the transformation
    :Return R: size (3 x 3) matrix of the rotation of the transformation (orthogonal matrix)
    '''
    
    
    #to disambiguate two rotation marices corresponding to the translation matrices (t and -t), 
    #multiply H by the sign of the z-comp on the t-matrix to enforce the contraint that z-compoment of point
    #in-front must be positive and thus obtain a unique rotational matrix
    H=H*np.sign(H[2,2])

    h1,h2,h3 = H[:,0].reshape(-1,1), H[:,1].reshape(-1,1) , H[:,2].reshape(-1,1)
    
    R_ = np.hstack((h1,h2,np.cross(h1,h2,axis=0))).reshape(3,3)
    
    U, S, V = np.linalg.svd(R_)
    
    R = [email protected]([[1,0,0],
                   [0,1,0],
                    [0,0,np.linalg.det([email protected])]])@V.T
    
    t = (h3/np.linalg.norm(h1)).reshape(-1,1)
    
    return R,t
person saksham jindal    schedule 20.12.2020

Вот версия 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()
person Clay    schedule 09.03.2015