Как известно, в OpenCV я могу получить аффинное или перспективное преобразование между двумя изображениями:
estimateRigidTransform()
FeatureDetector
(SIFT, SURF, BRISK, FREAK, …), затем FlannBasedMatcher
а также findHomography()
Тогда я могу сделать:
warpAffine(img_src, img_dst, M)
warpPerspective(img_src, img_dst, H)
Но если у меня есть 3 или более изображений, и я уже нашел:
тогда я могу получить matix трансформации (img1 -> img3) просто добавить две матрицы?
M3 = M1 + M2;
H3 = H1 + H2;
Или какую из функций я должен использовать для этого?
Нет нужно умножать матрицы для получения каскадного эффекта. Я не буду вдаваться в математику, но применение преобразования к координатам — это вопрос умножения матриц. Если вам интересно узнать, почему это так, я отсылаю вас к этому хорошая статья в Википедии о каскадных матричных преобразованиях. Учитывая координату 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
соответственно.
Надеюсь это поможет!