Могу ли я просто добавить аффинные или перспективные (гомографические) матрицы преобразования?

Как известно, в OpenCV я могу получить аффинное или перспективное преобразование между двумя изображениями:

Тогда я могу сделать:

  • аффинное преобразование — с помощью warpAffine(img_src, img_dst, M)
  • Перспективное преобразование — с помощью warpPerspective(img_src, img_dst, H)

Но если у меня есть 3 или более изображений, и я уже нашел:

  • аффинно: M1 (img1 -> img2), M2 (img2 -> img3)
  • перспектива: H1 (img1 -> img2), H2 (img2 -> img3)

тогда я могу получить matix трансформации (img1 -> img3) просто добавить две матрицы?

  • аффинного преобразования: M3 = M1 + M2;
  • перспективного преобразования: H3 = H1 + H2;

Или какую из функций я должен использовать для этого?

6

Решение

Нет нужно умножать матрицы для получения каскадного эффекта. Я не буду вдаваться в математику, но применение преобразования к координатам — это вопрос умножения матриц. Если вам интересно узнать, почему это так, я отсылаю вас к этому хорошая статья в Википедии о каскадных матричных преобразованиях. Учитывая координату X и матрица преобразования M, вы получите выходную координату Y от:

Y = M*X

Здесь я использую * ссылаясь на матрица умножение в отличие от поэлементного умножения. Что у вас есть пара матриц преобразования, которые идут от img1 в img2 затем img2 в img3, Вам нужно будет сделать операцию дважды. Итак, чтобы перейти от img1 в img2 где X принадлежит координатному пространству img1, имеем (при условии, что мы используем аффинные матрицы):

Y1 = M1*X

Далее, чтобы перейти от img2 в img3, у нас есть:

Y2 = M2*Y1 --> Y2 = M2*M1*X --> Y2 = M3*X --> M3 = M2*M1

Поэтому, чтобы получить желаемый эффект цепочки, нужно создать новую матрицу такую, чтобы M2 умножается на M1, Такой же как H2 а также H1,

Итак, определите новую матрицу так, чтобы:

cv::Mat M3 = M2*M1;

Аналогично для ваших проективных матриц вы можете сделать:

cv::Mat H3 = H2*H1;

Тем не мение, estimateRigidTransform (выход M в вашем случае) дает вам 2 x 3 матрица. Один трюк состоит в том, чтобы увеличить эту матрицу так, чтобы она стала 3 x 3, где мы добавляем дополнительную строку, где все это 0 Кроме для последнего элемента, который установлен в 1. Следовательно, у вас будет последняя строка, так что он становится [0 0 1], Вы должны сделать это для обеих матриц, умножить их, а затем извлечь только первые две строки в новую матрицу для передачи в warpAffine, Поэтому сделайте что-то вроде этого:

// Create padded matrix for M1
cv::Mat M1new = cv::Mat(3,3,M1.type());
M1new.at<double>(0,0) = M1.at<double>(0,0);
M1new.at<double>(0,1) = M1.at<double>(0,1);
M1new.at<double>(0,2) = M1.at<double>(0,2);

M1new.at<double>(1,0) = M1.at<double>(1,0);
M1new.at<double>(1,1) = M1.at<double>(1,1);
M1new.at<double>(1,2) = M1.at<double>(1,2);

M1new.at<double>(2,0) = 0.0;
M1new.at<double>(2,1) = 0.0;
M1new.at<double>(2,2) = 1.0;

// Create padded matrix for M2
cv::Mat M2new = cv::Mat(3,3,M2.type());
M2new.at<double>(0,0) = M2.at<double>(0,0);
M2new.at<double>(0,1) = M2.at<double>(0,1);
M2new.at<double>(0,2) = M2.at<double>(0,2);

M2new.at<double>(1,0) = M2.at<double>(1,0);
M2new.at<double>(1,1) = M2.at<double>(1,1);
M2new.at<double>(1,2) = M2.at<double>(1,2);

M2new.at<double>(2,0) = 0.0;
M2new.at<double>(2,1) = 0.0;
M2new.at<double>(2,2) = 1.0;

// Multiply the two matrices together
cv::Mat M3temp = M2new*M1new;

// Extract out relevant rows and place into M3
cv::Mat M3 = cv::Mat(2, 3, M3temp.type());
M3.at<double>(0,0) = M3temp.at<double>(0,0);
M3.at<double>(0,1) = M3temp.at<double>(0,1);
M3.at<double>(0,2) = M3temp.at<double>(0,2);

M3.at<double>(1,0) = M3temp.at<double>(1,0);
M3.at<double>(1,1) = M3temp.at<double>(1,1);
M3.at<double>(1,2) = M3temp.at<double>(1,2);

Когда имеешь дело с cv::Mat и * оператор, он перегружен, чтобы специально выполнять умножение матриц.

Вы можете использовать M3 а также H3 в warpAffine а также warpPerspective соответственно.


Надеюсь это поможет!

5

Другие решения


По вопросам рекламы [email protected]