opencv 基于sift的多张图片全景图拼接

这里是基于sift来寻找特征点经行图像的匹配的原理来进行图像拼接的,具体步骤如下:

1、利用sift特征探测器来检测出两幅图片的sift特征点



2根据上一步提取到的特征点来提取特征向量,使用SiftDescriptorExtractor对完成特征向量提取的工作,通过他对关键点周围邻域内的像素分块进行梯度运算,得到128维的特征向量



3、进行特征向量临近匹配,找到两幅图之间相互匹配的特征点


匹配之后的结果如下图:(2张图片的)

opencv 基于sift的多张图片全景图拼接_第1张图片

4、在第一次匹配的基础上再进行筛选,算出匹配的特征向量之间的距离,然后只去向量距离小于2倍的最小距离的特征点

opencv 基于sift的多张图片全景图拼接_第2张图片

这样得到的结果为:

opencv 基于sift的多张图片全景图拼接_第3张图片

5、 通过随机抽样 一致 RANSAC算法找出特征点之间的映射关系,求出单应矩阵H


6、判断两幅图在结果图中的左边还是右边,这里是根据特征点在图像的位置来判断的,求出图像上特征点的x坐标大于图像宽的一半的特征点数量与总的特征点数量的比值,比值大的就是在结果图的右边

opencv 基于sift的多张图片全景图拼接_第4张图片

7、 把第 6 步算得的右图经过透视转换转换到结果图中,这里要使用单应矩阵 H 再把计算得到的左图放到结果图中:

opencv 基于sift的多张图片全景图拼接_第5张图片

部分拼接结果:

opencv 基于sift的多张图片全景图拼接_第6张图片

opencv 基于sift的多张图片全景图拼接_第7张图片

opencv 基于sift的多张图片全景图拼接_第8张图片


opencv 基于sift的多张图片全景图拼接_第9张图片

源代码为:(为了方便测试我把图像都命名为1.jpg 2.jpg .......)

#include 
#include
#include
#include
#include
#include
#include
#include 
using namespace std;
using namespace cv;
Mat Stitched(Mat img1, Mat img2) {
	Mat g1(img1, Rect(0, 0, img1.cols, img1.rows));
	Mat g2(img2, Rect(0, 0, img2.cols, img2.rows));
	cvtColor(g1, g1, CV_BGR2GRAY);
	cvtColor(g2, g2, CV_BGR2GRAY);
	SiftFeatureDetector siftdet;
	vectorkp1, kp2;
	//SIFT sift;
	SiftDescriptorExtractor extractor;
	Mat descriptor1, descriptor2;
	FlannBasedMatcher matcher;
	vector matches, goodmatches;
	/*进行特征点提取*/
	siftdet.detect(g1, kp1);
	siftdet.detect(g2, kp2);
	/* 进行特征向量提取 */
	extractor.compute(g1, kp1, descriptor1);
	extractor.compute(g2, kp2, descriptor2);
	/* 进行特征向量临近匹配 */
	matcher.match(descriptor1, descriptor2, matches);
	Mat  firstmatches;
	/*画出第一次匹配的结果*/
	drawMatches(img1, kp1, img2, kp2,
		matches, firstmatches, Scalar::all(-1), Scalar::all(-1),
		vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
	imshow("first_matches", firstmatches);
	/* 下面计算向量距离的最大值与最小值 */
	double max_dist = 0; double min_dist = 1000;
	for (int i = 0; i < descriptor1.rows; i++) {
		if (matches[i].distance > max_dist) {
			max_dist = matches[i].distance;
		}
		if (matches[i].distance < min_dist) {
			min_dist = matches[i].distance;
		}
	}
	cout << "The max distance is: " << max_dist << endl;
	cout << "The min distance is: " << min_dist << endl;
	for (int i = 0; i < descriptor1.rows; i++) {
		if (matches[i].distance < 2 * min_dist) {
			goodmatches.push_back(matches[i]);
		}
	}
	Mat img_matches;
	/*第二次筛选后的结果*/
	drawMatches(img1, kp1, img2, kp2,
		goodmatches, img_matches, Scalar::all(-1), Scalar::all(-1),
		vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
	imshow("good_matches", img_matches);
	vector keypoints1, keypoints2;
	for (int i = 0; i < goodmatches.size(); i++) {
		keypoints1.push_back(kp1[goodmatches[i].queryIdx].pt);
		keypoints2.push_back(kp2[goodmatches[i].trainIdx].pt);
	}
	/*计算单应矩阵*/
	Mat H = findHomography(keypoints1, keypoints2, CV_RANSAC);
	Mat stitchedImage;
	int mRows = img2.rows;
	if (img1.rows> img2.rows)
	{
		mRows = img1.rows;
	}
	/*判断图像在左边还是在右边*/
	int propimg1 = 0, propimg2 = 0;
	for (int i = 0; i < goodmatches.size(); i++) {
		if (kp1[goodmatches[i].queryIdx].pt.x > img1.cols / 2) {
			propimg1++;
		}
		if (kp2[goodmatches[i].trainIdx].pt.x > img2.cols / 2) {
			propimg2++;
		}
	}
	bool flag = false;
	Mat imgright;
	Mat imgleft;
	if ((propimg1 / (goodmatches.size() + 0.0)) > (propimg2 / (goodmatches.size() + 0.0))) {
		imgleft = img1.clone();
		flag = true;
	}
	else {
		imgleft = img2.clone();
		flag = false;
	}
	if (flag) {
		imgright = img2.clone();
		flag = false;
	}
	else {
		imgright = img1.clone();
	}
	/*把上边求得的右边的图像经过矩阵H转换到stitchedImage中对应的位置*/
	warpPerspective(imgright, stitchedImage, H, Size(img2.cols + img1.cols, mRows));
	/*把左边的图像放进来*/
	Mat half(stitchedImage, Rect(0, 0, imgleft.cols, imgleft.rows));
	imgleft.copyTo(half);
	return stitchedImage;
}
int main() {
	Mat img1 = imread("1.jpg");
	Mat  stitchedImage;
	int n;
	cout << "Dataset2" << endl;
	cout << "请输入想拼接的图片数量(大于1小于18)" << endl;
	cin >> n;
	cout << "输入成功,开始计时" << endl;
	clock_t start,finish;  
    double totaltime;
    start=clock();  
	resize(img1, img1, Size(img1.cols / 4, img1.rows / 4));
	for (int k = 2; k <= n; k++) {
		stringstream stream;
		string str;
		stream << k;
		stream >> str;
		string filename = str + ".jpg";
		cout << "正在拼接......." << filename << endl;
		Mat img = imread(filename);
		resize(img, img, Size(img.cols / 4, img.rows / 4));
		stitchedImage = Stitched(img1, img);
		img1 = stitchedImage;
	}
	finish = clock();
	totaltime = (double)(finish - start) / CLOCKS_PER_SEC;
	cout << "拼接成功" << endl;
	cout << "拼接花费总时间为:" << totaltime << "秒!" << endl;
	imshow("ResultImage", stitchedImage);
	imwrite("ResultImage.jpg", stitchedImage);
	waitKey(0);
	return 0;
}


你可能感兴趣的:(计算机视觉,opencv)