图像拼接

图像拼接的基本流程


(1) 图像预处理:对原始图像进行直方图匹配、平滑滤波、增强变换等数字图像
处理的基本操作,为图像拼接的下一步作好准备。

(2) 图像配准:图像配准是整个图像拼接流程的核心,配准的精度决定了图像的拼接质量。其基本思想是:首先找到待配准图像与参考图像的模板或特征点的对应位置,然后根据对应关系建立参考图像与待配准图像之间的转换数学模型将待配准图像转换到参考图像的坐标系中,确定两图像之间的重叠区域。精确配准的关键是寻找一个能很好描述两幅图像转换关系的数据模型。

(3) 图像合成:确定了两幅图像之间的转换关系模型,即重叠区域后,就需要根据重叠区域的信息将待拼接图像镶嵌成一个视觉可行的全景图。由于地形存在微小差别或拍摄条件不同等因素造成图像灰度(或亮度)差异,或者图像配准结果仍存在一定配准误差,为了尽可能地减少遗留变形或图像间的亮度(或灰度)差异对镶嵌结果的影响,就需要选择合适的图像合成策略。



目前,国内外学者提出了很多图像配准的方法,但是各种方法都与一定范围的应用领域有关系,具有各自不同的特点。它们一般由四个要素组成[9]:特征空间、相似性度量、搜索空间和搜索策略。

(1) 特征空间(feature space)
特征空间是从图像中提取的用于配准的信息。特征可以是图像的灰度值,也可以是边界、轮廓等结构特征,或是角点、高曲率点等显著特征,亦或是统计特征、高层结构描述与句法描述等[9-11]。

(2) 相似性度量(similarity metric)
相似性度量是度量配准图像特征之间的相似性。典型的相似性度量有灰度相关、相关系数、互信息等。基于图像特征配准算法,常采用的相似性度量一般建立在各种距离函数上,如欧式距离、街区距离、Hausdorff 距离等。特征空间代表参与配准的数据,相似性度量决定配准度,二者的结合可以忽略许多与配准不相关的畸变,突出图像的本质结构与特征。

(3) 搜索空间(search space)
图像配准问题是一个参数的最优化估计问题,搜索空间就是指所有可能的变换组成的空间,即待估计参数组成的空间。搜索空间的组成和范围由图像变换的类型和强度决定。图像变换分为全局变换和局部变换。全局变换将整幅数字图像作为研究对象,用一个参数矩阵来描述整个图像的变换参数,常见的全局几何变换有仿射变换、投影变换和非线性变换等;局部变换允许变换参数有位置依赖性,即各个单元的变换参数随其所处位置不同而不同。配准算法就是要在搜索空间找出一个使图像之间的相似性度量最佳的位置。

(4) 搜索策略(search strategy)
搜索策略是指在搜索空间中采用合适的方法找出平移、旋转等变换参数的最优估计。这对于减少配准特征和相似性度量的计算量具有重要意义。图像间的变换越复杂,搜索空间就越复杂,对搜索策略的要求就越高,因此选择合适的探索策略至关重要。常见的搜索策略有穷尽搜索、启发式搜索、广义Hough 变换、多尺度搜索、树与图搜索、序贯判决、线性规划、神经网络、遗传算法、模拟退火算法等等。每种方法都有它的优缺点,在很大程度上,搜索策略的选择取决于搜索空间的特性。

设计配准算法时首先确定图像的类型和成像畸变范围,然后根据图像配准的性能指标确定特征空间和搜索空间,最后选择合适的搜索策略找到能使待配准图像之间的相似性度量最大的最佳匹配关系模型。根据上述四个要素的不同选择,产生了各种具体的图像配准技术的不同分类方法。目前提出的用于图像配准的算法可以分为三大类型:基于区域灰度相关的匹配算法、基于特征相关的匹配算法和基于解释相似的算法[12]。图像配准技术经过多年的研究,每类方法中都包含了不同的具体实现途径以适应具体问题。其中,基于解释的图像匹配需要建立在图片自动判读的专家系统之上进行,至今尚未取得突破性的进展。

—————————————————————————————————————

作者:刘伟民

毕业于:中国科学院计算技术研究所   

 

 

   最近我在看图像拼接的东西,在这里普及一下知识。

    图像拼接就是将两幅图像(有公共部分)拼成一个大的图像。这个用在视频里面就是视频拼接。视频拼接中有着特殊的需求:

  1. 视频中的图像一般重叠面积比较大,因此容易找到对应点。
  2. 视频中的图像一般很难用到和人交互的东西,所以一般识别对应点应该是自动的过程。
  3. 视频拼接一般要求速度比较快,最好达到实时拼接的效果。

图像拼接的要求:

  1. 很多图像要自动识别出图像之间的序列关系,就是那幅图像应该和那副图像挨着。
  2. 图像不要求速度,但是要求精确,就是准确度比较高。
  3. 图像拼接可以加入人工成分,就是可以让人自己选定对应的点。

    在图像选完了对应的特征点之后就该进行图像对应特征点的计算,求出两幅图像的对应的透视变换关系。

    变换

    接下来进行拼接,将两幅图像合成一幅图像。

 

 

下面我们用SIFT特征进行一个简单的图像拼接过程:

步骤:

 提取图像特征

 对特征进行匹配,找到正确的匹配点

 根据这些特征对,进行透视变换矩阵计算。

 根据得到的透视变换矩阵,对两幅图像进行透视映射。

 将变换后的两幅图像加到一个图像中。

拼接实验:

素材图片:

 

基于sift特征的简易图像拼接程序

基于sift特征的简易图像拼接程序

基于sift特征的简易图像拼接程序

基于sift特征的简易图像拼接程序

 

下面是我拼接的结果:



基于sift特征的简易图像拼接程序

 

下面是*****的拼接结果:



基于sift特征的简易图像拼接程序

结果分析:

我的实验中的图像有的地方很亮,这个对图像进行加权融合就可以解决。

其效果和*****的差不多。

*****的拼接程序经常出现【拼接失败】的情况,我的程序更具有鲁棒性。

缺点:拼接速度没有*****的快。

 

基于sift特征的简易图像拼接程序

基于sift特征的简易图像拼接程序

基于sift特征的简易图像拼接程序

基于sift特征的简易图像拼接程序

基于sift特征的简易图像拼接程序 

基于sift特征的简易图像拼接程序

——————————————————————————————————————
算法描述 

procedure ImageMatching 

{ 

    输入FirstImage; 

    输入SecondImage; 

    //获得两幅图象的大小 

    Height1=GetImageHeight(FirstImage); 

    Height2=GetImageHeight(SecondImage); 

    Width1=GetImageWidth(FirstImage); 

    Width2=GetImageWidth(SecondImage); 

// 从第二幅图象取网格匹配模板 

    SecondImageGrid = GetSecondImageGrid(SecondImage); 

// 粗略匹配,网格在第一幅图象中先从左向右移动,再从下到上移动,每次移动一个网格间距,Step_Width 或Step_Height,当网格移出重叠区域后结束 

y=Heitht1-GridHeight; 

MinValue = MaxInteger; 

While ( y<Height1-OverlapNumber)//当网格移出重叠部分后结束 

{ 

       x=Grid_Width/2; //当网格位于第一幅图象的最左边时,A点的横坐标。 

       While ( x<(Width1-Grid_Width/2) ) 

{ 

           FirstImageGrid=GetImgaeGrid(FirstImgaeGrid, x, y); 

        differ=CaculateDiff(FirstImgaeGrid, SecondImageGrid);//计算象素值差的平 

                               //方和 

           if (differ<MinValue) 

           { 

              BestMatch_x=x; 

              BestMatch_y=y; 

              MinValue = differ; 

           } 

       x= x+Step_width; 

       } 

       y=y-Step_Height; 

}   

//精确匹配 

Step_Width= Step_Width/2; 

Step_Height= Step_Height/2; 

While ( Step_Height>0 & Step_Width>0)//当水平步长和垂直步长均减为零时结束 

{ 

    if(Step_Height==0)//当仅有垂直步长减为零时,将其置为1 

       Step_Height=1; 

    If(Step_Width==0) //当仅有水平步长减为零时,将其置为1 

       Step_Width=1; 

temp_x = BestMatch_x; 

temp_y = BestMatch_y; 

    for ( i= -1; i<1; i++) 

       for( j= -1; j<1; j++) 

       { 

           if ((i=0&j!=0)|(i!=0&j=0)) 

           { 

              FirstImageGrid=GetImgaeGrid(FirstImgaeGrid, 

temp_x+i*Step_Width, temp_y +j*Step_Height); 

           differ=CaculateDiff(FirstImgaeGrid, SecondImageGrid); 

       if (differ<MinValue) 

              { 

                  BestMatch_x=x; 

                  BestMatch_y=y; 

                  MinValue = differ; 

           } 

           } 

          } 

       Step_Height = Step_Height /2; 

       Step_Width = Step_Width/2; 

    } 

}  

——————————————————————————————————————

主要分为以下几个步骤:

(1) 读入两张图片并分别提取SIFT特征

(2) 利用k-d tree和BBF算法进行特征匹配查找

(3) 利用RANSAC算法筛选匹配点并计算变换矩阵

(3) 图像融合


SIFT算法以及RANSAC算法都是利用的RobHess的SIFT源码,前三个步骤RobHess的源码中都有自带的示例。


(1) SIFT特征提取

直接调用RobHess源码(RobHess的SIFT源码分析:综述)中的sift_features()函数进行默认参数的SIFT特征提取,主要代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. img1_Feat = cvCloneImage(img1);//复制图1,深拷贝,用来画特征点  
  2. img2_Feat = cvCloneImage(img2);//复制图2,深拷贝,用来画特征点  
  3.   
  4. //默认提取的是LOWE格式的SIFT特征点  
  5. //提取并显示第1幅图片上的特征点  
  6. n1 = sift_features( img1, &feat1 );//检测图1中的SIFT特征点,n1是图1的特征点个数  
  7. export_features("feature1.txt",feat1,n1);//将特征向量数据写入到文件  
  8. draw_features( img1_Feat, feat1, n1 );//画出特征点  
  9. cvNamedWindow(IMG1_FEAT);//创建窗口  
  10. cvShowImage(IMG1_FEAT,img1_Feat);//显示  
  11.   
  12. //提取并显示第2幅图片上的特征点  
  13. n2 = sift_features( img2, &feat2 );//检测图2中的SIFT特征点,n2是图2的特征点个数  
  14. export_features("feature2.txt",feat2,n2);//将特征向量数据写入到文件  
  15. draw_features( img2_Feat, feat2, n2 );//画出特征点  
  16. cvNamedWindow(IMG2_FEAT);//创建窗口  
  17. cvShowImage(IMG2_FEAT,img2_Feat);//显示  
