简单快速的多图像拼接---百图拼接---左右左拼图(之字)

前面我们已经完成一圈拼图,现在第加上后面的二圈,先左,再右,后左

总流程:

1。选择图像来源(文件名)

1。默认文件名(list.txt)

或2。命令行选择列表名(以图标拖放的方式选择文件)



2.载入图像,检测特征,串联匹配


3。计算图像位置和颜色调整比值

1。计算匹配图像的相对位置

2。以第一张图左上角点为原点,找到所有图的位置

4。找到第一圈的头尾

1。以前10个图的x递增(减)方向 也就是在前10个图中找到和第一个图距离最大值

2。接着向后查找最大值,当当前值达到最大值的一半时,结束查找



5。调平(根据两头偏差)

1。从头尾匹配

2.取得匹配相对位移

3.校正 中间图的位置(按距离远近)

6。颜色中间值为标准校正图像


第一圈--------------结束


7。后面的每个图对第一圈匹配,并调整位置


第二三圈------------结束

8。再计算最小,最大边界,确定大图宽、高


9。对所有位置排序,从左到右(我们的最佳缝合线只能从左到右)


10。再把所有图像放到大图中(多频段图像融合)

int main(int argc, char *argv[])
{
	//选择图像来源-----------------------------------------------开始
	//以图标拖放的方式选择文件
	//1。默认文件名
	char name[]="list.txt"; 
	char* list  =name; //你拍摄的用于全景的视频文件名

	//2。命令行选择列表名
	if (argc == 2) {
		list=argv[1]; //命令行,和图标拖放
    }
	//选择图像来源-----------------------------------------------结束

	//载入图像,检测特征,串联匹配---------------------------------开始
	unsigned int num;//总数

	cout << "多图像拼接已经开始了..."<< endl;
		
	num=setListGetNum( list) ;
	//cout << "有 "<<num<<" 个图"<< endl;
	//载入图像,检测特征,串联匹配---------------------------------结束

	//图像位置和颜色调整值-----------------------------------------------------------------------开始
	vector<cv::Point2f> position_2; // position_da[i]表示第i个图像i+1的相对位置(前+这=后)
	vector<float> colors;//colors[i]表示第i个图像和第1图匹配颜色的比值
	vector<cv::Point2f> position_da; // position_da[i]表示第i个图像在大图中的位置(左上角)

	Point2f position_s=Point2f(0,0);
	position_da.push_back (position_s); // 第1个图像为原点


	float c=1.0;//颜色比率;
	colors.push_back (c);

	float c_2=0;//颜色比率;


	for (unsigned int i=1;i<num;i++)
	{
		//3。计算匹配图像的相对位置
		cout <<i-1<<","<<i<<endl;
		Point2f a = getOffsetStitch(i-1,i,c);//取得匹配相对位移

		colors.push_back (c);

		position_2.push_back (a);//保存相对位置
		cout << "两个相差:"<<a<< endl;

		//4。以第一张图左上角点为原点,找到所有图的位置
		//在大图的位置
		position_s.x=position_s.x+a.x;
		position_s.y=position_s.y+a.y;
		position_da.push_back (position_s);
		cout << "当前位置:"<<position_s<< endl;
	}
	//图像位置和颜色调整值-----------------------------------------------------------------------结束


	//两头调平-------------------------------------------------------------------------开始
	int minl=0,maxr=0;//头、尾  //只对一圈
	{
		//大于2圈找尾部(视频需要左右左,右左右 转圈)
		//1。以前10个图的x递增(减)方向 也就是在前10个图中找到和第一个图距离最大值
		unsigned int s=(num<10)?num:10;
		float xmin=0,xmax=0;

		for (unsigned int i=0;i<s;i++)
		{
			if(position_da[i].x<xmin){
				xmin=position_da[i].x;
				minl=i;

			}
			if(position_da[i].x>xmax){
				xmax=position_da[i].x;
				maxr=i;
			}
		}
		//2。接着向后查找最大值,当当前值达到最大值的一半时,结束查找
		bool lr;//向右=true;向左=false
		if(maxr>minl)//向右转圈
		{
			lr=true;
		}else{//向左转圈
			lr=false;
		}
		for(unsigned int i=10;i<num;i++)
		{
			if(position_da[i].x<xmin){
				xmin=position_da[i].x;
				minl=i;

			}
			if(position_da[i].x>xmax){
				xmax=position_da[i].x;
				maxr=i;
			}
			if(lr){
				if(position_da[i].x<xmax/2)
					break;

			}else{
				if(position_da[i].x>xmin/2)
					break;
			}

		}



		//3。把前面的最大值和最小值作为第一圈的左右边界 调平
		cout << "头,尾:"<<minl<<","<<maxr<< endl;

		//1。从头尾匹配
		int pp;
		Point2f a = getOffsetStitch(pp,minl,maxr);//取得匹配相对位移
		cout << "两个相差:"<<a<< endl;

		if(pp>15){
			float yn=-(a.y-(position_da[maxr].y-position_da[minl].y));//总校正量  =需要校正量-(已经校正量)
					cout << "总校正量:"<<yn<< endl;

			//校正 中间图的位置(按距离远近)
			//计算单位校正量
			float xd=	position_da[maxr].x-position_da[minl].x;//总距离
			float y校正量=yn/xd;//单位x的y校正量
					cout << "单位校正量:"<<y校正量<< endl;
			for (int j=minl;j<maxr;j++)//以maxr为标准
			{
				position_da[j].y+=(position_da[maxr].x-position_da[j].x)*y校正量;
			}

			//对minl前面的 + minl的校正量
			for(int i=0;i<minl;i++)
				position_da[i].y+=yn;

			//对maxr后面的 + maxr的校正量
			//以maxr为标准,后面不用校正
		}
		//
	

	}
	//两头调平-------------------------------------------------------------------------结束
	//debugWriteFile("maxr:");
 //   debugWriteFile(maxr);//调试写中间值到文件

	//上面是以第一个图为参考点,还是平均值点为标准------------------开始
	//只平均第一圈,后面的颜色,单独匹配(和前面)
	c=0;
	for (unsigned int i=0;i<maxr;i++)
	{
		c+=colors[i];
	}
	c/=maxr;//平均值
	for (unsigned int i=0;i<colors.size ();i++)
	{
		colors[i]/=c;
	}
	//颜色中间值为标准------------------------------------------------结束

	//-=-=-=-=-=-=-=-=-=-=-=-=-第一层-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=结束
	Mat img0=getimg(0);
	//第二圈及以后
	//对maxr以后的设立置信度,置信度低的不绘上
	vector<cv::Point2i> maxr_后_置信度;
	{

		for(unsigned int i=maxr+1;i<num;i++)
		{
			Point2i 置信度=Point2i(i,0);

			cout<<"第#"<<i<<" 个,还有 "<<num-i<<" 个"<<endl;
			//1。跳回以前2张向前找,找到当前的和前面距离(小于一张图宽,高)的最近的哪1张
			float minjl=100000000.0;//距离
			int minj=-1;//最近的
			//int js=0;//计数
			for ( int j=0;j<maxr+1;j++)
			{
				//if(j>maxr+maxr_后_置信度.size()||(j>maxr && j<maxr+maxr_后_置信度.size() && maxr_后_置信度[j-maxr-1].y==0))//第一圈 或 j的置信度不为0
				//	continue;
				float x=position_da[i].x-position_da[j].x;
				float y=position_da[i].y-position_da[j].y;
				//cout<<"x,y:"<<x<<","<<y<<endl;
				//cout<<"rows,cols:"<<img0.rows <<","<<img0.cols<<endl;

				if(abs(x)<img0.cols*7/8 && abs(y)<img0.rows*7/8 )
				{
					float tmp=x*x+y*y;

					if(minjl>tmp){
						minjl=tmp;
						minj=j;

					}
					//if(js++>5)
					//	break;
				}//正向
			}
			if(minj!=-1)
			{
				int pp;//置信度(匹配数)
				//Point2f a = getOffsetStitch(pp,minj,i);//取得匹配相对位移
				c=1;
				Point2f a = getOffsetStitch(pp,minj,i,c);//取得匹配相对位移 和颜色比

				cout<<"*对#"<<minj<<" 和 "<<i<<" 匹配"<<endl;
				cout << "两个相差:"<<a<< endl;

				if(pp>20){//&& tmp!=1
					//2。匹配,调整后面的
							int src=minj;
							int dis=i;

							//colors[dis]=colors[src]/c;//匹配调整颜色

							//在大图的位置
							//新的位置
							//1。只调整当前位置
							position_da[dis].x=position_da[src].x+a.x;
							position_da[dis].y=position_da[src].y+a.y;

							//2。后面也调整
							position_s.x=position_da[src].x+a.x;
							position_s.y=position_da[src].y+a.y;
							//差值(新 - 老)
							position_s.x-=position_da[dis].x;
							position_s.y-=position_da[dis].y;
							cout << "位置差值:"<<position_s<< endl;



							//加上差值
							for (unsigned int k=dis;k<num;k++)
							{
								position_da[k].x+=position_s.x;
								position_da[k].y+=position_s.y;
							}
							置信度.y=pp;
				}
			}
			maxr_后_置信度.push_back (置信度);
		
		}//3。直到结束

	}


	//再计算最小,最大边界
	float xmin=0,xmax=0,ymin=0,ymax=0;
	for (unsigned int i=1;i<position_da.size ();i++)
	{
		xmin=(position_da[i].x<xmin)?position_da[i].x:xmin;
		xmax=(position_da[i].x>xmax)?position_da[i].x:xmax;
		ymin=(position_da[i].y<ymin)?position_da[i].y:ymin;
		ymax=(position_da[i].y>ymax)?position_da[i].y:ymax;
	}



	//计算大图宽高
	int h = (int)(img0.rows + ymax-ymin+0.5);//拼接图行数(高度)
	int w = (int)(img0.cols + xmax-xmin+0.5);//拼接图列数(宽度)
	cout<<"大图宽,高:"<<w<<","<<h<<endl;

	Mat stitch = Mat::zeros(h, w, CV_8UC3);

	//对所有位置排序,从左到右
	vector<int> da_x=	da_sort(position_da);	//对 position_da 排序( x 值)  返回一个顺序索引


	//计算各图匹配点亮度比例
	//vector<float> 比_colors;//比_colors[i]表示第i个图像颜色和第一个图的比值
								//亮度比值,第一个为1,其它相对于第一个

	//再把所有图像放到一个大图中(拼接)
	for (unsigned int j=0;j<position_da.size ();j++)
	{
		unsigned int i=da_x[j];//j;//

		if(i>maxr && maxr_后_置信度[i-(maxr+1)].x==i-(maxr+1) && maxr_后_置信度[i-(maxr+1)].y<30)
			continue;

		Mat im = getimg(i);;//读出一个图

		//1。亮度直接调整
		//im/=比_colors[i];//按比值反向修正

		//2。Lab颜色空间调整亮度---------------------------------------开始
		{
			//将RGB图像转换为Lab图  
			Mat LabImage;  
			Mat Image[3];  
			cvtColor(im, LabImage, COLOR_BGR2Lab);  
			split(LabImage, Image);  //分解成三个通道
			//imshow("L", Image[0]);  imshow("a", Image[1]); imshow("b", Image[2]);  imshow("Lab", LabImage);  

			Mat im_L=Image[0];//Mat im_a=Image[1];//Mat im_b=Image[2];
			//计算L通道平均值//或者匹配区
			im_L/=colors[i];//按比值反向修正 L通道

			//合回3通道图
			merge(Image,3, LabImage);
			//将Lab图像转换为RGB图  
			//Mat RGBImage;  
			cvtColor(LabImage, im, COLOR_Lab2BGR);  
		}
		//Lab颜色空间调整亮度---------------------------------------结束

		float x=position_da[i].x-xmin;
		float y=position_da[i].y-ymin;

		cout<<"**x,y:"<<x<<","<<y<<endl;

		if(i==0){//第一个图
		//1。直接复盖拼接
			Mat roi2(stitch, Rect(x, y, im.cols, im.rows));
			im(Range(0, im.rows), Range(0, im.cols)).copyTo(roi2);
		}
		//2。权重融合(两边)
		//融合2(im,stitch,Point2f(x,y));

		else if( position_2[i-1].x<0) //i!=0 &&//<0 就是右合左
		//3。多频段图像融合
			融合3(im,stitch,Point2f(x,y));

		else{
		//4。多频段图像融合+最佳缝合线(只能左向右,否则这里先反向,回来再反向)
			//if(i!=0)
				融合(im,stitch,Point2f(x,y),position_2[i-1]);
			//else
			//{//第一个图
			//	Mat roi2(stitch, Rect(x, y, im.cols, im.rows));
			//	im(Range(0, im.rows), Range(0, im.cols)).copyTo(roi2);
			//}
		}

	}
    imshow("拼接结果", stitch);
    imwrite("stitch.jpg", stitch);
		waitKey();

	return 0;
}
效果图:


好象不怎么样

只有图像位置基本准确(除了中间底下几张)

用第一圈的覆盖一遍


好象好了一点了,看来要先绘制后面的。


把权重融合加上 上下融合和四角融合


接缝稍稍好了一点

把最佳缝合线的上下两边和四角加上权重融合


重影没有了,把融合宽度加大一点


两端颜色相差太多了,调平一下

其它向第一圈对准


全部86张用时:

177.183秒!3分钟还不到



  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值