Không, bạn cần phải nhân ma trận để có được hiệu ứng xếp tầng. Tôi sẽ không đi vào toán học, nhưng việc áp dụng một phép biến đổi cho các tọa độ là vấn đề thực hiện phép nhân ma trận. Tuy nhiên, nếu bạn tò mò muốn biết lý do tại sao, tôi giới thiệu bạn đến số good Wikipedia article on cascading matrix transformations này. Cho một phối hợp X
và một ma trận chuyển đổi M
, bạn sẽ có được sản lượng phối hợp Y
bởi:
Y = M*X
Ở đây tôi sử dụng *
để chỉ ma trận nhân như trái ngược với nhân tố khôn ngoan. Những gì bạn có là một cặp ma trận chuyển đổi từ img1
đến img2
rồi img2
đến img3
. Bạn sẽ cần thực hiện thao tác này hai lần.Vì vậy, để đi từ img1
để img2
nơi X
thuộc về không gian toạ độ img1
, chúng tôi đã (giả sử chúng ta đang sử dụng các ma trận affine):
Y1 = M1*X
Tiếp theo, để đi từ img2
để img3
, ta có:
Y2 = M2*Y1 --> Y2 = M2*M1*X --> Y2 = M3*X --> M3 = M2*M1
Do đó, để có được hiệu ứng chuỗi mong muốn, bạn cần tạo một ma trận mới sao cho M2
được nhân với M1
. Tương tự như H2
và H1
.
Vì vậy, xác định một ma trận mới như rằng:
cv::Mat M3 = M2*M1;
Tương tự như vậy đối với ma trận projective, bạn có thể làm:
cv::Mat H3 = H2*H1;
Tuy nhiên, estimateRigidTransform
(đầu ra là M
trong trường hợp của bạn) mang đến cho bạn ma trận 2 x 3
. Một mẹo là tăng thêm ma trận này sao cho nó trở thành 3 x 3, trong đó chúng ta thêm một hàng bổ sung khi nó là tất cả 0 trừ cho phần tử cuối cùng, được đặt thành 1. Vì vậy, bạn sẽ có hàng cuối cùng sao cho nó trở thành [0 0 1]
. Bạn sẽ làm điều này cho cả hai ma trận, nhân chúng, sau đó trích xuất chỉ hai hàng đầu tiên vào một ma trận mới để đường ống vào warpAffine
. Vì vậy, làm một cái gì đó như thế này:
// 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);
Khi giao dịch với cv::Mat
và *
điều hành, it is overloaded to specifically perform matrix multiplication.
Sau đó, bạn có thể sử dụng M3
và H3
thành warpAffine
và warpPerspective
tương ứng.
Hy vọng điều này sẽ hữu ích!
Cảm ơn bạn rất nhiều! Nhưng phép nhân ma trận có thể được thực hiện chỉ khi số cột trong ma trận 1-st bằng với số hàng trong ma trận 2-nd. ** H - phối cảnh (homography) là một ma trận 3x3 **, và ** Tôi có thể làm: 'H3 = H1 * H2;' **. Nhưng ** ma trận affine là một 2x3 ** và tôi không thể đơn giản nhân hai ma trận affine, ** Tôi không thể làm: 'M3 = M1 * M2;' **. Làm thế nào tôi có thể làm điều này cho việc chuyển đổi Affine - M? – Alex
'EstimatedRigidTransform();' cung cấp cho tôi ma trận 2x3, 'và estimatedAffine3D();' cung cấp cho tôi ma trận 3x4. – Alex
@Alex - Tôi đã thêm thông tin để giúp bạn với 'EstimatedRigidTransform'. Tôi xin lỗi vì đã không nhìn thấy điều đó sớm hơn. Tuy nhiên, 'EstimatedAffine3D' giao dịch với sự chuyển đổi giữa một đám mây điểm 3D sang đám mây khác. Bạn không thể sử dụng hình ảnh đó để làm cong hình ảnh vì hình ảnh vốn là không gian tọa độ 2D. – rayryeng