前面我们已经完成一圈拼图,现在第加上后面的二圈,先左,再右,后左
总流程:
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=.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分钟还不到