在圖像拼接(七):OpenCV單應變換模型拼接多幅圖像 這篇博客中實現了用單應變換模型拼接多幅圖像,圖像拼接使用的OpenCV庫函數warpPerspective()
。
因爲這個函數只有在右側圖像變換到左側圖像時才能完整顯示,所以拼接過程選擇了以最左側圖像爲參考幀。由於累加誤差,最右側的圖像出現嚴重的變形。如下所示:
在這篇博客中,我們以中間幅圖像爲參考圖像,實現多幅拼接。圖像數量爲4張,從左到右分別爲,,,。以左側第2幅圖像,即爲參考圖像。
從右到左,,的單應變形仍可直接使用warpPerspective()
,那麼從左到右,到怎麼辦呢?
解決的辦法是對添加一個向右距離爲img3.width
的平移變換。這樣變形後的即可顯示在畫布中了。
這個平移變換矩陣爲:
若 點座標設爲,點座標設爲,則他們之間的關係爲:
所以到變換後的圖像如下,注意的原點向右位移至中間。在之後的拼接中要考慮這一點。
->
其它圖像之間的變換:
->
->
所有的4幅圖像的拼接結果爲:
整體觀感相比圖像拼接(七):OpenCV單應變換模型拼接多幅圖像的結果提升不少,最右側圖像變形失真減輕。
代碼
#include"Homography.h"
int main()
{
//從右向左升序
string imgPath1 = "trees_003.jpg";
string imgPath2 = "trees_002.jpg";
string imgPath3 = "trees_001.jpg";
string imgPath4 = "trees_000.jpg";
Mat img1 = imread(imgPath1, CV_LOAD_IMAGE_GRAYSCALE);
Mat img2 = imread(imgPath2, CV_LOAD_IMAGE_GRAYSCALE);
Mat img3 = imread(imgPath3, CV_LOAD_IMAGE_GRAYSCALE);
Mat img4 = imread(imgPath4, CV_LOAD_IMAGE_GRAYSCALE);
Mat img1_color = imread(imgPath1, CV_LOAD_IMAGE_COLOR);
Mat img2_color = imread(imgPath2, CV_LOAD_IMAGE_COLOR);
Mat img3_color = imread(imgPath3, CV_LOAD_IMAGE_COLOR);
Mat img4_color = imread(imgPath4, CV_LOAD_IMAGE_COLOR);
Homography homo12(img1, img2);
Homography homo23(img2, img3);
Homography homo34(img3, img4);
Mat h12 = homo12.getHomography();
Mat h23 = homo23.getHomography();
Mat h34 = homo34.getHomography();
/*homo12.drawMatches();
homo23.drawMatches();
homo34.drawMatches();*/
//以從左至右第2幅圖像爲參考,即img3
Mat h13 = h23*h12;
Mat h43 = h34.inv(DECOMP_LU);
double scale_h13 = h13.at<double>(2, 2);
h13 = h13 / scale_h13;
double scale_h43 = h43.at<double>(2, 2);
h43 = h43 / scale_h43;
Mat warp1;
warpPerspective(img1_color, warp1, h13, Size(img3.cols * 4, img3.rows));
Mat warp2;
warpPerspective(img2_color, warp2, h23, Size(img3.cols * 4, img3.rows));
Mat warp4;
Mat Tx = (Mat_<double>(3, 3) << 1, 0, img3.cols, 0, 1, 0, 0, 0, 1);
warpPerspective(img4_color, warp4, Tx*h43, Size(img3.cols * 2, img3.rows));
imshow("warp1", warp1);
imshow("warp2", warp2);
imshow("warp4", warp4);
imwrite("warp1.jpg", warp1);
imwrite("warp2.jpg", warp2);
imwrite("warp4.jpg", warp4);
int d = img3.cols * 2 / 5;
int x2 = h23.at<double>(0, 2) + d;
int x1 = x2 + h12.at<double>(0, 2);
Mat canvas(img3.rows, img3.cols * 4, CV_8UC3);
img3_color.copyTo(canvas(Range::all(), Range(img3.cols, img3.cols*2)));
warp2(Range::all(), Range(x2, x1)).copyTo(canvas(Range::all(), Range(x2 + img3.cols, x1 + img3.cols)));
warp1(Range::all(), Range(x1, x1+img3.cols)).copyTo(canvas(Range::all(), Range(x1 + img3.cols, x1+img3.cols*2)));
warp4(Range::all(), Range(0, img3.cols)).copyTo(canvas(Range::all(), Range(0, img3.cols)));
canvas(Range::all(), Range(x1 + img3.cols * 2, img3.cols * 4)) = Scalar::all(0);
imwrite("canvas.jpg", canvas);
imshow("canvas", canvas);
waitKey(0);
return 0;
}