检测出的SIFT特征点如下:

                 


(2) 利用k-d tree和BBF算法进行特征匹配查找,并根据最近邻和次近邻距离比值进行初步筛选

也是调用RobHess源码中的函数,加上之后的一些筛选处理,主要代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //根据图1的特征点集feat1建立k-d树,返回k-d树根给kd_root  
  2. kd_root = kdtree_build( feat1, n1 );  
  3.   
  4. Point pt1,pt2;//连线的两个端点  
  5. double d0,d1;//feat2中每个特征点到最近邻和次近邻的距离  
  6. int matchNum = 0;//经距离比值法筛选后的匹配点对的个数  
  7.   
  8. //遍历特征点集feat2,针对feat2中每个特征点feat,选取符合距离比值条件的匹配点,放到feat的fwd_match域中  
  9. for(int i = 0; i < n2; i++ )  
  10. {  
  11.     feat = feat2+i;//第i个特征点的指针  
  12.     //在kd_root中搜索目标点feat的2个最近邻点,存放在nbrs中,返回实际找到的近邻点个数  
  13.     int k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );  
  14.     if( k == 2 )  
  15.     {  
  16.         d0 = descr_dist_sq( feat, nbrs[0] );//feat与最近邻点的距离的平方  
  17.         d1 = descr_dist_sq( feat, nbrs[1] );//feat与次近邻点的距离的平方  
  18.         //若d0和d1的比值小于阈值NN_SQ_DIST_RATIO_THR,则接受此匹配,否则剔除  
  19.         if( d0 < d1 * NN_SQ_DIST_RATIO_THR )  
  20.         {   //将目标点feat和最近邻点作为匹配点对  
  21.             pt2 = Point( cvRound( feat->x ), cvRound( feat->y ) );//图2中点的坐标  
  22.             pt1 = Point( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );//图1中点的坐标(feat的最近邻点)  
  23.             pt2.x += img1->width;//由于两幅图是左右排列的,pt2的横坐标加上图1的宽度,作为连线的终点  
  24.             cvLine( stacked, pt1, pt2, CV_RGB(255,0,255), 1, 8, 0 );//画出连线  
  25.             matchNum++;//统计匹配点对的个数  
  26.             feat2[i].fwd_match = nbrs[0];//使点feat的fwd_match域指向其对应的匹配点  
  27.         }  
  28.     }  
  29.     free( nbrs );//释放近邻数组  
  30. }  
  31. //显示并保存经距离比值法筛选后的匹配图  
  32. cvNamedWindow(IMG_MATCH1);//创建窗口  
  33. cvShowImage(IMG_MATCH1,stacked);//显示  
匹配结果如下:



(3) 利用RANSAC算法筛选匹配点并计算变换矩阵

此部分最主要的是RobHess源码中的ransac_xform()函数,此函数实现了用RANSAC算法筛选匹配点,返回结果是计算好的变换矩阵。

此部分中,我利用匹配点的坐标关系,对输入的两幅图像的左右关系进行了判断,并根据结果选择使用矩阵H或H的逆阵进行变换。

所以读入的两幅要拼接的图像的左右位置关系可以随意,程序中可自动调整。

主要代码如下:


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //利用RANSAC算法筛选匹配点,计算变换矩阵H,  
  2. //无论img1和img2的左右顺序,计算出的H永远是将feat2中的特征点变换为其匹配点,即将img2中的点变换为img1中的对应点  
  3. H = ransac_xform(feat2,n2,FEATURE_FWD_MATCH,lsq_homog,4,0.01,homog_xfer_err,3.0,&inliers,&n_inliers);  
  4.   
  5. //若能成功计算出变换矩阵,即两幅图中有共同区域  
  6. if( H )  
  7. {  
  8.     qDebug()<<tr("经RANSAC算法筛选后的匹配点对个数:")<<n_inliers<<endl; //输出筛选后的匹配点对个数  
  9.   
  10.     int invertNum = 0;//统计pt2.x > pt1.x的匹配点对的个数,来判断img1中是否右图  
  11.   
  12.     //遍历经RANSAC算法筛选后的特征点集合inliers,找到每个特征点的匹配点,画出连线  
  13.     for(int i=0; i<n_inliers; i++)  
  14.     {  
  15.         feat = inliers[i];//第i个特征点  
  16.         pt2 = Point(cvRound(feat->x), cvRound(feat->y));//图2中点的坐标  
  17.         pt1 = Point(cvRound(feat->fwd_match->x), cvRound(feat->fwd_match->y));//图1中点的坐标(feat的匹配点)  
  18.         //qDebug()<<"pt2:("<<pt2.x<<","<<pt2.y<<")--->pt1:("<<pt1.x<<","<<pt1.y<<")";//输出对应点对  
  19.   
  20.         //统计匹配点的左右位置关系,来判断图1和图2的左右位置关系  
  21.         if(pt2.x > pt1.x)  
  22.             invertNum++;  
  23.   
  24.         pt2.x += img1->width;//由于两幅图是左右排列的,pt2的横坐标加上图1的宽度,作为连线的终点  
  25.         cvLine(stacked_ransac,pt1,pt2,CV_RGB(255,0,255),1,8,0);//在匹配图上画出连线  
  26.     }  
  27.   
  28.     cvNamedWindow(IMG_MATCH2);//创建窗口  
  29.     cvShowImage(IMG_MATCH2,stacked_ransac);//显示经RANSAC算法筛选后的匹配图  
  30.   
  31.     /*程序中计算出的变换矩阵H用来将img2中的点变换为img1中的点,正常情况下img1应该是左图,img2应该是右图。 
  32.       此时img2中的点pt2和img1中的对应点pt1的x坐标的关系基本都是:pt2.x < pt1.x 
  33.       若用户打开的img1是右图,img2是左图,则img2中的点pt2和img1中的对应点pt1的x坐标的关系基本都是:pt2.x > pt1.x 
  34.       所以通过统计对应点变换前后x坐标大小关系,可以知道img1是不是右图。 
  35.       如果img1是右图,将img1中的匹配点经H的逆阵H_IVT变换后可得到img2中的匹配点*/  
  36.   
  37.     //若pt2.x > pt1.x的点的个数大于内点个数的80%,则认定img1中是右图  
  38.     if(invertNum > n_inliers * 0.8)  
  39.     {  
  40.         CvMat * H_IVT = cvCreateMat(3, 3, CV_64FC1);//变换矩阵的逆矩阵  
  41.         //求H的逆阵H_IVT时,若成功求出,返回非零值  
  42.         if( cvInvert(H,H_IVT) )  
  43.         {  
  44.             cvReleaseMat(&H);//释放变换矩阵H,因为用不到了  
  45.             H = cvCloneMat(H_IVT);//将H的逆阵H_IVT中的数据拷贝到H中  
  46.             cvReleaseMat(&H_IVT);//释放逆阵H_IVT  
  47.             //将img1和img2对调  
  48.             IplImage * temp = img2;  
  49.             img2 = img1;  
  50.             img1 = temp;  
  51.             ui->mosaicButton->setEnabled(true);//激活全景拼接按钮  
  52.         }  
  53.         else//H不可逆时,返回0  
  54.         {  
  55.             cvReleaseMat(&H_IVT);//释放逆阵H_IVT  
  56.             QMessageBox::warning(this,tr("警告"),tr("变换矩阵H不可逆"));  
  57.         }  
  58.     }  
  59.     else  
  60.         ui->mosaicButton->setEnabled(true);//激活全景拼接按钮  
  61. }  
  62. else //无法计算出变换矩阵,即两幅图中没有重合区域  
  63. {  
  64.     QMessageBox::warning(this,tr("警告"),tr("两图中无公共区域"));  
  65. }  
经RANSAC筛选后的匹配结果如下图:



(3) 图像融合

这里有两种拼接方法:

① 简易拼接方法的过程是:首先将右图img2经变换矩阵H变换到一个新图像中,然后直接将左图img1加到新图像中,这样拼接出来会有明显的拼接缝,但也是一个初步的成品了。

② 另一种方法首先也是将右图img2经变换矩阵H变换到一个新图像中,然后图像的融合过程将目标图像分为三部分,最左边完全取自img1中的数据,中间的重合部分是两幅图像的加权平均,重合区域右边的部分完全取自img2经变换后的图像。加权平均的权重选择也有好多方法,比如可以使用最基本的取两张图像的平均值,但这样会有明显的拼接缝。这里首先计算出拼接区域的宽度,设d1,d2分别是重叠区域中的点到重叠区域左边界和右边界的距离,则使用如下公式计算重叠区域的像素值:

,这样就可以实现平滑过渡。

