OpenCV单应变换模型拼接多幅图像--单向

看了《图像拼接(七):OpenCV单应变换模型拼接多幅图像》

《图像拼接(十三):OpenCV拼接多幅图像(以中间图像为参考)》两个博文,感觉思路和代码都非常好,

但是哪个结果是不能用的,所以我把它改一下用在这里。

流程:

1。在List.txt文件中读出图像文件名(便于前面的视频选图接力)(其中的文件名请按从左到右顺序排好,程序中不作检测,否则出错)

2。检测每个图的特征点

3。两两匹配

4。并记录两两的单应矩阵

5。从右到左变换

请准备好 2 至 8 个右边有部分重合的图。

main函数:

int main ()
{
	/*	特征点的提取与匹配 	*/
	vector<string> image_names; // image_names[i]表示第i个图像的名称

	LoadImageNamesFromFile("list.txt",image_names);//从list.txt文件装载图像文件名

	vector<vector<KeyPoint>> image_keypoints; // image_keypoints[i]表示第i个图像的特征点
	vector<Mat> image_descriptor; // image_descriptor[i]表示第i个图像的特征向量描述符
	//vector<vector<Vec3b>> image_colors; // image_colors[i]表示第i个图像特征点的颜色
	vector<vector<DMatch>> image_matches; // image[i]表示第i幅图像和第i+1幅图像特征点匹配的结果
	extract_features (image_names, image_keypoints, image_descriptor/*, image_colors*/); // 提取特征点
	match_features2 (image_descriptor, image_matches); // 特征点匹配

	image_descriptor.swap(vector<Mat>());//匹配完清除内存

	Mat img0 = imread(image_names[0]);//读出一个图
	//gms_match_features(image_keypoints,img0.size(),image_matches);


	//显示匹配
	//for (unsigned int i=0;i<image_matches.size ();i++)
	//{
	//	Mat img1 = imread(image_names[i]);
	//	Mat img2 = imread(image_names[i+1]);//读出一个图

	//	Mat show = DrawInlier(img1, img2, image_keypoints[i], image_keypoints[i+1], image_matches[i], 1);
	//	imshow("匹配图", show);
	//	char wname[255];
	//	sprintf(wname,"met%d.jpg",i);
	//	imwrite(String(wname),show);


	//	waitKey();
	//}

	//查找向应矩阵
	vector<Mat> im_Homography; // im_Homography[i]表示第i+1-->i的单应矩阵

	for (unsigned int i=0;i<image_matches.size ();i++)
	{

		//单应矩阵
		Mat h12 = myfindHomography(image_matches[i],  image_keypoints[i], image_keypoints[i+1] );


		Mat h21;
		invert(h12, h21, DECOMP_LU);
		im_Homography.push_back(h21);

	}
	vector<vector<KeyPoint>>().swap(image_keypoints);//已经用不到了,清除容器并最小化它的容量

	//拼接
	Mat canvas;
	int canvasSize=image_names.size()*1.5;
	unsigned int j=image_names.size();
		j--;
		Mat img2 = imread(image_names[j]);//读出最后的哪个图

	for (unsigned int i=0;i<image_matches.size ();i++)
	{
		//从后到前
		Mat img1;
		Mat h21;
		j--;
		if(j==image_matches.size ()-1){//最右图
			h21=im_Homography[j];
			//使用透视变换
			warpPerspective(img2, canvas, h21, Size(img0.cols*canvasSize, img0.rows));
			img1 = imread(image_names[j]);//读出最后的哪个图
			//拼接
			img1.copyTo(canvas(Range::all(), Range(0, img0.cols)));
		}
		else{//其它
			h21=im_Homography[j];

			Mat temp2=canvas.clone();        //保存拷贝
			warpPerspective(temp2, canvas, h21, Size(img0.cols*canvasSize, img0.rows));//一起透视变换
			img1 = imread(image_names[j]);//读出当前的哪个图
			img1.copyTo(canvas(Range::all(), Range(0, img0.cols)));//加当前(拼接)

		}
		imshow("拼接图",canvas);
		char wname[255];
		sprintf(wname,"can%d.jpg",i);
		imwrite(String(wname),canvas);

		
		waitKey();
	}
	return 0;
}

效果图:


这里是4张图


这里是到第5张图至,后面的图都已经没法用了。

list.txt内容分别为:

trees_000.jpg
trees_001.jpg
trees_002.jpg
trees_003.jpg
C:/Users/ASUS/Videos/38.jpg
C:/Users/ASUS/Videos/107.jpg
C:/Users/ASUS/Videos/173.jpg
C:/Users/ASUS/Videos/209.jpg
C:/Users/ASUS/Videos/237.jpg
C:/Users/ASUS/Videos/283.jpg
C:/Users/ASUS/Videos/323.jpg
C:/Users/ASUS/Videos/363.jpg
C:/Users/ASUS/Videos/543.jpg
C:/Users/ASUS/Videos/575.jpg
用到的函数:
//读入一行, 并且去掉结尾的换行符(如果有的话)
char *myfgets(char *s, FILE *fp1)
{
	char tmp[255];

	fgets(tmp,255, fp1);//读入一行

	char *ret=strrchr(tmp, 10);
	if(ret!=NULL){//去掉结尾的换行符(如果有的话)
			*ret='\0';//memset(ret, 0,1);
		 memcpy(s, tmp, strlen(tmp)+1);//包括\0
	
	}
	else
		return "no";//文件最后一行必须有一个换行符(空行)
	return "ok";

}

