Nie, musisz pomnożyć macierzy, aby uzyskać efekt kaskadowy. Nie wchodzę w matematykę, ale zastosowanie przekształcenia do współrzędnych jest kwestią wykonywania mnożenia macierzy. Jeśli jednak jesteś ciekawy, dlaczego tak się dzieje, odsyłam Cię do tego good Wikipedia article on cascading matrix transformations. Biorąc pod uwagę koordynować X
i macierzą transformacji M
, masz wyjście koordynować Y
przez:
Y = M*X
Tutaj używam *
odnieść się do mnożenia macierzy w przeciwieństwie do elementu mnożenie. To, co masz, to para macierzy transformacji, które przechodzą od img1
do img2
, następnie img2
do img3
. Musisz wykonać tę operację dwukrotnie.Tak więc, aby przejść od img1
do img2
gdzie X
należący do przestrzeni współrzędnych img1
mamy (zakładając, że używamy macierze afiniczne):
Y1 = M1*X
Następny, aby przejść od img2
do img3
, mamy:
Y2 = M2*Y1 --> Y2 = M2*M1*X --> Y2 = M3*X --> M3 = M2*M1
Dlatego, aby uzyskać pożądany efekt łańcucha, trzeba utworzyć nową matrycę tak, że M2
jest mnożona przez M1
. To samo, co H2
i H1
.
więc zdefiniować nową matrycę takie, że:
cv::Mat M3 = M2*M1;
Podobnie dla rzutowych macierzy, można zrobić:
cv::Mat H3 = H2*H1;
Jednak estimateRigidTransform
(wyjście jest M
w danym przypadku) daje macierz 2 x 3
. Jedna sztuczka polega na rozszerzeniu tej macierzy tak, aby stała się 3 x 3, gdzie dodajemy dodatkowy wiersz, gdzie wszystko jest 0 , z wyjątkiem dla ostatniego elementu, który jest ustawiony na 1. Dlatego też ostatni wiersz będzie taki, że staje się [0 0 1]
. Zrobilibyśmy to dla obu macierzy, pomnożylibyśmy je, a następnie wyodrębniliśmy tylko pierwsze dwa wiersze do nowej macierzy, aby utworzyć rurę w warpAffine
. Dlatego też zrobić coś takiego:
// 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);
Gdy mamy do czynienia z cv::Mat
a operatorem *
, it is overloaded to specifically perform matrix multiplication.
Można następnie użyć odpowiednio M3
i H3
do warpAffine
i warpPerspective
.
Mam nadzieję, że to pomoże!
Dziękuję bardzo! Ale mnożenie macierzy może być wykonane tylko wtedy, gdy liczba kolumn w 1-st macierzy jest równa liczbie rzędów w 2-macie macierzy. ** H - perspektywa (homografia) to macierz 3x3 ** i ** mogę zrobić: 'H3 = H1 * H2;' **. Ale ** matryca afiniczna to 2x3 ** i nie mogę po prostu pomnożyć dwóch matematycznych afiliacji, ** nie mogę tego zrobić: 'M3 = M1 * M2;' **. Jak mogę to zrobić w Affine Transformation - M? – Alex
'estimateRigidTransform();' daje mi macierz 2x3, 'i estimateAffine3D();' daje mi macierz 3x4. – Alex
@Alex - Dodałem informacje, które pomogą ci w 'estimateRigidTransform'. Przepraszam, że nie widziałem tego wcześniej. Jednak "estimateAffine3D" zajmuje się transformacją między chmurami punktów 3D na inne. Nie można tego użyć do zniekształcania obrazów, ponieważ obrazy są z natury przestrzenią współrzędnych 2D. – rayryeng