主要代码如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //若能成功计算出变换矩阵,即两幅图中有共同区域,才可以进行全景拼接  
  2. if(H)  
  3. {  
  4.     //拼接图像,img1是左图,img2是右图  
  5.     CalcFourCorner();//计算图2的四个角经变换后的坐标  
  6.     //为拼接结果图xformed分配空间,高度为图1图2高度的较小者,根据图2右上角和右下角变换后的点的位置决定拼接图的宽度  
  7.     xformed = cvCreateImage(cvSize(MIN(rightTop.x,rightBottom.x),MIN(img1->height,img2->height)),IPL_DEPTH_8U,3);  
  8.     //用变换矩阵H对右图img2做投影变换(变换后会有坐标右移),结果放到xformed中  
  9.     cvWarpPerspective(img2,xformed,H,CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS,cvScalarAll(0));  
  10.     cvNamedWindow(IMG_MOSAIC_TEMP); //显示临时图,即只将图2变换后的图  
  11.     cvShowImage(IMG_MOSAIC_TEMP,xformed);  
  12.   
  13.     //简易拼接法:直接将将左图img1叠加到xformed的左边  
  14.     xformed_simple = cvCloneImage(xformed);//简易拼接图,克隆自xformed  
  15.     cvSetImageROI(xformed_simple,cvRect(0,0,img1->width,img1->height));  
  16.     cvAddWeighted(img1,1,xformed_simple,0,0,xformed_simple);  
  17.     cvResetImageROI(xformed_simple);  
  18.     cvNamedWindow(IMG_MOSAIC_SIMPLE);//创建窗口  
  19.     cvShowImage(IMG_MOSAIC_SIMPLE,xformed_simple);//显示简易拼接图  
  20.   
  21.     //处理后的拼接图,克隆自xformed  
  22.     xformed_proc = cvCloneImage(xformed);  
  23.   
  24.     //重叠区域左边的部分完全取自图1  
  25.     cvSetImageROI(img1,cvRect(0,0,MIN(leftTop.x,leftBottom.x),xformed_proc->height));  
  26.     cvSetImageROI(xformed,cvRect(0,0,MIN(leftTop.x,leftBottom.x),xformed_proc->height));  
  27.     cvSetImageROI(xformed_proc,cvRect(0,0,MIN(leftTop.x,leftBottom.x),xformed_proc->height));  
  28.     cvAddWeighted(img1,1,xformed,0,0,xformed_proc);  
  29.     cvResetImageROI(img1);  
  30.     cvResetImageROI(xformed);  
  31.     cvResetImageROI(xformed_proc);  
  32.     cvNamedWindow(IMG_MOSAIC_BEFORE_FUSION);  
  33.     cvShowImage(IMG_MOSAIC_BEFORE_FUSION,xformed_proc);//显示融合之前的拼接图  
  34.   
  35.     //采用加权平均的方法融合重叠区域  
  36.     int start = MIN(leftTop.x,leftBottom.x) ;//开始位置,即重叠区域的左边界  
  37.     double processWidth = img1->width - start;//重叠区域的宽度  
  38.     double alpha = 1;//img1中像素的权重  
  39.     for(int i=0; i<xformed_proc->height; i++)//遍历行  
  40.     {  
  41.         const uchar * pixel_img1 = ((uchar *)(img1->imageData + img1->widthStep * i));//img1中第i行数据的指针  
  42.         const uchar * pixel_xformed = ((uchar *)(xformed->imageData + xformed->widthStep * i));//xformed中第i行数据的指针  
  43.         uchar * pixel_xformed_proc = ((uchar *)(xformed_proc->imageData + xformed_proc->widthStep * i));//xformed_proc中第i行数据的指针  
  44.         for(int j=start; j<img1->width; j++)//遍历重叠区域的列  
  45.         {  
  46.             //如果遇到图像xformed中无像素的黑点,则完全拷贝图1中的数据  
  47.             if(pixel_xformed[j*3] < 50 && pixel_xformed[j*3+1] < 50 && pixel_xformed[j*3+2] < 50 )  
  48.             {  
  49.                 alpha = 1;  
  50.             }  
  51.             else  
  52.             {   //img1中像素的权重,与当前处理点距重叠区域左边界的距离成正比  
  53.                 alpha = (processWidth-(j-start)) / processWidth ;  
  54.             }  
  55.             pixel_xformed_proc[j*3] = pixel_img1[j*3] * alpha + pixel_xformed[j*3] * (1-alpha);//B通道  
  56.             pixel_xformed_proc[j*3+1] = pixel_img1[j*3+1] * alpha + pixel_xformed[j*3+1] * (1-alpha);//G通道  
  57.             pixel_xformed_proc[j*3+2] = pixel_img1[j*3+2] * alpha + pixel_xformed[j*3+2] * (1-alpha);//R通道  
  58.         }  
  59.     }  
  60.     cvNamedWindow(IMG_MOSAIC_PROC);//创建窗口  
  61.     cvShowImage(IMG_MOSAIC_PROC,xformed_proc);//显示处理后的拼接图  
  62.   
  63.     /*重叠区域取两幅图像的平均值,效果不好 
  64.         //设置ROI,是包含重叠区域的矩形 
  65.         cvSetImageROI(xformed_proc,cvRect(MIN(leftTop.x,leftBottom.x),0,img1->width-MIN(leftTop.x,leftBottom.x),xformed_proc->height)); 
  66.         cvSetImageROI(img1,cvRect(MIN(leftTop.x,leftBottom.x),0,img1->width-MIN(leftTop.x,leftBottom.x),xformed_proc->height)); 
  67.         cvSetImageROI(xformed,cvRect(MIN(leftTop.x,leftBottom.x),0,img1->width-MIN(leftTop.x,leftBottom.x),xformed_proc->height)); 
  68.         cvAddWeighted(img1,0.5,xformed,0.5,0,xformed_proc); 
  69.         cvResetImageROI(xformed_proc); 
  70.         cvResetImageROI(img1); 
  71.         cvResetImageROI(xformed); //*/  
  72.   
  73.     /*对拼接缝周围区域进行滤波来消除拼接缝,效果不好 
  74.         //在处理前后的图上分别设置横跨拼接缝的矩形ROI 
  75.         cvSetImageROI(xformed_proc,cvRect(img1->width-10,0,img1->width+10,xformed->height)); 
  76.         cvSetImageROI(xformed,cvRect(img1->width-10,0,img1->width+10,xformed->height)); 
  77.         cvSmooth(xformed,xformed_proc,CV_MEDIAN,5);//对拼接缝周围区域进行中值滤波 
  78.         cvResetImageROI(xformed); 
  79.         cvResetImageROI(xformed_proc); 
  80.         cvShowImage(IMG_MOSAIC_PROC,xformed_proc);//显示处理后的拼接图 */  
  81.   
  82.     /*想通过锐化解决变换后的图像失真的问题,对于扭曲过大的图像,效果不好 
  83.         double a[]={  0, -1,  0, -1,  5, -1, 0, -1,  0  };//拉普拉斯滤波核的数据 
  84.         CvMat kernel = cvMat(3,3,CV_64FC1,a);//拉普拉斯滤波核 
  85.         cvFilter2D(xformed_proc,xformed_proc,&kernel);//滤波 
  86.         cvShowImage(IMG_MOSAIC_PROC,xformed_proc);//显示处理后的拼接图*/  
  87.   
  88. }  

右图经变换后的结果如下图:


简易拼接结果如下图:


使用第二种方法时,重合区域融合之前如下图:


加权平均融合之后如下图:



用Qt做了个简单的界面,如下:



还有很多不足,经常有黑边无法去除,望大家多多指正。

实验环境:

IDE是 Qt Creator 2.4.1Qt版本是4.8.4OpenCV版本是2.4.4,SIFT源码来自RobHess给出的源码

源码下载:基于SIFT特征的全景图像拼接,Qt工程:http://download.csdn.net/detail/masikkk/5702681

——————————————————————————————————————

遥感图像拼接与裁剪

一、试验目的:通过ENVI和ARCGIS软件对下载的大足地区的TM图像进行拼接和裁剪,将自己的家乡所在的区域裁剪出来。通过本次试验,初步熟悉ENVI和ARCGIS软件,为今后环境遥感学习奠定基础。

二、试验原理:  1、图像拼接原理:ENVI的图像拼接功能提供交互式的方式将没有地理坐标或者有地理坐标的多幅图像合并,生成一幅单一的合成图像。2、图像裁剪原理:通常按照行政区划边界或自然区划边界进行图像剪裁,在基础数据生产中,还经常要进行标准分幅裁剪。