//从list.txt文件装载图像文件名
void LoadImageNamesFromFile(char* name,vector<string>& image_names)
{
		FILE *f = fopen(name, "r");

	if (f == NULL) {
	    printf("Error opening file List.txt for reading\n");
	    exit(1);
	}
	char s[255];
	while(1)
	{
		if (myfgets(s,f)=="ok")
			image_names.push_back(string(s));
		else
			break;
	}
}

/********************************************************************************************************
参数:
image_names[i] 第i个图像的名称; image_keypoints[i] 第i个图像的特征点;
image_descriptor[i] 第i个图像的特征向量(描述子); image_colors[i] 第i个图像特征点的颜色。
功能:
从一系列图像(image_names)中提取出它们的特征点保存在image_keypoints中,特征向量保存在image_descriptor中,
特征点的颜色保存在image_colors中。
*********************************************************************************************************/
bool extract_features (
	vector<string> image_names,
	vector<vector<KeyPoint>>& image_keypoints,
	vector<Mat>& image_descriptor//,
	//vector<vector<Vec3b>>& image_colors
)
{
	//Ptr<Feature2D> sift = xfeatures2d::SIFT::create (); // SIFT特征提取器
		//sift->detectAndCompute (image, noArray (), keypoints, descriptor);

	
		
	//Ptr<AKAZE> akaze = AKAZE::create();
		//akaze->detect(image, keypoints, descriptor);

			Ptr<ORB> orb = ORB::create(2100);
			orb->setFastThreshold(0);

		//int size;
		for (unsigned int k=0;k<image_names.size();k++)
		{
			string name=image_names[k];
			Mat img1 = imread(name);//data/nn_left.jpg
			if (img1.empty()) {
				printf("出现一个错误,没有找到图像:%s\n",name);
				return false;}

			// 提取特征并计算特征向量
			vector<KeyPoint> kp1;
			Mat d1;
			cout << "正在检测特征点: " << name << endl;
			
			orb->detectAndCompute(img1, Mat(), kp1, d1);
			image_keypoints.push_back(kp1);
			image_descriptor.push_back (d1);


			//cout << "保存角点颜色: " << endl;
			//vector<Vec3b> colors;
			//for (unsigned int i = 0; i < kp1.size(); i++)
			//{
			//	Point2f p = kp1[i].pt;
			//	colors.push_back(img1.at<Vec3b>((int)p.y, (int)p.x));
			//}
			//image_colors.push_back(colors);
		}

	return true;
}

/********************************************************************************************************
参数:
image_descriptor[i] 第i个图像的特征向量; image_matches[i] 第i个特征向量和第i + 1个特征向量匹配的结果。
功能:
对一组特征向量(image_descriptor)两两匹配,将结果保存在image_matches中。
*********************************************************************************************************/
void match_features2 (vector<Mat> image_descriptor, vector<vector<DMatch>>& image_matches)
{
	for (unsigned int i = 0; i < image_descriptor.size () - 1; i++)
	{
		cout << "正在匹配 " << i << " - " << i + 1 << endl;
		vector<DMatch> matches;
		//match_features1 (image_descriptor[i], image_descriptor[i + 1], matches);

		BFMatcher matcher(NORM_HAMMING);
		matcher.match(image_descriptor[i], image_descriptor[i + 1], matches);

		cout << "有 " << matches.size() << " 个匹配点" << endl;

		image_matches.push_back (matches);
	}
}

//利用findHomography函数利用匹配的关键点找出相应的变换:
Mat myfindHomography(std::vector< DMatch > & good_matches,  std::vector<KeyPoint>& keypoints_1,std::vector<KeyPoint> & keypoints_2 )
{
	//-- Localize the object from img_1 in img_2     //在img_2中定位来自img_1的对象
	std::vector<Point2f> obj;    
	std::vector<Point2f> scene;    
	    
	for(unsigned int i = 0; i < good_matches.size(); i++ )    
	{    
	  //-- Get the keypoints from the good matches    //从好的匹配中获取关键点
	  obj.push_back( keypoints_1[ good_matches[i].queryIdx ].pt );    
	  scene.push_back( keypoints_2[ good_matches[i].trainIdx ].pt );     
	}    
	    
	//两个平面上相匹配的特征点求出变换公式
	Mat H = findHomography( obj, scene, CV_RANSAC );    
	    
	return H;
}

结束。

猜你喜欢

转载自blog.csdn.net/juebai123/article/details/79586525