精华内容
下载资源
问答
  • Visionpro实现多图像拼接源码,带有素材
  • opencv3.4 多图像拼接

    2019-07-10 20:39:55
    本例为opencv 3.4.5版本的多图像拼接代码,采用SURF算法
  • 主要为大家详细介绍了OpenCV实现多图像拼接成一张大图,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Automatic Panoramic Image Stitching using Invariant Features 论文多图像拼接程序 可支持多图像自动拼接,可设置图像融合方式,全景图像融合
  • python 下的多图像拼接源代码,供学习参考! python 下的多图像拼接源代码,供学习参考! python 下的多图像拼接源代码,供学习参考!
  • 多图像拼接---最佳缝合融合

    万次阅读 热门讨论 2018-03-28 20:41:52
    在一个博文《分辨率拼接算法(继最佳缝合线之后)》中,有一个最佳缝合线的matlab的代码, 我把它改成opencv的一个函数bestlinefusion: //《图像拼接的改进算法》最佳缝合线算法 图像融合 Mat_<Vec3f...

    前面已经做了亮度调整,和权重融合

    这个图融合处是有重影的

    在一个博文《多分辨率拼接算法(继最佳缝合线之后)》中,有一个最佳缝合线的matlab的代码,

    我把它改成opencv的一个函数bestlinefusion:

     

    //《图像拼接的改进算法》最佳缝合线算法 图像融合
    Mat_<Vec3f>  bestlinefusion(Mat_<Vec3f> & A,Mat_<Vec3f>& B,int rdata1)
    //function D=bestlinefusion(A,B,rdata1)
    {
    	//先根据之前得到的H矩阵计算重叠区域Rect
    	//[H,W,k]=size(A);
    	int H,W;
    	H=A.rows;W=A.cols;
    
    	//rdata1=-118;
    	//rdata1=fix(-rdata1);
    	rdata1=-rdata1;
    	//L=W+1+rdata1;
    	int L=W+rdata1;
    	//R=W;
    	int R=W;
    	//n=R-L+1;
    	int n=R-L;
    	//计算得到重叠区域的差值图像  其实我不懂计算差值图像干嘛  只要计算重叠区域的大小就好了 为什么还要计算差值图 后面又没用到
    	//Rect=zeros(H,n);
    	Mat_<float> Rectf=Mat_<float>::zeros(H,n);
    
    #define A(x,y) A(x,y)[0]
    #define B(x,y) B(x,y)[0]
    
    	//for i=1:H
    	for(int i=0;i<H;i++){
    	//	for j=L:R
    		for(int j=L;j<R;j++){
    			Rectf(i,j-L+1)=A(i,j)-B(i,j-L+1);
    			//Rectf(i,j-L)=A(i,j)[0]-B(i,j-L+1)[0];
    	 	}//end
    	}//end
    	//Rectf=uint8(Rectf);//这句要不要呢?
    
    			
    	//最终融合图的大小
    	//rdata1=-118;
    	//rdata2=3;
    	int Y=2*W+rdata1+1;
    	Mat_<Vec3f> D=Mat_<Vec3f>::zeros(H,Y);
    	//放路径的矩阵
    	Mat_<float> path=Mat_<float>::zeros(H,n);
    	//放强度值 每条路径的强度值strength=color^2+geometry
    	Mat_<float> color=Mat_<float>::zeros(1,n);
    	Mat_<float> geometry=Mat_<float>::zeros(1,n);
    	Mat_<float> strength1=Mat_<float>::zeros(1,n);
    	Mat_<float> strength2=Mat_<float>::zeros(1,n);
    
    	float Bxdao;
    	float Bydao;
    	float Aydao;
    	float Axdao;
    
    	//计算第一行即初始化的强度值
    	//for j=L:R
    	for(int j=L;j<R;j++){
    		int y=j-L+1;
    		color(y)=A(1,j)-B(1,y);
    		if(y==1){
    			Bxdao=B(1,y+1)+2*B(2,y+1);
    			Bydao=B(2,y)+2*B(2,y+1);
    			Aydao=2*A(2,j-1)+A(2,j)+2*A(2,j+1);
    			Axdao=A(1,j+1)+2*A(2,j+1)-A(1,j-1)-2*A(2,j-1);
    			geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
    			strength1(y)=sqrt(color(y))+geometry(y);
    			path(1,y)=y;
    			continue;
    		}//end
    		if(j==R){
    			Axdao=A(1,j-1)-2*A(2,j-1);
    			Aydao=2*A(2,j-1)+A(2,j);
    			Bxdao=B(1,y+1)+2*B(2,y+1)-B(1,y-1)-2*B(2,y-1);
    			Bydao=2*B(2,y-1)+B(2,y)+2*B(2,y+1);
    			geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
    			strength1(y)=sqrt(color(y))+geometry(y);
    			path(1,y)=y;
    			continue;
    		}//end
    		Axdao=A(1,j+1)+2*A(2,j+1)-A(1,j-1)-2*A(2,j-1);
    		Bxdao=B(1,y+1)+2*B(2,y+1)-B(1,y-1)-2*B(2,y-1);
    		Aydao=2*A(2,j-1)+A(2,j)+2*A(2,j+1);
    		Bydao=2*B(2,y-1)+B(2,y)+2*B(2,y+1);
    		geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
    		strength1(y)=sqrt(color(y))+geometry(y);
    		path(1,y)=y;
    	}//end
    color=Mat_<float>::zeros(1,n);
    geometry=Mat_<float>::zeros(1,n);
    float small=0;
    
    //开始扩展 向下一行 从第二行到倒数第二行 最后一行单独拿出来 像第一行一样 因为它的结构差值geometry不好算
    //for i=2:H-1
    for(int i=1;i<H-1;i++){
        //先把下一行的强度值全部计算出来 到时候需要比较哪三个就拿出哪三个
        //for j=L:R
    	for(int j=L;j<R;j++){
            int x=i;
            int y=j-L+1;
            color(y)=A(i,j)-B(x,y);
    		if(y==1){
                Axdao=2*A(i-1,j+1)+A(i,j+1)+2*A(i+1,j+1)-2*A(i-1,j-1)-A(i,j-1)-2*A(i+1,j-1);
                Bxdao=2*B(x-1,y+1)+B(x,y+1)+2*B(x+1,y+1);
                Aydao=-2*A(i-1,j-1)-A(i-1,j)-2*A(i-1,j+1)+2*A(i+1,j-1)+A(i+1,j)+2*A(i+1,j+1);
                Bydao=-B(x-1,y)-2*B(x-1,y+1)+B(x+1,y)+2*B(x+1,y+1);
                geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
                strength2(y)=sqrt(color(y))+geometry(y);
                continue;
    		}//end
    		if(j==R){
                Axdao=-2*A(i-1,j-1)-A(i,j-1)-2*A(i+1,j-1);
                Bxdao=2*B(x-1,y+1)+B(x,y+1)+2*B(x+1,y+1)-2*B(x-1,y-1)-B(x,y-1)-2*B(x+1,y-1);
                Aydao=-2*A(i-1,j-1)-A(i-1,j)+2*A(i+1,j-1)+A(i+1,j);
                Bydao=-2*B(x-1,y-1)-B(x-1,y)-2*B(x-1,y+1)+2*B(x+1,y-1)+B(x+1,y)+2*B(x+1,y+1);
                geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
                strength2(y)=sqrt(color(y))+geometry(y);
               continue;
    		}//end
            Axdao=2*A(i-1,j+1)+A(i,j+1)+2*A(i+1,j+1)-2*A(i-1,j-1)-A(i,j-1)-2*A(i+1,j-1);
            Bxdao=2*B(x-1,y+1)+B(x,y+1)+2*B(x+1,y+1)-2*B(x-1,y-1)-B(x,y-1)-2*B(x+1,y-1);
            Aydao=-2*A(i-1,j-1)-A(i-1,j)-2*A(i-1,j+1)+2*A(i+1,j-1)+A(i+1,j)+2*A(i+1,j+1);
            Bydao=-2*B(x-1,y-1)-B(x-1,y)-2*B(x-1,y+1)+2*B(x+1,y-1)+B(x+1,y)+2*B(x+1,y+1);
            geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
            strength2(y)=sqrt(color(y))+geometry(y);
    	}//end
        //for j=1:n
    	for(int j=0;j<n;j++){
    		if(path(i-1,j)==1){
    			if(strength2(1)<strength2(2)){
                  strength1(j)=strength1(j)+strength2(1);
                  path(i,j)=1;
    			}else{
                  strength1(j)=strength1(j)+strength2(2);
                  path(i,j)=2;
    			}//end
    		}else{
    			if(path(i-1,j)==n){
    				if(strength2(n-1)<strength2(n)){
                    strength1(j)=strength1(j)+strength2(n-1);
                    path(i,j)=n-1;
    				}else{
                    strength1(j)=strength1(j)+strength2(n);
                    path(i,j)=n;
    				}//end
    			}else{
    				if(strength2(path(i-1,j)-1)<strength2(path(i-1,j))){
    					if(strength2(path(i-1,j)-1)<strength2(path(i-1,j)+1)){
                            small=strength2(path(i-1,j)-1);
                            path(i,j)=path(i-1,j)-1;
                        }else{
                            small=strength2(path(i-1,j)+1);
                            path(i,j)=path(i-1,j)+1;
                        }//end
                    }else{
    					if(strength2(path(i-1,j))<strength2(path(i-1,j)+1)){
                            small=strength2(path(i-1,j));
                            path(i,j)=path(i-1,j);
                        }else{
                            small=strength2(path(i-1,j)+1);
                            path(i,j)=path(i-1,j)+1;
                        }//end
                    }//end
                    strength1(j)=strength1(j)+small;
                }//end
    		}//end
            small=0;
    	}//end
        strength2=Mat_<float>::zeros(1,n);
        color=Mat_<float>::zeros(1,n);
        geometry=Mat_<float>::zeros(1,n);
        //if (0==(i%10))cout<<i<<endl;//disp(i);end;
    }//end
    //cout<<"color:"<<color.rows<<"'"<<color.cols<<endl;
    
    //单独计算最后一行
    {
    int i=H-1;
    //for j=L:R
    //cout<<"L,R:"<<L<<"'"<<R<<endl;
    
    for(int j=L;j<R;j++){
    
            int x=i;
            int y=j-L+1;
    	//cout<<"i:"<<i<<endl;
    	//cout<<"j:"<<j<<endl;
    	//cout<<"x:"<<x<<endl;
    	//cout<<"y:"<<y<<endl;
    		
            color(y)=A(i,j)-B(x,y);
    		if(y==1){
                Axdao=2*A(i-1,j+1)+A(i,j+1)-2*A(i-1,j-1)-A(i,j-1);
                Aydao=-2*A(i-1,j-1)-A(i-1,j)-2*A(i-1,j+1);
                Bxdao=2*B(x-1,y+1)+B(x,y+1);
                Bydao=-B(x-1,y)-2*B(x-1,y+1);
                continue;
            }//end
    		if(j==R){
                Bxdao=2*B(x-1,y+1)+B(x,y+1)-2*B(x-1,y-1)-B(x,y-1);
                Bydao=-2*B(x-1,y-1)-B(x-1,y)-2*B(x-1,y+1);
                Axdao=-2*A(i-1,j-1)-A(i,j-1);
                Aydao=-2*A(i-1,j-1)-A(i-1,j);
                continue;
            }//end 
            Axdao=2*A(i-1,j+1)+A(i,j+1)-2*A(i-1,j-1)-A(i,j-1);
            Bxdao=2*B(x-1,y+1)+B(x,y+1)-2*B(x-1,y-1)-B(x,y-1);
            Aydao=-2*A(i-1,j-1)-A(i-1,j)-2*A(i-1,j+1);
            Bydao=-2*B(x-1,y-1)-B(x-1,y)-2*B(x-1,y+1);
            geometry(y)=(Axdao-Bxdao)*(Aydao-Bydao);
            strength2(y)=sqrt(color(y))+geometry(y);
    }//end
    
    //for j=1:n
    for(int j=0;j<n;j++){
    	if(path(i-1,j)==1){
    		if(strength2(1)<strength2(2)){
                  strength1(j)=strength1(j)+strength2(1);
                  path(i,j)=1;
               }else{
                  strength1(j)=strength1(j)+strength2(2);
                  path(i,j)=2;
               }//end
            }else{
    			if(path(i-1,j)==n){
    				if(strength2(n-1)<strength2(n)){
                    strength1(j)=strength1(j)+strength2(n-1);
                    path(i,j)=n-1;
                  }else{
                    strength1(j)=strength1(j)+strength2(n);
                    path(i,j)=n;
                  }//end
                }else{
    				if(strength2(path(i-1,j)-1)<strength2(path(i-1,j))){
    					if(strength2(path(i-1,j)-1)<strength2(path(i-1,j)+1)){
                            small=strength2(path(i-1,j)-1);
                            path(i,j)=path(i-1,j)-1;
                        }else{
                            small=strength2(path(i-1,j)+1);
                            path(i,j)=path(i-1,j)+1;
                        }//end
                    }else{
    					if(strength2(path(i-1,j))<strength2(path(i-1,j)+1)){
                            small=strength2(path(i-1,j));
                            path(i,j)=path(i-1,j);
                        }else{
                            small=strength2(path(i-1,j)+1);
                            path(i,j)=path(i-1,j)+1;
                        }//end
                    }//end
                    strength1(j)=strength1(j)+small;
                }//end
            }//end
            small=0;
    }//end  
    }
    //比较strength1里放的每条路径的强度值的总和 谁最小 就选path中对应的那一列的路径
    //[minzhi,minth]=min(strength1);
    float minzhi=strength1(0);
    int minth=0;
    for(int i=1;i<n;i++){
    	if(minzhi>strength1(i)){
    		minzhi=strength1(i);
    		minth=i;
    	}
    }
    Mat_<float> mypath=Mat_<float>::zeros(H,1);
    //mypath=path(:,minth);
    mypath=path.colRange(n-1,n);
    //朋友MR_Radish666 说上句应该是:mypath=path.colRange(minth-1,minth);
    
    //cout<<"一条最小路径:"<<endl<<mypath<<endl;
    
    #undef A
    #define A(x,y,i) A(x,y)[i-1]
    #undef B
    #define B(x,y,i) B(x,y)[i-1]
    #define D(x,y,i) D(x,y)[i-1]
    
    //mypath放的就是最佳缝合线选出的路径 这条路径坐标是参考图A 右边是目标图B
    //for i=1:H
    for(int i=0;i<H;i++){
    	for(int j=0;j<mypath(i)+L;j++){
            D(i,j,1)=A(i,j,1);
            D(i,j,2)=A(i,j,2);
            D(i,j,3)=A(i,j,3);
        }//end
    	for(int j=mypath(i)+L;j<Y;j++){
             int x=i;
             int y=j-L+1;
             //if( y>W || x>H )continue;//end
             D(i,j,1)=B(x,y,1);
             D(i,j,2)=B(x,y,2);
             D(i,j,3)=B(x,y,3);
        }//end
    }//end
    
     //D=uint8(D);
    
    // 画最佳缝合线
    L=W+1+rdata1;
    //figure;imshow(D)
    //hold on;
    for(int i=0;i<H;i++){
         D(i,L+mypath(i),1)=1.0;
         D(i,L+mypath(i),2)=1.0;
         D(i,L+mypath(i),3)=1.0;
    }//end
    //hold off;
    //Mat roi2;
    //D.convertTo(roi2,CV_8U,255);
    //imwrite("line.jpg",roi2);
     return D;
    #undef A
    #undef B
    #undef D
    
    }
    

    然后调用这个函数,调用前

     

    先准备好,左、右图,(由于这个函数只能左向右拼,如果要向其它方向拼,可能要先翻转图像):

     

    //左图
    Mat_<Vec3f> l; 
    int x=p.x-(im.cols-w);
    
    cout<<"x="<<x<<endl;
    Mat l8u(dst, Rect(x, p.y, im.cols, im.rows));//左图
    
    l8u2.convertTo(l,CV_32F,1.0/255.0);//Vec3f表示有三个通道,即 l[row][column][depth]
    
    //imshow("l",l);
    
    
    //右图
    Mat_<Vec3f> r; 
    im.convertTo(r,CV_32F,1.0/255.0);
    //缝合图
    Mat_<Vec3f> bm=bestlinefusion(l,r,w);
    
    //imshow("最佳缝合线",bm);
    Mat src;
    bm.convertTo(src,CV_8U,255);
    Mat dstroi(dst, Rect(p.x, p.y, im.cols, im.rows));//大图中的右图位置
    
    Rect r0(im.cols-w,0,im.cols,im.rows);  // 只取右图位置
    
    src(r0).convertTo(dstroi, dstroi.type(), 1,0); // 到大图
    


    再把该文中的多分辨率拼接类保存为cpp放在我们的程序中

     

     

    #include"v2.cpp"//多频段图像融合 类
    

    和上面的函数类似,准备左、右、掩码图,调用

     

     

    Mat_<Vec3f> blend = LaplacianBlend(l, r, m);//金字塔融合
    blend.convertTo(dstroi,CV_8U,255);//到大图
    

    效果图:

     



    哪个重影已经没有了。

    这个最佳缝合线好象不是很好,好多地方跑到重合区边界就成一条直线了,接缝就比较明显了

    先这样吧。

     

    展开全文
  • Visionpro实现多图像拼接

    千次阅读 2020-09-24 16:19:58
    将四张图拼接在一起,新建作业,在配置中新建C#脚本,添加代码如下 using System; using System.Threading; using System.Windows.Forms; using Cognex.VisionPro; using Cognex.VisionPro.QuickBuild; using ...

    将四张图拼接在一起,新建作业,在配置中新建C#脚本,添加代码如下

    using System;
    using System.Threading;
    using System.Windows.Forms;
    using Cognex.VisionPro;
    using Cognex.VisionPro.QuickBuild;
    using Cognex.VisionPro.ImageProcessing;
    
    public class UserScript : CogJobBaseScript
    {
      private CogCopyRegionTool  imageStitcher;
      private int                Counter;
      
    
    #region "When an Acq Fifo Has Been Constructed and Assigned To The Job"
      // This function is called when a new fifo is assigned to the job.  This usually
      // occurs when the "Initialize Acquisition" button is pressed on the image source
      // control.  This function is where you would perform custom setup associated
      // with the fifo.
      public override void AcqFifoConstruction(Cognex.VisionPro.ICogAcqFifo fifo)
      {
      }
    #endregion
    
    #region "When an Acquisition is About To Be Started"
      // Called before an acquisition is started for manual and semi-automatic trigger
      // models.  If "Number of Software Acquisitions Pre-queued" is set to 1 in the
      // job configuration, then no acquisitions should be in progress when this
      // function is called.
      public override void PreAcquisition()
      {
        // To let the execution stop in this script when a debugger is attached, uncomment the following lines.
        // #if DEBUG
        // if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
        // #endif
    
      }
    #endregion
    
    #region "When an Acquisition Has Just Completed"
      // Called immediately after an acquisition has completed.
      // Return true if the image should be inspected.
      // Return false to skip the inspection and acquire another image.
      public override bool PostAcquisitionRefInfo(ref Cognex.VisionPro.ICogImage image,
                                                      Cognex.VisionPro.ICogAcqInfo info)
      {
        // To let the execution stop in this script when a debugger is attached, uncomment the following lines.
        // #if DEBUG
        // if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
        // #endif
        
        Counter = Counter + 1;
        
        if(Counter == 1)
        {
          //Create a new tool
          imageStitcher = new CogCopyRegionTool();
          
          //Create a destination image and assign it to the tool
          CogImage8Grey stitchedImage = new CogImage8Grey();
          stitchedImage.Allocate(image.Width * 2, image.Height * 2);
          imageStitcher.DestinationImage = stitchedImage;
          
          imageStitcher.Region = null;
          imageStitcher.RunParams.ImageAlignmentEnabled = true;
          
          //First sub-image goes into the upper left corner
          imageStitcher.RunParams.DestinationImageAlignmentX = 0;
          imageStitcher.RunParams.DestinationImageAlignmentY = 0;
          
        }
        
        else if(Counter == 2)
        {
          //Second sub-image goes into the upper right cornet
          imageStitcher.RunParams.DestinationImageAlignmentX = image.Width;
          imageStitcher.RunParams.DestinationImageAlignmentY = 0;
        }
        
        else if(Counter == 3)
        {
          //Third sub-image goes into the lower left corner
          imageStitcher.RunParams.DestinationImageAlignmentX = 0;
          imageStitcher.RunParams.DestinationImageAlignmentY = image.Height;
        }
        
        else
        {
          //Final sub-image goes into the lower right corner
          imageStitcher.RunParams.DestinationImageAlignmentX = image.Width;
          imageStitcher.RunParams.DestinationImageAlignmentY = image.Height;
        }
        
        //Run the tool to add the just-acquired sub-image
        imageStitcher.InputImage = CogImageConvert.GetIntensityImage(image, 0, 0, image.Width, image.Height);
        imageStitcher.Run();
        
        if(Counter == 4)
        {
          //Set the acquired image to the final stitched image
          image = imageStitcher.OutputImage;
          
          //Reset to begin a new stitched image next time
          imageStitcher = null;
          Counter = 0;
          
          //Return true to inspect the stitched image
          return true;
        }
    
        else
        {
          //Return false to skip inspectiona nd acquire the next sub-image
          return false;
        }
      }
    #endregion
    
    #region "When the Script is Initialized"
      //Perform any initialization required by your script here.
      public override void Initialize(CogJob jobParam)
      {
        //DO NOT REMOVE - Call the base class implementation first - DO NOT REMOVE
        base.Initialize(jobParam);
        
        imageStitcher = null;
        Counter = 0;
      }
    #endregion
    
    }
    

    最终拼接效果如图所示:

     

    参考:

    蔚来教育企业店

    展开全文
  • VisionPro_9.5中多图像拼接简单操作

    千次阅读 2020-09-10 22:53:09
    但是如果涉及到测量,定位,计数等类似应用的时候,图像拼接技术则显的非常重要。 这里模拟四台相机分别拍摄一组二维码图像,然后将四张图拼接成为一张图,最后实现读码的功能。 实现功能: 1. 准备4张图像 2. 在...

    应用场景:

    比如在一个视觉项目应用中,由于FOV过大,单相机像素精度不能满足预期,那么就需要分开布局多个相机拍摄。但是如果涉及到测量,定位,计数等类似应用的时候,图像拼接技术则显的非常重要。
    这里模拟四台相机分别拍摄一组二维码图像,然后将四张图拼接成为一张图,最后实现读码的功能。
    实现功能:
    在这里插入图片描述

    1. 准备4张图像
    在这里插入图片描述
    2. 在VisionPro中新建一个ToolBlock,然后添加4个CogImageFileTool工具
    在这里插入图片描述
    3. 然后依次加载上面准备好的4张图像
    在这里插入图片描述
    注意:这里用CogImageFileTool工具模拟真实环境中4台相机,真实环境中
    只需要将CogImageFileTool替换成CogAcqFifoTool,然后为每个CogAcqFifoTool工具分配一台相机即可。

    4. 添加CogIDTool工具,用于读取拼接后图像的二维码
    在这里插入图片描述
    这里的InputImage可以暂时不用引用,后面直接在脚本中赋值即可。

    5. 重点部分:为ToolBlock编写脚本

    5.1 添加程序集Dll
    在这里插入图片描述
    5.2 引用命名空间:
    在这里插入图片描述
    5.3 代码部分:

    public class CogToolBlockAdvancedScript : CogToolBlockAdvancedScriptBase
    {
      private Cognex.VisionPro.ToolBlock.CogToolBlock mToolBlock;
      private List<CogImage8Grey> imgList = new List<CogImage8Grey>();
      private CogCopyRegionTool imageStitcher = new CogCopyRegionTool();
      private CogIDTool idTool;
        
      public override bool GroupRun(ref string message, ref CogToolResultConstants result)
      {
        //if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
        imgList.Clear();
       
        // Run each tool using the RunTool function
        foreach(ICogTool tool in mToolBlock.Tools)
        {
          if(tool is CogImageFileTool)
          {
            //如果是真实现场的相机,这里需要改成CogAcqFifoTooL
            CogImageFileTool imageTool = (CogImageFileTool) tool;
            imageTool.Run();
            if(imageTool.OutputImage != null)
            {
              //将所有采到的图像,按上往下的顺序,依次保存在List集合中
              imgList.Add((CogImage8Grey)imageTool.OutputImage);
            }
          }
        }
        
        CogImage8Grey img = new CogImage8Grey();
        img.Allocate(imgList[0].Width * 2, imgList[0].Height * 2);
        
        //指定画框
        imageStitcher.DestinationImage = img;
        
        imageStitcher.Region = null;
        imageStitcher.RunParams.ImageAlignmentEnabled = true;
        
        for (int i = 0; i < 4; i++)
        {
          //这里指定图像存放在画框中的起始XY点,然后程序跳转到if else下面
          //将当前遍历到的照片贴进画框中
          if(i == 0) 
          {
            imageStitcher.RunParams.DestinationImageAlignmentX = 0;
            imageStitcher.RunParams.DestinationImageAlignmentY = 0;
          }
          else if(i == 1)
          {
            imageStitcher.RunParams.DestinationImageAlignmentX = imgList[i].Width;
            imageStitcher.RunParams.DestinationImageAlignmentY = 0;
          }
          else if(i == 2)
          {
            imageStitcher.RunParams.DestinationImageAlignmentX = 0;
            imageStitcher.RunParams.DestinationImageAlignmentY = imgList[i].Height;
          }
          else
          {
            imageStitcher.RunParams.DestinationImageAlignmentX = imgList[i].Width;
            imageStitcher.RunParams.DestinationImageAlignmentY = imgList[i].Height;
          }
          //将当前遍历到的图像贴进画框中
          imageStitcher.InputImage = CogImageConvert.GetIntensityImage(imgList[i], 0, 0, imgList[i].Width, imgList[i].Height);
          imageStitcher.Run();
        }
        mToolBlock.Outputs[0].Value = imageStitcher.OutputImage;
        
        // Read ID Tool
        idTool= mToolBlock.Tools["CogIDTool1"] as CogIDTool;
        idTool.InputImage = (CogImage8Grey) mToolBlock.Outputs[0].Value;
        idTool.Run();
        
        return false;
      }
    }

    原理: 可以将CogCopyRegionTool对象想象成一个尚未完成的画框,因为要装4张图,所以首先需要确定画框尺寸 (一张图*2的大小)。
    然后准备装照片进去了,拿到一张照片后,首先确定照片应该放置的位置 (第一张00,第二张10,第三张01,第四张11这样)。
    在这里插入图片描述
    确认完一张图像位置之后,则将当前的图片装入指定的位置,以此往复。

    6. 最终,我们会得到一张全新的无缝拼接图片(为了便于展示直接通过代码的形式将其传入CogODTool工具的输入)
    在这里插入图片描述
    以上,如有错误,欢迎指正,谢谢。。。

    展开全文
  • 简单快速的多图像拼接---百图拼接

    千次阅读 热门讨论 2018-03-19 09:08:00
    opencv自带的stitching速度很慢,而且对图容易出错,好象对竖着拍摄的图(高&gt;宽)不能用。 其中一个最大的原因是每一张图都要和其它的图去匹配,如果有10张图,除去自身不用匹配外, 要匹配 10X(10-1) = ...

    opencv自带的stitching速度很慢,而且对多图容易出错,好象对竖着拍摄的图(高>宽)不能用。

    其中一个最大的原因是每一张图都要和其它的图去匹配,如果有10张图,除去自身不用匹配外,

    要匹配 10X(10-1) = 90 次。所以慢得不能忍受。(等了很久很久,咚的出错,这感受真的不好)

    我们拍摄全景图的时候都是从左到右,或者从右到左,前后两张图一般有部分重合。

    所以我们这里只对前后两张图匹配,然后连成一串。

    流程:

    1。从列表(list.txt)文件装载图像文件名
    2。前后匹配
    3。计算匹配图像的相对位置
    4。以第一张图左上角点为原点,找到所有图的位置(同一坐标系)
    5。再计算最小,最大边界,并构建一个大图
    6。再把所有图像放到一个大图中
    

    main:

    int main ()
    {
    	/*	特征点的提取与匹配 	*/
    
    	vector<string> image_names; // image_names[i]表示第i个图像的名称
    
        LoadImageNamesFromFile("list0.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); // 特征点匹配
    	//gms_match_features(image_keypoints,img0.size(),image_matches);
    
    	//单应性过滤特征点
    	for (unsigned int i=0;i<image_matches.size ();i++)
    	{
    		refineMatchesWithHomography( image_keypoints[i], image_keypoints[i+1],1.0, image_matches[i]    );    
    	}	
    	image_descriptor.swap(vector<Mat>());//匹配完清除内存
    
    	Mat img0 = imread(image_names[0]);//读出一个图
    	img0= mynarrow(img0);//如果太大缩小一点。(>2400*1200的)
    
    
    	//显示匹配
    	//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<cv::Point2f> position_da; // position_da[i]表示第i个图像在大图中的位置(左上角)
    	Point2f position_s=Point2f(0,0);
    	position_da.push_back (position_s); // 第1个图像为原点
    
    
    	for (unsigned int i=0;i<image_matches.size ();i++)
    	{
    
    		if(image_matches[i].size ()==0)break;//如果无匹配点,则后面的就取消了
    
    		//得到匹配点坐标
    		vector<Point2f> points1, points2;
    		get_match_points (image_keypoints[i], image_keypoints[i+1] ,image_matches[i], points1, points2);
    		unsigned int shi=image_matches[i].size ();
    		shi=(shi>10)?10:shi;//只取前十个
    		Point2f a;
    		for(unsigned int j=0;j<shi;j++)
    		{
    			a.x+=points1[j].x-points2[j].x;
    			a.y+=points1[j].y-points2[j].y;
    		}
    		a.x /=shi;a.y /=shi;//取平均值
    		cout << "两个相差:"<<a<< endl;
    
    		//在大图的位置
    		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;
    		
    
    
    
    	}
    	vector<vector<KeyPoint>>().swap(image_keypoints);//已经用不到了,清除容器并最小化它的容量
    
    
    	//再计算最小,最大边界
    	int 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 = img0.rows + ymax-ymin;//拼接图行数(高度)
    	int w = img0.cols + xmax-xmin;//拼接图列数(宽度)
    	Mat stitch = Mat::zeros(h, w, CV_8UC3);
    
    	//再把所有图像放到一个大图中(拼接)
    	for (unsigned int i=0;i<position_da.size ();i++)
    	{
    		img0 = imread(image_names[i]);//读出一个图//左图像
    		img0= mynarrow(img0);//如果太大缩小一点。
    
    		Mat roi2(stitch, Rect(position_da[i].x-xmin, position_da[i].y-ymin, img0.cols, img0.rows));
            img0(Range(0, img0.rows), Range(0, img0.cols)).copyTo(roi2);
    
    	}
    
    
        imshow("拼接结果", stitch);
        imwrite("stitch.jpg", stitch);
    		waitKey();
    	return 0;
    }

    用到的函数:

    //如果图像太大缩小一半
    Mat mynarrow(Mat img)
    {
    	Mat dst ;//读出一个图
    	if(img.rows*img.cols>2400*1200)
    		resize(img,dst,Size(),0.5,0.5); 
    	else
    		dst=img.clone();
    	return dst;
    }
    

    在所有读图的地方都要用上。

    过滤函数:

    //用单应性过滤匹配
    bool refineMatchesWithHomography(const std::vector<cv::KeyPoint>& queryKeypoints,      
        const std::vector<cv::KeyPoint>& trainKeypoints,       
        float reprojectionThreshold,      
        std::vector<cv::DMatch>& matches//,      
        //cv::Mat& homography
    	)    
    {    cv::Mat homography;
        const int minNumberMatchesAllowed = 4;      
        if (matches.size() < minNumberMatchesAllowed)      
            return false;      
        // 为 cv::findHomography 准备数据    
        std::vector<cv::Point2f> queryPoints(matches.size());      
        std::vector<cv::Point2f> trainPoints(matches.size());      
        for (size_t i = 0; i < matches.size(); i++)      
        {      
            queryPoints[i] = queryKeypoints[matches[i].queryIdx].pt;      
            trainPoints[i] = trainKeypoints[matches[i].trainIdx].pt;      
        }      
        // 查找单应矩阵并获取内点掩码    
        std::vector<unsigned char> inliersMask(matches.size());      
        homography = cv::findHomography(queryPoints,       
            trainPoints,       
            CV_FM_RANSAC,       
            reprojectionThreshold,       
            inliersMask);      
        std::vector<cv::DMatch> inliers;      
        for (size_t i=0; i<inliersMask.size(); i++)      
        {      
            if (inliersMask[i])      
                inliers.push_back(matches[i]);      
        }      
        matches.swap(inliers);    
        //Mat homoShow;    
        //drawMatches(src,queryKeypoints,frameImg,trainKeypoints,matches,homoShow,Scalar::all(-1),CV_RGB(255,255,255),Mat(),2);         
        //imshow("homoShow",homoShow);     
        return matches.size() > minNumberMatchesAllowed;     
      
    }  

    其它的在前一个文章中

    效果图:

    38个图合成

    75个图合成

    由于原始图像太大,上传是缩小了。虽然效果不是很理想,但速度很快

    第一个拍了2圈,第二个拍了3圈,如果分别分成2次和3次合成,可能不一样。

    结束

    -----------------------分隔线---------------------------------

    应有人要完整的程序,现修改一下:

    请把-main- "复制" 保存为 “快主main函数.cpp”
    再把-mynarrow函数- "复制" 保存为 "mynarrow函数.cpp"
    把-过滤函数- "复制" 保存为 "过滤函数.cpp"
    最后把下面的函数- "复制" 保存为 "获取匹配点坐标.cpp"
     

    //获取匹配点坐标
    /********************************************************************************************************
    参数:
    keypoints1 第一张图片的特征点; keypoints2 第二张图片的特征点; matches 匹配的结果; (points1[i], points2[i]) 第
    i个匹配的特征点对。
    功能:
    利用两张图片的特征点keypoints1、keypoints2和匹配的结果matches,可以得到两个数组points1和points2,
    (points1[i], points2[i])表示第i个匹配的特征点对。
    *********************************************************************************************************/
    void get_match_points (
    	vector<KeyPoint> keypoints1,
    	vector<KeyPoint> keypoints2,
    	vector<DMatch> matches,
    	vector<Point2f>& points1,
    	vector<Point2f>& points2
    )
    {
    	for (int i = 0; i < matches.size (); i++)
    	{
    		points1.push_back (keypoints1[matches[i].queryIdx].pt);
    		points2.push_back (keypoints2[matches[i].trainIdx].pt);
    	}
    }
    
    

    完整的程序为:
     

    #include "头包含.cpp"
    
    #include "用到的函数.cpp"
    
    //#include "主main函数.cpp"
    
    //=================分隔线(之前在上一篇中)=======================
    
    #include "mynarrow函数.cpp"
    
    #include "过滤函数.cpp"
    
    #include "获取匹配点坐标.cpp"
    
    #include "快主main函数.cpp"
    

     

    展开全文
  • 需求 高性能图像拼接服务器由于在存在误差,需要使用标定软件获取计算后的每个位置图片进行像素标定(校准),将人工校准的图像相关信息以指令形式发送给服务器端,服务器的每次拼接将依赖此标定参数。 标定80幅图,...
  • 4)开始拼接,拷贝第一张图片的数据,按照左上角坐标为(0,0),此处我们因需要把图像显示在中间,故我们是从坐标(0,320)开始的,一行一行的拷贝数据,拷贝完第一张图片后,做一个偏移,开始拷贝第二张图片数据...
  • 主要为大家详细介绍了python实现单张图像拼接与批量图片拼接,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 图像拼接程序图像拼接程序图像拼接程序图像拼接程序图像拼接程序图像拼接程序图像拼接程序
  • 图像拼接 轻松实现拼接 编译环境是visual C++ 6.0
  • 主要为大家详细介绍了opencv实现图像拼接功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • MATLAB 程序 实现图像拼接,自动匹配特征点 将图片拼接成长图,MATLAB 程序 实现图像拼接,自动匹配特征点 将图片拼接成长图MATLAB 程序 实现图像拼接,自动匹配特征点 将图片拼接成长图
  • 多图像拼接算法研究,能实现图像拼接
  • OpenCV图像拼接,OpenCV扩展模块配置 VS2015,OpenCV3.1.0点扩展模块环境配置。 两张图像拼接图像拼接。 技术交流 资源共享 博主QQ:68823886
  • Python实现单张图像拼接与批量图片拼接.pdf
  • 图像拼接简介 传统全景图(panorama) 是由在一个固定位置上以不同角度拍摄到的一系列图像拼接而成的大视场图像 特点没有或只有轻微的运动视差 多重投影拼接图(multi-perspective mosaic) 是由在一些不同位置上拍摄到...
  • 图像拼接imagestitching

    千次下载 热门讨论 2012-05-22 17:17:54
    基于opencv2.4.0+vs2008平台的图像拼接,附带3张练习图片
  • 图像拼接matlab实现 sift特征提取、描述、匹配、RANSAC、仿射变换 图像拼接matlab实现 sift特征提取、描述、匹配、RANSAC、仿射变换
  • 图像拼接

    千次阅读 2018-12-08 17:15:01
    图像拼接是指将描述同一场景的两张或者张有重叠区域的图像,通过图像配准和图像融合技术拼接成一幅大场景全新图像的过程。 文章目录图像拼接过程的三个过程图像的预处理图像预处理图像的投影模型平面投影模式...
  • 图像拼接论文集,包括大规模显微图像拼接算法,基于2D格状图的显微图像拼接,基于尺度不变特征变换特征的显微图像在线拼接方法,基于互相关的显微医学图像配准,基于特征的显微图像全自动拼接,基于最小路由代价树的...
  • 图像拼接综述

    2018-04-15 15:55:34
    图像拼接综述图像拼接技术是虚拟现实和图像绘制技术的一个重要研究方向,该文对图像拼接的内涵进行了阐述,提出图像拼接在虚拟现实、 提高图像的分辨率、增大光学系统的视场角、方便图像的检索、编辑、分析和理解等...
  • 图像拼接matlab实现 sift特征提取、描述、匹配、RANSAC、仿射变换 图像拼接matlab实现 sift特征提取、描述、匹配、RANSAC、仿射变换

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 115,914
精华内容 46,365
关键字:

多图像拼接