三、数据来源:已经数字化好的1:400万部全国各县界的shp格式的矢量数据。从遥感数据共享中心(http://ids.ceode.ac.cn/)下载下来的LANDSAT5 TM数据。波段数为7,各波段信息如表1所示:

波段

波长范围(μm)

分辨率

1

0.45~0.53

30米

2

0.52~0.60

30米

3

0.63~0.69

30米

4

0.76~0.90

30米

5

1.55~1.75

30米

6

10.40~12.50

120>米

7

2.08~2.35

30米

表1

四、实验步骤:

1、数据的下载:

    打开遥感数据共享中心(http://ids.ceode.ac.cn/)并登陆用户。

[转载]遥感图像预处理之图像拼接与裁剪
图1

    按空间条件进行查询,输入中国、重庆市、重庆市郊、大足县等信息,点击显示查询所需下载的区域。并且选择LANDSAT5卫星进行查询。

[转载]遥感图像预处理之图像拼接与裁剪

 

图2

    通过查看JP2K快视图可以看出,并没有一副遥感影像能够完全覆盖所选的大足县,因此需要下载两幅图像进行图像的拼接。

[转载]遥感图像预处理之图像拼接与裁剪
图3

2、图像的拼接

    打开ENVI软件,并通过3-2-1真彩色通道打开下载好的两幅遥感影像。

[转载]遥感图像预处理之图像拼接与裁剪

图4

    在ENVI主菜单中选择Map—Mosaicing—Georeferenced,在Mosaic对话框中点击Import—Import File,选择需要拼接的两幅图像。

[转载]遥感图像预处理之图像拼接与裁剪
图5

[转载]遥感图像预处理之图像拼接与裁剪

 

图6

    对图片点击右键,选中Edit Entry,在Edit Entry对话框中,设置Data Value to Ignor:0,忽略0值,设置Feathering Distance为10,羽化半径为10个像素,点击OK确定。

[转载]遥感图像预处理之图像拼接与裁剪

 

图8

    如图8所示,图像已经无接缝地拼接成功,点击File—Apply输出图片。

    将保存好的图片转存成TIFF文件,以便可以在ARCMAP中存在。在ENVI主菜单点击FILE—SAVE FILE AS—TIFF/GeoTIFF。

[转载]遥感图像预处理之图像拼接与裁剪

 

图9

3、投影转换

    打开ARCMAP,导入中国县界数据和已经拼接好的遥感数据,通过字段查找(Find功能)查询属性字段为大足县的面数据。右键—Select选中大足县。

[转载]遥感图像预处理之图像拼接与裁剪

图10

    在ArcToolbox中,选择分析工具中的提取工具中的Clip裁剪,将所需的大足县面数据裁剪出来。

[转载]遥感图像预处理之图像拼接与裁剪

图11

[转载]遥感图像预处理之图像拼接与裁剪
图12

    同时打开拼接好的遥感影像和大足矢量文件可以发现,根据地理坐标,两幅图叠加在一起,矢量文件的位置就是我们需要裁剪的位置。

    在TOC工具栏里,对大足矢量文件点击右键—properties,并点击source选项卡查看其属性,发现其为兰伯特投影。如图13所示。

[转载]遥感图像预处理之图像拼接与裁剪
图13

    而打开拼接好的遥感影像却发现,其为横轴麦卡托投影。如图14所示:

[转载]遥感图像预处理之图像拼接与裁剪

图14

    由于ENVI软件和ARCGIS软件不同,ENVI软件中没有自动投影转换功能,因此,我们需要对这两幅图像进行投影转换,否则这两幅图像在ENVI软件中无法进行叠加。就无法进一步对图像进行裁剪。

    麦卡托投影是低纬度地区常用的一种投影方式。它将地球表面上各点投影到与地球相切的圆柱面上,然后依某条母线剪开而成。它是一种保角圆柱面投影。其计算公式如下:

[转载]遥感图像预处理之图像拼接与裁剪

 

    兰勃特投影以圆锥为投影面构成保角投影,此圆锥与地球上某一纬度线相切或与两条纬度线相割,投影后沿某一母线剖开展平即成为兰勃特投影。

 

[转载]遥感图像预处理之图像拼接与裁剪

 

    将兰伯特投影转换成麦卡托投影就是要将兰伯特投影公式中的X和Y倒推成地理坐标,然后再代入麦卡托投影公式求出麦卡托投影中新的X和Y。

    这些计算比较复杂,在ArcMap中,用封装好的工具很容易将其实现。在ArctoolBOX中,点击Data Management Tools—Projections and Transformations—Feature—Project。

[转载]遥感图像预处理之图像拼接与裁剪

 

图15

    我们需要将大足县矢量数据的兰伯特投影转换为横轴麦卡托投影(与大足裁剪一致),因此在Project对话框中,输入大足县矢量数据,在output dataset or feature class,点击右边的输入按钮,在Spatial Reference Properties点击Import选择拼接好的大足遥感影像数据。这部操作的含义是,将大足矢量数据的投影转换成为大足遥感影像数据的投影,并不需要我们知道转换过程,点击确定。

[转载]遥感图像预处理之图像拼接与裁剪

图16

    如图所示,转换后的大足县shp文件已经变成了横轴麦卡托投影,与遥感图像的投影一致了。

4、图像的裁剪

    ENVI软件中图像的裁剪有三种方法:第一种为规则裁剪,第二种为选区ROI感兴趣区域进行掩膜裁剪,第三种就是我们首先要介绍的矢量文件掩膜裁剪。

(1)矢量文件掩膜裁剪

    打开ENVI软件,输入拼接后的遥感图像。在ENVI主菜单中点击FILE—Open Vector File输入矢量文件(投影转换后的大足shp文件)。

[转载]遥感图像预处理之图像拼接与裁剪

图17

    在Available Vector List对话框中,选择FILE—Export layers to ROIs,点击大足接好图片,选择Convert all records of an EVF layer to one ROI,回到Available Vector List对话框,点击Load Selected可以查看ROI区域是否在图像指定位置。点击Load Selected之后,选择显示的窗口为遥感图像打开的窗口,将Current Layer颜色改成黑色。点击Apply查看,效果如图18所示:

[转载]遥感图像预处理之图像拼接与裁剪

 

图18

    当确定所需裁剪的区域是黑色框体选中的位置之后,在ENVI主菜单选择Basic Tools—Subset data via ROIs,选择大足拼接图像,在Spatial subset via ROI Parameters对话框中,选择刚才导出的ROI,将掩膜项设为YES,掩膜背景的值为0,点击确定输出文件。

裁剪好的大足图像如图19所示:

[转载]遥感图像预处理之图像拼接与裁剪

图19

(2)规则裁剪

    规则裁剪裁剪出来的区域一般为矩形,规则裁剪一般用于已经明确知道需要裁剪的区域范围所在,或者只需要大概裁剪出部分矩形区域,以缩小处理的面积。具体的ENVI操作步骤如下。

    在ENVI主菜单中点击FILE—SAVE FILE AS—ENVI STANDARD,如图20所示。在NEW FILE BUILDER对话框中,点击IMPORT FILE按钮,在CREATE NEW FILE INPUT FILE对话框中,选择大足接好,点击下方的spatial subset按钮。在Select Spatial Subset对话框中,可以通过选择裁剪的行和列来裁剪图像,如图21所示。也可以点击Image,通过点击红色方框的四个角来扩大缩小裁剪区域,通过点击方框内部实现裁剪区域的移动,也可以实现裁剪区域的选取,如图22所示。

[转载]遥感图像预处理之图像拼接与裁剪
图20

[转载]遥感图像预处理之图像拼接与裁剪

 

图21

[转载]遥感图像预处理之图像拼接与裁剪

 

图22

    点击OK输出图像即为所裁剪的矩形规则区域。如如图23所示:

[转载]遥感图像预处理之图像拼接与裁剪

 

图23

 

(3)感兴趣区掩膜裁剪

    这种裁剪方法常常用于各类地物的提取裁剪,如水体等。

    选取感兴趣区的方法多种多样,如监督分类、非监督分类、NDVI和自定义波段运算、手工勾勒等等。

    下面就以大足拼接遥感图像中某区域的森林提取为例子,来说明这种感兴趣区掩膜裁剪的方法。

    首先对图像进行NDVI计算。严格意义上定量计算NDVI植被指数的值,需要将原始图像(DN值)经过辐射定标、大气矫正后得到地表反射率才能进行NDVI计算。但是在此为了简单起见,在不需要定量计算植被指数的时候,直接用DN值进行NDVI计算。

    如图24所示,在ENVI主菜单中,选择Transform—NDVI,我们用的是TM数据,对应的近红外波段为4波段,红光波段为3波段,ENVI软件中已经集成好,不需要我们进行设置。

[转载]遥感图像预处理之图像拼接与裁剪

图24

    NDVI计算结果如图25所示,在图中可以发现,植被区域,NDVI的值比较大,约为0.65—0.8,我们可以对此设置波段阈值。在ENVI主菜单中,选择Basic Tools—Region of Interest—Band threshold to ROI,选择刚才计算的NDVI,设置阈值为0.65—0.8如图27所示。

[转载]遥感图像预处理之图像拼接与裁剪

图25

[转载]遥感图像预处理之图像拼接与裁剪

图26

[转载]遥感图像预处理之图像拼接与裁剪

 

图27

    在ENVI主菜单选择Basic Tools—Subset data via ROIs,选择大足拼接图像,在Spatial subset via ROI Parameters对话框中,选择刚才NDVI提取的植被ROI,然后进行掩膜裁剪,其操作方法和矢量文件掩膜裁剪一致,在此不再赘述。

五、实验结果与分析:

    经上诉步骤,通过不同的方法可以对图像进行不同的裁剪,最终获得了较好的效果。

六、实验心得:

    实验操作需要对软件通过不断的练习与摸索才能比较熟练,清楚地了解到软件操作所带来的对自己有价值的东西。

——————————————————————————————————————
 经过数字化扫描及几何校正后的数字化遥感影像,均为一幅幅具有相同比例尺的影像图。这些影像图互相之间都存在着部分的重叠。所谓图像拼接就是通过对相邻影像图的无缝拼接处理,把这些影像图相互间的重叠部分去掉,从而为在逻辑上将这些影像图整合成覆盖区域的一幅影像图创造条件。

    图像拼接的具体工作步骤为: 

    首先是进行色差处理,借助photoshop软件中的色彩调整功能,将需要拼接的两幅相邻影像图的色彩调整到尽可能和谐。其次是选择拼接线,在两幅相邻的影像图上,用彩色线把需要进行拼接的界线勾画出来。再则是拼接影像图,当选好拼接线后,由专用软件沿着拼接线的轨迹自动进行拼接处理。最后是拼接后的检查,着重检查沿拼接线的接缝处是否存在着错位,若存在错位,还需要对拼接后的影像作进一步的修补。 

    在进行图像拼接时,必须注意以下三个问题: 一是拼接线要尽可能沿着道路、河流、田埂、空地、阴影等延伸,尽量将拼接线选择在两旁无高楼的区域。二是注意两幅相邻影像图在拼接处的高楼单中心投影倾向,要尽可能使拼接线两侧的楼房保持相似的倾向,同时也要防止在拼接后将某一侧楼房切掉一部分的情况。三是拼接线要尽可能避免穿越高架、桥梁、铁路等地物,假如必须要穿越高架、桥梁、铁路时,应尽量从衔接较好的地方或阴影区内穿过。 

    在进行错位修补时,必须遵循以下四个原则: 一要遵循客观性的原则,即在尊重原始影像的基础上,经过对影像错位的修补,使修补后的影像能客观地体现地物的原有面貌。二要遵循准确性的原则,即只对几何校正不准的影像部分作错位修补处理,而对几何校正准确的影像部分保持其原状不动。三要遵循整体性的原则,即无论是大尺度地物还是小尺度地物,只要拼接时在它的拼接处呈现错位,就要对整个地物作整体性地修补。四要遵循连锁性的原则,即对原有的影像错位作了锁定修补后,不要在其它地方再产生新的错位。

——————————————————————————————————————

图像拼接技术主要包括两个关键环节即图像配准和图像融合对于图像融合部分,由于其耗时不太大,且现有的几种主要方法效果差别也不多,所以总体来说算法上比较成熟。而图像配准部分是整个图像拼接技术的核心部分,它直接关系到图像拼接算法的成功率和运行速度,因此配准算法的研究是多年来研究的重点。

       目前的图像配准算法基本上可以分为两类:基于频域的方法(相位相关方法)和基于时域的方法。
       
       相位相关法最早是由Kuglin和Hines在1975年提出的,并且证明在纯二维平移的情形下,拼接精度可以达到1个像素,多用于航空照片和卫星遥感图像的配准等领域。该方法对拼接的图像进行快速傅立叶变换,将两幅待配准图像变换到频域,然后通过它们的互功率谱直接计算出两幅图像间的平移矢量,从而实现图像的配准。由于其具有简单而精确的特点,后来成为最有前途的图像配准算法之一。但是相位相关方法一般需要比较大的重叠比例(通常要求配准图像之间有50%的重叠比例),如果重叠比例较小,则容易造成平移矢量的错误估计,从而较难实现图像的配准。

 

       基于时域的方法又可具体分为基于特征的方法和基于区域的方法。基于特征的方法首先找出两幅图像中的特征点(如边界点、拐点),并确定图像间特征点的对应关系,然后利用这种对应关系找到两幅图像间的变换关系。这一类方法不直接利用图像的灰度信息,因而对光线变化不敏感,但对特征点对应关系的精确程度依赖很大。这一类方法采用的思想较为直观,目前大部分的图像配准算法都可以归为这一类。基于区域的方法是以一幅图像重叠区域中的一块作为模板,在另一幅图像中搜索与此模板最相似的匹配块,这种算法精度较高,但计算量过大。

 

       按照匹配算法的具体实现又可以分为直接法和搜索法两大类,直接法主要包括变换优化法,它首先建立两幅待拼接图像间的变换模型,然后采用非线性迭代最小化算法直接计算出模型的变换参数,从而确定图像的配准位置。该算法效果较好,收敛速度较快,但是它要达到过程的收敛要求有较好的初始估计,如果初始估计不好,则会造成图像拼接的失败。搜索法主要是以一幅图像中的某些特征为依据,在另一幅图像中搜索最佳配准位置,常用的有比值匹配法,块匹配法和网格匹配法。比值匹配法是从一幅图像的重叠区域中部分相邻的两列上取出部分像素,然后以它们的比值作模板,在另一幅图像中搜索最佳匹配。这种算法计算量较小,但精度较低;块匹配法则是以一幅图像重叠区域中的一块作为模板,在另一幅图像中搜索与此模板最相似的匹配块,这种算法精度较高,但计算量过大;网格匹配法减小了块匹配法的计算量,它首先要进行粗匹配,每次水平或垂直移动一个步长,记录最佳匹配位置,然后在此位置附近进行精确匹配,每次步长减半,然后循环此过程直至步长减为0。这种算法较前两种运算量都有所减小,但在实际应用中仍然偏大,而且粗匹配时如果步长取的太大,很可能会造成较大的粗匹配误差,从而很难实现精确匹配。

——————————————————————————————————————

网上搜的都是一行代码Stitcher::Status status = stitcher.stitch(imgs, pano);就出来的傻瓜拼接,连opencv基本的包都没用。

自己好歹用了下基本的包实现了下。

鲁棒性不太好,图片少的时候没事,图片一多就出现了内存错误和木有特征点的错误。

#include <iostream>
#include <fstream>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching/stitcher.hpp"
#include "opencv2/stitching/warpers.hpp"

#define MaxPics 30
//F:\Program Files\opencv\modules\stitching\include\opencv2\stitching
using namespace std;
using namespace cv;
bool try_use_gpu = false;
int filenum;
vector<Mat> imgs;
string result_name = "result.jpg";
//void printUsage();
//int parseCmdArgs(int argc, char** argv);
int readDir(char *path,char fnames[MaxPics][100]);

int readDir(char *path,char fnames[MaxPics][100]) 

struct _finddata_t c_file;
intptr_t hFile;
filenum=0;

char fullpath[100];

sprintf(fullpath,"%s\\*.jpg",path);
// Find first .c file in current directory 
if( (hFile = _findfirst( fullpath, &c_file )) == -1L )
printf( "No *.jpg files in current directory %s!\n",fullpath);
else
{
printf( "Listing of .jpg files in %s directory\n\n",path);
printf( "RDO HID SYS ARC FILE SIZE\n", ' ' );
printf( "--- --- --- --- ---- ----\n", ' ' );
do {
printf( ( c_file.attrib & _A_RDONLY ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_SYSTEM ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_HIDDEN ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_ARCH ) ? " Y " : " N " );
//ctime_s( buffer, _countof(buffer), &c_file.time_write );
printf( " %-15s %9ld\n",c_file.name, c_file.size );
sprintf(fnames[filenum],"%s\\%s",path,c_file.name);
filenum++;
} while( _findnext( hFile, &c_file ) == 0 );
_findclose( hFile );
}
return filenum;

int main(int argc, char* argv[])
{
clock_t start,finish;
double totaltime;
start=clock();


argv[1]="pic";
char fdir[MaxPics][100];
filenum = readDir(argv[1],fdir);
Mat img, pano;
for(int i=0 ; i<filenum ;i++){
img = imread(fdir[i]);
imgs.push_back(img);
}
Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
stitcher.setRegistrationResol(0.1);//为了加速,我选0.1,默认是0.6,最大值1最慢,此方法用于特征点检测阶段,如果找不到特征点,调高吧
//stitcher.setSeamEstimationResol(0.1);//默认是0.1
//stitcher.setCompositingResol(-1);//默认是-1,用于特征点检测阶段,找不到特征点的话,改-1
stitcher.setPanoConfidenceThresh(1);//默认是1,见过有设0.6和0.4的
stitcher.setWaveCorrection(false);//默认是true,为加速选false,表示跳过WaveCorrection步骤
//stitcher.setWaveCorrectKind(detail::WAVE_CORRECT_HORIZ);//还可以选detail::WAVE_CORRECT_VERT ,波段修正(wave correction)功能(水平方向/垂直方向修正)。因为setWaveCorrection设的false,此语句没用

//找特征点surf算法,此算法计算量大,但对刚体运动、缩放、环境影响等情况下较为稳定
detail::SurfFeaturesFinder *featureFinder = new detail::SurfFeaturesFinder();
stitcher.setFeaturesFinder(featureFinder);

//找特征点ORB算法,但是发现草地这组图,这个算法不能完成拼接
//detail::OrbFeaturesFinder *featureFinder = new detail::OrbFeaturesFinder();
//stitcher.setFeaturesFinder(featureFinder);

//Features matcher which finds two best matches for each feature and leaves the best one only if the ratio between descriptor distances is greater than the threshold match_conf.
detail::BestOf2NearestMatcher *matcher = new detail::BestOf2NearestMatcher(false, 0.5f/*=match_conf默认是0.65,我选0.8,选太大了就没特征点啦,0.8都失败了*/);
stitcher.setFeaturesMatcher(matcher);

// Rotation Estimation,It takes features of all images, pairwise matches between all images and estimates rotations of all cameras.
//Implementation of the camera parameters refinement algorithm which minimizes sum of the distances between the rays passing through the camera center and a feature,这个耗时短
stitcher.setBundleAdjuster(new detail::BundleAdjusterRay());
//Implementation of the camera parameters refinement algorithm which minimizes sum of the reprojection error squares.
//stitcher.setBundleAdjuster(new detail::BundleAdjusterReproj());

//Seam Estimation
//Minimum graph cut-based seam estimator
//stitcher.setSeamFinder(new detail::GraphCutSeamFinder(detail::GraphCutSeamFinderBase::COST_COLOR));//默认就是这个
//stitcher.setSeamFinder(new detail::GraphCutSeamFinder(detail::GraphCutSeamFinderBase::COST_COLOR_GRAD));//GraphCutSeamFinder的第二种形式
//啥SeamFinder也不用,Stub seam estimator which does nothing.
stitcher.setSeamFinder(new detail::NoSeamFinder);
//Voronoi diagram-based seam estimator.
//stitcher.setSeamFinder(new detail::VoronoiSeamFinder);

//exposure compensators曝光补偿
//stitcher.setExposureCompensator(new detail::BlocksGainCompensator());//默认的就是这个
//不要曝光补偿
stitcher.setExposureCompensator(new detail::NoExposureCompensator());
//Exposure compensator which tries to remove exposure related artifacts by adjusting image intensities
//stitcher.setExposureCompensator(new detail::detail::GainCompensator());
//Exposure compensator which tries to remove exposure related artifacts by adjusting image block intensities 
//stitcher.setExposureCompensator(new detail::detail::BlocksGainCompensator()); 

//Image Blenders
//Blender which uses multi-band blending algorithm 
//stitcher.setBlender(new detail::MultiBandBlender(try_use_gpu));//默认的是这个
//Simple blender which mixes images at its borders
stitcher.setBlender(new detail::FeatherBlender());//这个简单,耗时少

//柱面?球面OR平面?默认为球面
PlaneWarper* cw = new PlaneWarper();
//SphericalWarper* cw = new SphericalWarper();
//CylindricalWarper* cw = new CylindricalWarper();
stitcher.setWarper(cw);

Stitcher::Status status = stitcher.estimateTransform(imgs);
if (status != Stitcher::OK)
{
cout << "Can't stitch images, error code = " << int(status) << endl;
return -1;
}
status = stitcher.composePanorama(pano);
if (status != Stitcher::OK)
{
cout << "Can't stitch images, error code = " << int(status) << endl;
return -1;
}
cout<<"程序开始";
imwrite(result_name, pano);
finish=clock();
totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
cout<<"\n此程序的运行时间为"<<totaltime<<"秒!"<<endl;
return 0;
}

至于其他的拼接方式,http://academy.nearsoft.com/project-updates/makingapanoramapicture写的挺好。我引用之,并总结如下

1,Stitcher class from OpenCV library

  • Pros
    • Extremely simple. Build panorama in just one command.
    • It performs from finding features through blending in the selected projection by itself.
  • Cons
    • Uses SURF algorithm (patented, not allowed for commercial use).
    • Slow at searching for features, running on a smartphone

2,BoofCV

  • Pros
    • Still easy to use.
    • Java native.
  • Cons
    • It blends without warping into the spherical projection.
    • Still uses SURF.

当然自己实现最好,我的上述代码就是第一种了

——————————————————————————————————————
opencv2.4.0以上的版本提供了stitcher类,可以很方便的实现几幅图像的拼接,关于这个类详细的介绍,可以参考文档: http://docs.opencv.org/2.4.2/modules/stitching/doc/high_level.html?highlight=stitcher#stitcher
      该类主要用的成员函数有createDefault,用于创建缺省参数的stitcher;estimatedTransform,用于匹配图像、分析摄像头旋转角度;composePanorama,生成最后的拼接图像。文档中提示如果对stitching的整过过程不熟悉的话,最好不要使用以上两个函数,直接使用stitch就行了。关于图像拼接的过程,涉及到特征点的提取、特征点匹配、图像融合等等比较复杂的过程,可以参考相关论文和期刊。
      在安装文件下,提供了图像拼接的例子:C:\opencv2.4.2\opencv\samples\cpp\stitching.cpp  
配置好后直接运行就可以了:

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching/stitcher.hpp"


using namespace std;
using namespace cv;

bool try_use_gpu = false;
vector<Mat> imgs;
string result_name = "result.jpg";

//void printUsage();
//int parseCmdArgs(int argc, char** argv);

int main(int argc, char* argv[])
{

Mat img=imread("1.jpg");
imgs.push_back(img);
img=imread("2.jpg");
imgs.push_back(img);
img=imread("3.jpg");
imgs.push_back(img);

Mat pano;
Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
Stitcher::Status status = stitcher.stitch(imgs, pano);

if (status != Stitcher::OK)
{
cout << "Can't stitch images, error code = " << int(status) << endl;
return -1;
}

imwrite(result_name, pano);
return 0;
}

最终结果:
示例程序047--用opencv的stitcher类实现图像拼接

示例程序047--用opencv的stitcher类实现图像拼接

示例程序047--用opencv的stitcher类实现图像拼接

示例程序047--用opencv的stitcher类实现图像拼接
——————————————————————————————————————
第一章  绪论

  1.1 图像拼接技术的研究背景及研究意义

  图像拼接(image mosaic)是一个日益流行的研究领域,他已经成为照相绘图学、计算机视觉、图像处理和计算机图形学研究中的热点。图像拼接解决的问题一般式,通过对齐一系列空间重叠的图像,构成一个无缝的、高清晰的图像,它具有比单个图像更高的分辨率和更大的视野。

  早期的图像拼接研究一直用于照相绘图学,主要是对大量航拍或卫星的图像的整合。近年来随着图像拼接技术的研究和发展,它使基于图像的绘制(IBR)成为结合两个互补领域——计算机视觉和计算机图形学的坚决焦点,在计算机视觉领域中,图像拼接成为对可视化场景描述(Visual Scene Representaions)的主要研究方法:在计算机形学中,现实世界的图像过去一直用于环境贴图,即合成静态的背景和增加合成物体真实感的贴图,图像拼接可以使IBR从一系列真是图像中快速绘制具有真实感的新视图。

  在军事领域网的夜视成像技术中,无论夜视微光还是红外成像设备都会由于摄像器材的限制而无法拍摄视野宽阔的图片,更不用说360 度的环形图片了。但是在实际应用中,很多时候需要将360 度所拍摄的很多张图片合成一张图片,从而可以使观察者可以观察到周围的全部情况。使用图像拼接技术,在根据拍摄设备和周围景物的情况进行分析后,就可以将通过转动的拍摄器材拍摄的涵盖周围360 度景物的多幅图像进行拼接,从而实时地得到超大视角甚至是360 度角的全景图像。这在红外预警中起到了很大的作用。

  微小型履带式移动机器人项目中,单目视觉不能满足机器人的视觉导航需要,并且单目视觉机器人的视野范围明显小于双目视觉机器人的视野。利用图像拼接技术,拼接机器人双目采集的图像,可以增大机器人的视野,给机器人的视觉导航提供方便。在虚拟现实领域中,人们可以利用图像拼接技术来得到宽视角的图像或360 度全景图像,用来虚拟实际场景。这种基于全景图的虚拟现实系统,通过全景图的深度信息抽取,恢复场景的三维信息,进而建立三维模型。这个系统允许用户在虚拟环境中的一点作水平环视以及一定范围内的俯视和仰视,同时允许在环视的过程中动态地改变焦距。这样的全景图像相当于人站在原地环顾四周时看到的情形。在医学图像处理方面,显微镜或超声波的视野较小,医师无法通过一幅图像进行诊视,同时对于大目标图像的数据测量也需要把不完整的图像拼接为一个整体。所以把相邻的各幅图像拼接起来是实现远程数据测量和远程会诊的关键环节圆。在遥感技术领域中,利用图像拼接技术中的图像配准技术可以对来自同一区域的两幅或多幅图像进行比较,也可以利用图像拼接技术将遥感卫星拍摄到的有失真地面图像拼接成比较准确的完整图像,作为进一步研究的依据。

从以上方面可以看出,图像拼接技术的应用前景十分广阔,深入研究图像拼接技术有着很重要的意义

  1.2图像拼接算法的分类

  图像拼接作为这些年来图像研究方面的重点之一,国内外研究人员也提出了很多拼接算法。图像拼接的质量,主要依赖图像的配准程度,因此图像的配准是拼接算法的核心和关键。根据图像匹配方法的不同仁阔,一般可以将图像拼接算法分为以下两个类型:
  (1) 基于区域相关的拼接算法。
      这是最为传统和最普遍的算法。基于区域的配准方法是从待拼接图像的灰度值出发,对待配准图像中一块区域与参考图像中的相同尺寸的区域使用最小二乘法或者其它数学方法计算其灰度值的差异,对此差异比较后来判断待拼接图像重叠区域的相似程度,由此得到待拼接图像重叠区域的范围和位置,从而实现图像拼接。也可以通过FFT 变换将图像由时域变换到频域,然后再进行配准。对位移量比较大的图像,可以先校正图像的旋转,然后建立两幅图像之间的映射关系。
当以两块区域像素点灰度值的差别作为判别标准时,最简单的一种方法是直接把各点灰度的差值累计起来。这种办法效果不是很好,常常由于亮度、对比度的变化及其它原因导致拼接失败。另一种方法是计算两块区域的对应像素点灰度值的相关系数,相关系数越大,则两块图像的匹配程度越高。该方法的拼接效果要好一些,成功率有所提高。
 (2) 基于特征相关的拼接算法。
     基于特征的配准方法不是直接利用图像的像素值,而是通过像素导出图像的特征,然后以图像特征为标准,对图像重叠部分的对应特征区域进行搜索匹配,该类拼接算法有比较高的健壮性和鲁棒性。
基于特征的配准方法有两个过程:特征抽取和特征配准。首先从两幅图像中提取灰度变化明显的点、线、区域等特征形成特征集冈。然后在两幅图像对应的特征集中利用特征匹配算法尽可能地将存在对应关系的特征对选择出来。一系列的图像分割技术都被用到特征的抽取和边界检测上。如canny 算子、拉普拉斯高斯算子、区域生长。抽取出来的空间特征有闭合的边界、开边界、交叉线以及其他特征。特征匹配的算法有:交叉相关、距离变换、动态编程、结构匹配、链码相关等算法。

  1.3本文的主要工作和组织结构

本文的主要工作:
(1) 总结了前人在图像拼接方面的技术发展历程和研究成果。

(2) 学习和研究了前人的图像配准算法。

(3) 学习和研究了常用的图像融合算法。

(4) 用matlab实现本文中的图像拼接算法

(5) 总结了图像拼接中还存在的问题,对图像拼接的发展方向和应用前景进行展望。

  本文的组织结构:

  第一章主要对图像拼接技术作了整体的概述,介绍了图像拼接的研究背景和应用前景,以及图像拼接技术的大致过程、图像拼接算法的分类和其技术难点。第二章主要介绍讨论了图像预处理中的两个步骤,即图像的几何校正和噪声点的抑制。第三章主要介绍讨论了图像配准的多种算法。第四章主要介绍讨论了图像融合的一些算法。第五章主要介绍图像拼接软件实现本文的算法。第六章主要对图像拼接中还存在的问题进行总结,以及对图像拼接的发展进行展望。

  1.4 本章小结

  本章主要对图像拼接技术作了整体的概述,介绍了图像拼接的研究背景和应用前景,以图像拼接算法的分类和其技术难点,并且对全文研究内容进行了总体介绍。
  第二章  图像拼接的基础理论及图像预处理

  2.1图像拼接

    图像拼接技术主要有三个主要步骤:图像预处理、图像配准、图像融合与边界平滑,

如图。

图像拼接算法及实现

    图像拼接技术主要分为三个主要步骤:图像预处理、图像配准、图像融合与边界平滑,图像预处理主要指对图像进行几何畸变校正和噪声点的抑制等,让参考图像和待拼接图像不存在明显的几何畸变。在图像质量不理想的情况下进行图像拼接,如果不经过图像预处理,很容易造成一些误匹配。图像预处理主要是为下一步图像配准做准备,让图像质量能够满足图像配准的要求。图像配准主要指对参考图像和待拼接图像中的匹配信息进行提取,在提取出的信息中寻找最佳的匹配,完成图像间的对齐。图像拼接的成功与否主要是图像的配准。待拼接的图像之间,可能存在平移、旋转、缩放等多种变换或者大面积的同色区域等很难匹配的情况,一个好的图像配准算法应该能够在各种情况下准确找到图像间的对应信息,将图像对齐。图像融合指在完成图像匹配以后,对图像进行缝合,并对缝合的边界进行平滑处理,让缝合自然过渡。由于任何两幅相邻图像在采集条件上都不可能做到完全相同,因此,对于一些本应该相同的图像特性,如图像的光照特性等,在两幅图像中就不会表现的完全一样。图像拼接缝隙就是从一幅图像的图像区域过渡到另一幅图像的图像区域时,由于图像中的某些相关特性发生了跃变而产生的。图像融合就是为了让图像间的拼接缝隙不明显,拼接更自然

  2.2 图像的获取方式

  图像拼接技术原理是根据图像重叠部分将多张衔接的图像拼合成一张高分辨率全景图 。这些有重叠部分的图像一般由两种方法获得 : 一种是固定照相机的转轴 ,然后绕轴旋转所拍摄的照片 ;另一种是固定照相机的光心 ,水平摇动镜头所拍摄的照片。其中 ,前者主要用于远景或遥感图像的获取 ,后者主要用于显微图像的获取 ,它们共同的特点就是获得有重叠的二维图像。

  2.3 图像的预处理

  2.3.1 图像的校正

  当照相系统的镜头或者照相装置没有正对着待拍摄的景物时候,那么拍摄到的景物图像就会产生一定的变形。这是几何畸变最常见的情况。另外,由于光学成像系统或电子扫描系统的限制而产生的枕形或桶形失真,也是几何畸变的典型情况。几何畸变会给图像拼接造成很大的问题,原本在两幅图像中相同的物体会因为畸变而变得不匹配,这会给图像的配准带来很大的问题。因此,解决几何畸变的问题显得很重要。

  图象校正的基本思路是,根据图像失真原因,建立相应的数学模型,从被污染或畸变的图象信号中提取所需要的信息,沿着使图象失真的逆过程恢复图象本来面貌。实际的复原过程是设计一个滤波器,使其能从失真图象中计算得到真实图象的估值,使其根据预先规定的误差准则,最大程度地接近真实图象。

  2.3.2 图像噪声的抑制

  图像噪声可以理解为妨碍人的视觉感知,或妨碍系统传感器对所接受图像源信息进行理解或分析的各种因素,也可以理解成真实信号与理想信号之间存在的偏差。一般来说,噪声是不可预测的随机信号,通常采用概率统计的方法对其进行分析。噪声对图像处理十分重要,它影响图像处理的各个环节,特别在图像的输入、采集中的噪声抑制是十分关键的问题。若输入伴有较大的噪声,必然影响图像拼接的全过程及输出的结果。根据噪声的来源,大致可以分为外部噪声和内部噪声;从统计数学的观点来定义噪声,可以分为平稳噪声和非平稳噪声。各种类型的噪声反映在图像画面上,大致可以分为两种类型。一是噪声的幅值基本相同,但是噪声出现的位置是随机的,一般称这类噪声为椒盐噪声。另一种是每一点都存在噪声,但噪声的幅值是随机分布的,从噪声幅值大小的分布统计来看,其密度函数有高斯型、瑞利型,分别成为高斯噪声和瑞利噪声,又如频谱均匀分布的噪声称为白噪声等。

  1.均值滤波

    所谓均值滤波实际上就是用均值替代原图像中的各个像素值。均值滤波的方法是,对将处理的当前像素,选择一个模板,该模板为其邻近的若干像素组成,用模板中像素的均值来替代原像素的值。如图2.4所示,序号为0是当前像素,序号为1至8是邻近像素。求模板中所有像素的均值,再把该均值赋予当前像素点((x, y),作为处理后图像在该点上的灰度g(x,y),即

 g(x,y)=图像拼接算法及实现 图像拼接算法及实现                                                      (2-2-2-1)

其中,s为模板,M为该模板中包含像素的总个数。

图像拼接算法及实现

图2.2.2.1模板示意图

  2.中值滤波

  中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术。它的核心算法是将模板中的数据进行排序,这样,如果一个亮点(暗点)的噪声,就会在排序过程中被排在数据序列的最右侧或者最左侧,因此,最终选择的数据序列中见位置上的值一般不是噪声点值,由此便可以达到抑制噪声的目的。
取某种结构的二维滑动模板,将模板内像素按照像素值的大小进行排序,生成单调上升(或下降)的二维数据序列。二维德中值滤波输出为
                                 ( 2-2-2-2 )                            

其中,f(x,y),g (x,y)分别为原图像和处理后的图像,w二维模板,k ,l为模板的长宽,Med 为取中间值操作,模板通常为3  3 、5 5 区域,也可以有不同形状,如线状、圆形、十字形、圆环形。

  2.4 本章小结

  本章主要介绍了图像几何畸变校正和图像噪声抑制两种图像预处理.

  第三章  图像配准算法

  3.1 图像配准的概念

    图像配准简而言之就是图像之间的对齐。图像配准定义为:对从不同传感器或不同时间或不同角度所获得的两幅或多幅图像进行最佳匹配的处理过程。为了更清楚图像配准的任务,我们将图像配准问题用更精确的数学语言描述出来。配准可以用描述为如下的问题:

给定同一景物的从不同的视角或在不同的时间获取的两个图像I ,I 和两个图像间的相似度量S(I ,I ),找出I ,I 中的同名点,确定图像间的最优变换T,使得S(T(I ),I )达到最大值。

    图像配准总是相对于多幅图像来讲的,在实际工作中,通常取其中的一幅图像作为配准的基准,称它为参考图,另一幅图像,为搜索图。图像配准的一般做法是,首先在参考图上选取以某一目标点为中心的图像子块,并称它为图像配准的模板,然后让模板在搜索图上有秩序地移动,每移到一个位置,把模板与搜索图中的对应部分进行相关比较,直到找到配准位置为止。

    如果在模板的范围内,同一目标的两幅图像完全相同,那么完成图像配准并不困难。然而,实际上图像配准中所遇到的同一目标的两幅图像常常是在不同条件下获得的,如不同的成像时间、不同的成像位置、甚至不同的成像系统等,再加上成像中各种噪声的影响,使同一目标的两幅图像不可能完全相同,只能做到某种程度的相似,因此图像配准是一个相当复杂的技术过程。
  3.2 基于区域的配准

  3.2.1 逐一比较法

设搜索图为s待配准模板为T,如图3.1所示,S大小为M N,T大小为U V,如图所示。

图像拼接算法及实现

              图3.1搜索图S与模板T示意图

 逐一比较法的配准思想是:

    在搜索图S中以某点为基点(i,j),截取一个与模板T大小一样的分块图像,这样的基点有(M-U+1) 图像拼接算法及实现(N-V+1)个,配准的目标就是在(M-U+1) 图像拼接算法及实现(N-V+1)个分块图像中找一个与待配准图像最相似的图像,这样得到的基准点就是最佳配准点。

    设模板T在搜索图s上移动,模板覆盖下的那块搜索图叫子图S ,(i,j)为这块子图的左上角点在S图中的坐标,叫做参考点。然后比较T和S 图像拼接算法及实现的内容。若两者一致,则T和S图像拼接算法及实现 之差为零。在现实图像中,两幅图像完全一致是很少见的,一般的判断是在满足一定条件下,T和S图像拼接算法及实现 之差最小。

根据以上原理,可采用下列两种测度之一来衡量T和S 的相似程度。D(i,j)的值越小,则该窗口越匹配。

          D(i,j)= 图像拼接算法及实现 图像拼接算法及实现  [S图像拼接算法及实现 (m,n)-T(m,n)]图像拼接算法及实现              (3-1)

          D(i,j)=图像拼接算法及实现 图像拼接算法及实现  图像拼接算法及实现 [S图像拼接算法及实现 (m,n)-T(m,n)图像拼接算法及实现              (3-2)

或者利用归一化相关函数。将式(3-1)展开可得:

D(i,j)=图像拼接算法及实现 图像拼接算法及实现  [S (m,n)] -2 图像拼接算法及实现 图像拼接算法及实现 S (m,n)*T(m,n)+图像拼接算法及实现 图像拼接算法及实现  [T(m,n)]  (3-3)

    式中等号右边第三项表示模板总能量,是一常数,与(i,j)无关;第一项是与模板匹配区域的能量,它随((i,j)的改变而改变,当T和S 匹配时的取最大值。因此相

关函数为:

R(i,j)=图像拼接算法及实现                                             (3-4)

当R(i,j)越大时,D(i,j)越小,归一化后为:

 R(i,j)=图像拼接算法及实现                      (3-5)

根据Cauchy-Schwarz不等式可知式(3-5)中0图像拼接算法及实现 R(i,j)图像拼接算法及实现 1,并且仅当值S (m, n)/T (m, n)=常数时,R(i,j)取极大值。

    该算法的优点:

    (1)算法思路比较简单,容易理解,易于编程实现。

    (2)选用的模板越大,包含的信息就越多,匹配结果的可信度也会提高,同时能够对参考图像进行全面的扫描。

    该算法的缺点:

    (1)很难选择待配准图像分块。因为一个如果分块选择的不正确,缺少信息量,则不容易正确的匹配,即发生伪匹配。同时,如果分块过大则降低匹配速度,如果分块过小则容易降低匹配精度。

    (2)对图像的旋转变形不能很好的处理。算法本身只是把待配准图像分块在标准参考图像中移动比较,选择一个最相似的匹配块,但是并不能够对图像的旋转变形进行处理,因此对照片的拍摄有严格的要求。

  3.2.2 分层比较法

  图像处理的塔形(或称金字塔:Pyramid)分解方法是由Burt和Adelson首先提出的,其早期主要用于图像的压缩处理及机器人的视觉特性研究。该方法把原始图像分解成许多不同空间分辨率的子图像,高分辨率(尺寸较大)的子图像放在下层,低分辨率(尺寸较小)的图像放在上层,从而形成一个金字塔形状。

    在逐一比较法的思想上,为减少运算量,引入了塔形处理的思想,提出了分层比较法。利用图像的塔形分解,可以分析图像中不同大小的物体。同时,通过对低分辨率、尺寸较小的上层进行分析所得到的信息还可以用来指导对高分辨率、尺寸较大的下层进行分析,从而大大简化分析和计算。在搜索过程中,首先进行粗略匹配,每次水平或垂直移动一个步长,计算对应像素点灰度差的平方和,记录最小值的网格位置。其次,以此位置为中心进行精确匹配。每次步长减半,搜索当前最小值,循环这个过程,直到步长为零,最后确定出最佳匹配位置。

    算法的具体实现步骤如下:

    (1)将待匹配的两幅图像中2 图像拼接算法及实现 2邻域内的像素点的像素值分别取平均,作为这一区域(2 图像拼接算法及实现 2)像素值,得到分辨率低一级的图像。然后,将此分辨率低一级的图像再作同样的处理,也就是将低一级的图像4 图像拼接算法及实现 4邻域内的像素点的像素值分别取平均,作为这一区域(4图像拼接算法及实现  4)点的像素值,得到分辨率更低一级的图像。依次处理,得到一组分辨率依次降低的图像。

    (2)从待匹配的两幅图像中分辨率最低的开始进行匹配搜索,由于这两幅图像像素点的数目少,图像信息也被消除一部分,因此,此匹配位置是不精确的。所以,在分辨率更高一级的图像中搜索时,应该在上一次匹配位置的附近进行搜索。依次进行下去,直到在原始图像中寻找到精确的匹配位置。

    算法的优点:

      (1)该算法思路简单,容易理解,易于编程实现。

      (2)该算法的搜索空间比逐一比较要少,在运算速度较逐一比较法有所提高。

    算法的缺点:

      (1)算法的精度不高。在是在粗略匹配过程中,移动的步长较大,很有可能将第一幅图像上所取的网格划分开,这样将造成匹配中无法取出与第一幅图像网格完全匹配的最佳网格,很难达到精确匹配。

      (2)对图像的旋转变形仍然不能很好的处理。与逐一比较法一样,该算法只是对其运算速度有所改进,让搜索空间变小,并无本质变化,因此对图像的旋转变形并不能进行相应处理。

  3.2.3 相位相关法

  相位相关度法是基于频域的配准常用算法。它将图像由空域变换到频域以后再进行配准。该算法利用了互功率谱中的相位信息进行图像配准,对图像间的亮度变化不敏感,具有一定的抗干扰能力,而且所获得的相关峰尖锐突出,位移检测范围大,具有较高的匹配精度。

    相位相关度法思想是利用傅立叶变换的位移性质,对于两幅数字图像s,t,其对应的傅立叶变换为S,T,即:

S=F{s}=图像拼接算法及实现 e图像拼接算法及实现    T=F{t}=图像拼接算法及实现 e图像拼接算法及实现              (3-6)

若图像s,t相差一个平移量(x ,y ),即有:

      s(x,y) = t(x-x ,y-y )                               (3-7)

    根据傅立叶变换的位移性质,上式的傅立叶变换为:

     S(图像拼接算法及实现 )=e图像拼接算法及实现 T(图像拼接算法及实现 )                        (3-8)

    也就是说,这两幅图像在频域中具有相同的幅值,只是相位不同,他们之间的相位差可以等效的表示为互功率谱的相位。两幅图的互功率谱为:

 图像拼接算法及实现=e 图像拼接算法及实现                       (3-9)

    其中*为共扼符号, 表示频谱幅度。通过对互功率谱式(3-9)进行傅立叶逆变换,在((x,y)空间的(x ,y ),即位移处,将形成一个单位脉冲函数 ,脉冲位置即为两幅被配准图像间的相对平移量x 和y

    式(3-9)表明,互功率谱的相位等价于图像间的相位差,故该方法称作相位相关法。

    相位相关度法的优点:

      (1)该算法简单速度快,因此经常被采用。对于其核心技术傅立叶变换,现在己经出现了很多有关的快速算法,这使得该算法的快速性成为众多算法中的一大优势。另外,傅立叶变换的硬件实现也比其它算法容易。

      (2)该算法抗干扰能力强,对于亮度变化不敏感。

  相位相关度法的缺点:

    (1)该算法要求图像有50%左右的重叠区域,在图像重叠区域很小的时,算法的结果很难保证,容易造成误匹配。

    (2)由于Fourier变换依赖于自身的不变属性,所以该算法只适用于具有旋转、平移、比例缩放等变换的图像配准问题。对于任意变换模型,不能直接进行处理,而要使用控制点方法,控制点方法可以解决诸如多项式、局部变形等问题。

  3.3 基于特征的配准

  3.3.1 比值匹配法

  比值匹配法算法思路是利用图像中两列上的部分像素的比值作为模板,即在参考图像T的重叠区域中分别在两列上取出部分像素,用它们的比值作为模板,然后在搜索图S中搜索最佳的匹配。匹配的过程是在搜索图S中,由左至右依次从间距相同的两列上取出部分像素,并逐一计算其对应像素值比值;然后将这些比值依次与模板进行比较,其最小差值对应的列就是最佳匹配。这样在比较中只利用了一组数据,而这组数据利用了两列像素及其所包含的区域的信息。

    该算法的具体实现步骤如下:

    (1)在参考图像T中间隔为c个像素的距离上的两列像素中,各取m个像素,计算这m个像素的比值,将m个比值存入数组中,将其作为比较的模板。

    (2)从搜索图S中在同样相隔c个像素的距离上的两列,各取出m+n个像素,计算其比值,将m+n个比值存入数组。假定垂直错开距离不超过n个像素,多取的n个像素则可以解决图像垂直方向上的交错问题。

    (3)利用参考图像T中的比值模板在搜索图S中寻找相应的匹配。首先进行垂直方向上的比较,即记录下搜索图S中每个比值数组内的最佳匹配。再将每个数组的组内最佳匹配进行比较,即进行水平方向的比较,得到的最小值就认为是全局最佳匹配。此时全局最佳匹配即为图像间在水平方向上的偏移距离,该全局最佳匹配队应的组内最佳匹配即为图像间垂直方向上的偏移距离。

    比值匹配法的优点:

    (1)算法思路清晰简单,容易理解,实现起来比较方便。

    (2)在匹配计算的时候,计算量小,速度快。

    比值匹配法的缺点:

    (1)利用图像的特征信息太少。只利用了两条竖直的平行特征线段的像素的信息,没有能够充分利用了图像重叠区域的大部分特征信息。虽然算法提到,在搜索图S中由左至右依次从间距相同的两列上取出部分像素,计算其对应像素的比值,然后将这些比值依次与模版进行比较,好像是利用了搜索图S中的重叠区域的大部分图像信息,但在参考图像T中,只是任意选择了两条特征线,没有充分利用到参考图像T的重叠区域的特征信息。

    (2)对图片的采集提出了较高的要求。此算法对照片先进行垂直方向上的比较,然后再进行水平方向上的比较,这样可以解决上下较小的错开问题。在采集的时候只能使照相机在水平方向上移动。然而,有时候不可避免的照相机镜头会有小角度的旋转,使得拍摄出来的照片有一定的旋转,在这个算法中是无法解决的。而且对重叠区域无明显特征的图像,比较背景是海洋或者天空,这样在选取特征模版的时候存在很大的问题。由于照片中存在大块纹理相同的部分,所以与模版的差别就不大,这样有很多匹配点,很容易造成误匹配。

    (3)不易对两条特征线以及特征线之间的距离进行确定。算法中在参考图像T的重叠区域中取出两列像素上的部分像素,并没有给出选择的限制。然而在利用拼接算法实现自动拼接的时候,如果选取的特征线不是很恰当,那么这样的特征线算出来的模版就失去了作为模版的意义。同时,在确定特征线间距时,选的过大,则不能充分利用重叠区域的图像信息。选择的过小,则计算量太大。

 

来源:http://www.ce86.com/a/computer/jsjyy123/200906/17-72995-2.html

——————————————————————————————————————

基本介绍

图像配准图像融合是图像拼接的两个关键技术。图像配准是图像融合的基础,而且图像配准算法的计算量一般非常大,因此图像拼接技术的发展很大程度上取决于图像配准技术的创新。早期的图像配准技术主要采用点匹配法,这类方法速度慢、精度低,而且常常需要人工选取初始匹配点,无法适应大数据量图像的融合。图像拼接的方法很多,不同的算法步骤会有一定差异,但大致的过程是相同的。一般来说,图像拼接主要包括以下五步:

折叠图像预处理

包括数字图像处理的基本操作(如去噪、边缘提取、直方图处理等)、建立图像的匹配模板以及对图像进行某种变换(如傅里叶变换、小波变换等)等操作。

折叠图像配准

就是采用一定的匹配策略,找出待拼接图像中的模板或特征点在参考图像中对应的位置,进而确定两幅图像之间的变换关系。

折叠建立变换模型

根据模板或者图像特征之间的对应关系,计算出数学模型中的各参数值,从而建立两幅图像的数学变换模型。

折叠统一坐标变换

根据建立的数学转换模型,将待拼接图像转换到参考图像的坐标系中,完成统一坐标变换。

折叠融合重构

将带拼接图像的重合区域进行融合得到拼接重构的平滑无缝全景图像。

折叠编辑本段图像拼接的基本流程图。

相邻图像的配准及拼接是全景图生成技术的关键,有关图像配准技术的研究至今已有很长的历史,其主要的方法有以下两种:基于两幅图像的亮度差最小的方法和基于特征的方法。其中使用较多的是基于特征模板匹配特征点的拼接方法。该方法允许待拼接的图像有一定的倾斜和变形,克服了获取图像时轴心必须一致的问题,同时允许相邻图像之间有一定色差。全景图的拼接主要包括以下4个步骤:图像的预拼接,即确定两幅相邻图像重合的较精确位置,为特征点的搜索奠定基础。特征点的提取,即在基本重合位置确定后,找到待匹配的特征点。图像矩阵变换及拼接,即根据匹配点建立图像的变换矩阵并实现图像的拼接。最后是图像的平滑处理。

折叠编辑本段图像拼接技术分类

图像拼接技术主要包括两个关键环节即图像配准和图像融合。对于图像融合部分,由于其耗时不太大,且现有的几种主要方法效果差别也不多,所以总体来说算法上比较成熟。而图像配准部分是整个图像拼接技术的核心部分,它直接关系到图像拼接算法的成功率和运行速度,因此配准算法的研究是多年来研究的重点。

目前的图像配准算法基本上可以分为两类:基于频域的方法(相位相关方法)和基于时域的方法。

折叠相位相关法

相位相关法最早是由Kuglin和Hines在1975年提出的,并且证明在纯二维平移的情形下,拼接精度可以达到1个像素,多用于航空照片和卫星遥感图像的配准等领域。该方法对拼接的图像进行快速傅立叶变换,将两幅待配准图像变换到频域,然后通过它们的互功率谱直接计算出两幅图像间的平移矢量,从而实现图像的配准。由于其具有简单而精确的特点,后来成为最有前途的图像配准算法之一。但是相位相关方法一般需要比较大的重叠比例(通常要求配准图像之间有50%的重叠比例),如果重叠比例较小,则容易造成平移矢量的错误估计,从而较难实现图像的配准。

折叠基于时域的方法

基于时域的方法又可具体分为基于特征的方法和基于区域的方法。基于特征的方法首先找出两幅图像中的特征点(如边界点、拐点),并确定图像间特征点的对应关系,然后利用这种对应关系找到两幅图像间的变换关系。这一类方法不直接利用图像的灰度信息,因而对光线变化不敏感,但对特征点对应关系的精确程度依赖很大。这一类方法采用的思想较为直观,大部分的图像配准算法都可以归为这一类。基于区域的方法是以一幅图像重叠区域中的一块作为模板,在另一幅图像中搜索与此模板最相似的匹配块,这种算法精度较高,但计算量过大。

按照匹配算法的具体实现又可以分为直接法和搜索法两大类,直接法主要包括变换优化法,它首先建立两幅待拼接图像间的变换模型,然后采用非线性迭代最小化算法直接计算出模型的变换参数,从而确定图像的配准位置。该算法效果较好,收敛速度较快,但是它要达到过程的收敛要求有较好的初始估计,如果初始估计不好,则会造成图像拼接的失败。搜索法主要是以一幅图像中的某些特征为依据,在另一幅图像中搜索最佳配准位置,常用的有比值匹配法,块匹配法和网格匹配法。比值匹配法是从一幅图像的重叠区域中部分相邻的两列上取出部分像素,然后以它们的比值作模板,在另一幅图像中搜索最佳匹配。这种算法计算量较小,但精度较低;块匹配法则是以一幅图像重叠区域中的一块作为模板,在另一幅图像中搜索与此模板最相似的匹配块,这种算法精度较高,但计算量过大;网格匹配法减小了块匹配法的计算量,它首先要进行粗匹配,每次水平或垂直移动一个步长,记录最佳匹配位置,然后在此位置附近进行精确匹配,每次步长减半,然后循环此过程直至步长减为0。这种算法较前两种运算量都有所减小,但在实际应用中仍然偏大,而且粗匹配时如果步长取的太大,很可能会造成较大的粗匹配误差,从而很难实现精确匹配。

——————————————————————————————————————

stitching是OpenCV2.4.0一个新模块,功能是实现图像拼接,所有的相关函数都被封装在Stitcher类当中。这个类当中我们可能用到的成员函数有createDefault、estimateTransform、composePanorama、stitch。其内部实现的过程是非常繁琐的,需要很多算法的支持,包括图像特征的寻找和匹配,摄像机的校准,图像的变形,曝光补偿和图像融合。但这些模块的接口、调用,强大的OpenCV都为我们搞定了,我们使用OpenCV做图像拼接,只需要调用createDefault函数生成默认的参数,再使用stitch函数进行拼接就ok了。就这么简单!estimateTransform和composePanorama函数都是比较高级的应用,如果各位对stitching的流程不是很清楚的话,还是慎用。

实例也非常简单,下载链接哦:http://download.csdn.net/detail/yang_xian521/4321158

输入原图(为了显示,我都压缩过):





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值