图像拼接(十三):OpenCV拼接多幅图像(以中间图像为参考)

图像拼接(七):OpenCV单应变换模型拼接多幅图像 这篇博客中实现了用单应变换模型拼接多幅图像,图像拼接使用的OpenCV库函数warpPerspective()

因为这个函数只有在右侧图像变换到左侧图像时才能完整显示,所以拼接过程选择了以最左侧图像为参考帧。由于累加误差,最右侧的图像出现严重的变形。如下所示:

这里写图片描述

在这篇博客中,我们以中间幅图像为参考图像,实现多幅拼接。图像数量为4张,从左到右分别为img4img4img3img3img2img2img1img1。以左侧第2幅图像,即img3img3为参考图像。

从右到左,img2img2img1img1的单应变形仍可直接使用warpPerspective(),那么从左到右,img4img4img3img3怎么办呢?

解决的办法是对img3img3添加一个向右距离为img3.width的平移变换。这样变形后的img4img4即可显示在画布中了。

这个平移变换矩阵为:

Tx=[10img3.cols010001]Tx=\begin{bmatrix} 1&0&img3.cols\\0&1&0\\0&0&1\end{bmatrix}

img3img3 点座标设为XX'img4img4点座标设为XX,则他们之间的关系为:
TxX=TxH43XTx*X'=Tx*H_{43}*X

所以img4img4img3img3变换后的图像如下,注意img3img3的原点向右位移至中间。在之后的拼接中要考虑这一点。

img4img4->img3img3
这里写图片描述

其它图像之间的变换:

img2img2->img3img3
这里写图片描述

img1img1->img3img3
这里写图片描述

所有的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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章