找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1668|回复: 0
收起左侧

C++图像拼接源程序

[复制链接]
ID:887902 发表于 2021-3-3 09:45 | 显示全部楼层 |阅读模式
自己做的图像拼接程序
51hei.png 51hei.png DJI_0058.JPG

待拼接图2

待拼接图2

拼接图

拼接图


源程序如下:

  1. //根据输入图像srcImg及其角点坐标和筛选过的keypoints向量,拼接两幅图像,输出拼接后的图像及新图像的角点

  2. class corners
  3. {

  4. public:
  5.         
  6.         Mat left_top,left_bottom,right_top,right_bottom;

  7.         
  8. };

  9. //图像融合总函数
  10. void FuseImg(Mat srcImg1, corners srcImg1_in_srcImg1,
  11.                  Mat srcImg2, corners srcImg2_in_srcImg2,
  12.                  vector<KeyPoint> FilterdKeypoints,
  13.                          vector<KeyPoint> matchedFilterdKeypoints,
  14.                          Mat &dstImg, corners &dstimg_in_dstimg);


  15. ////将原图像角点变换至目标图像坐标系下,确保corners_be_transformed里的矩阵数据类型为float型
  16. void put_value_2_transformed_corners(vector<Mat> corners_2_be_transformed,
  17.                                          Mat H_inverted,
  18.                                                                          vector<Mat> &corners_be_transformed);


  19. //根据两幅图像在新图像中的位置,确定平移量
  20. void get_transformation(vector<Mat> corner_srcImg1_in_dstImg,
  21.                             vector<Mat> corner_srcImg2_in_dstImg,
  22.                                                 Mat &trf);

  23. //根据输入图角点在最终图中的位置向量和位移,更新输入图角点在最终图中的位置类corners,保证坐标为int型
  24. void update_corners_in_dst(vector<Mat> corner_srcImg_in_dstImg,
  25.                                Mat trf, corners &mat_src_in_dst);

  26. //-----------------------------------------------计算dst的尺寸大小-----------------------------------------
  27. void cal_size_dstImg(vector<Mat> corner_srcImg1_in_dstImg,
  28.                      vector<Mat> corner_srcImg2_in_dstImg,
  29.                                          Mat trsf, int &rows_dst, int &cols_dst);

  30. //计算像素点权值
  31. float get_frac(int i_rows, int j_cols, corners corner_mat);

  32. //根据输入图像角点位置更新输出图像角点
  33. void get_union_corner(corners corner_mat_src1_in_dst, corners corner_mat_src2_in_dst, corners &corner_mat_dstImg_in_dstImg);

  34. //将srcImg变换至dstImg上
  35. void transf_srcImg2dst(Mat srcImg2, Mat transformation, vector<KeyPoint> FilterdKeypoints,  vector<KeyPoint> matchedFilterdKeypoints, Mat &dst);

  36. //用图像src更新图像dst
  37. void updateDstImg(Mat srcImg,corners corner_mat_src_in_dst, corners corner_mat_dst_in_dst,Mat &dstImg);
复制代码
  1. #include<iostream>
  2. #include <cxcore.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5. #include "opencv2/legacy/legacy.hpp"
  6. #include <E:\xunfei\stitch_sift20200330_vc10\stitch_sift20200330_vc10\runRansac.h>
  7. using namespace std;
  8. using namespace cv;

  9. /***************************** Function Prototypes ***************************/


  10. /**
  11.    Calculates a best-fit image transform from image feature correspondences
  12.    using RANSAC.
  13.    @ keyPoints,matchedkeyPoints 特征点
  14.    @ unFilteredMatches未筛选的特征匹配
  15.    @ n 匹配数
  16.    @ m 用来计算单应性矩阵的最少特征匹配数
  17.    @param p_badxform 模型允许的最大错误概率
  18.    @param err_tol 匹配误差,通过单应性矩阵变换后,计算匹配误差,在此误差内,认为是内点
  19.    @param n_in 内点数
  20.    @filteredPoints, matchedFilteredPoints最终的内点序列
  21.    @filteredMatches,最终的特征匹配
  22.    @返回最终单应性矩阵
  23.    
  24. */
  25. extern void ransac_xform(  vector<KeyPoint> keyPoints,
  26.                                  vector<KeyPoint> matchedkeyPoints,
  27.                                                          vector<DMatch> unFilteredMatches,
  28.                                                          int n, int m,double p_badxform,double err_tol ,
  29.                                          int &n_in,
  30.                                                          vector<KeyPoint> &FilteredPoints,
  31.                                                          vector<KeyPoint> &matchedFilteredPoints,
  32.                                                          vector<DMatch> &FilteredMatches)
  33. {
  34.         n=(int)unFilteredMatches.size();
  35.         Mat M;//单应性矩阵
  36.         m=N;
  37.         DMatch sample[N];//暂存被随机抽取到的匹配
  38.         DMatch* consensus;//当前一致集
  39.         DMatch* consensus_max = NULL;//当前最大一致集
  40.         double p, in_frac = RANSAC_INLIER_FRAC_EST;//p为当前计算出的模型的错误概率,当p小于p_badxform时迭代终止,in_frac为内点所占比例
  41.         //in为当前一致集元素个数,in_min为一致集中元素个数允许的最小值,保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目
  42.         //im_max为当前最优一致集中的元素个数
  43.         //k为迭代次数
  44.         //k_max为迭代次数最大值,即初始值
  45.         int i, in, in_min, in_max = 0, k = 0, k_max;
  46.         if(n<m)
  47.         {
  48.                 cout<<"实际匹配数小于计算模型需用的最小匹配数"<<endl;
  49.         }

  50.         srand( (int)time(NULL) );//初始化随机数发生器
  51.         //计算保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目
  52.         in_min = calc_min_inliers( n, m, RANSAC_PROB_BAD_SUPP, p_badxform );
  53.         //计算k的最大值
  54.         k_max = calc_max_k(in_frac, p_badxform, m);
  55.         k=k_max;

  56.         for(int j=0;j<k;j++)
  57.         //for(int j=0;j<5;j++)
  58.         {
  59.                 //pts与mpts为之后要用到的m个随机特征点对
  60.                 vector<Point2f> pts,mpts;
  61.                 //随机选择m(4)个匹配
  62.                 draw_ransac_sample( unFilteredMatches, m, n,sample );
  63.                 //提取m个匹配对应的特征点对
  64.                 extract_corresp_pts( keyPoints,matchedkeyPoints,sample, m, pts, mpts );
  65.                 //计算单应性矩阵M
  66.                 xform_fn( pts, mpts, M );
  67.                 //计算一致集和内点数
  68.                 consensus = new DMatch[n];
  69.                 in = find_consensus( keyPoints, matchedkeyPoints, unFilteredMatches, n, M, (double)err_tol, consensus);
  70.                 //更新最优一致集的元素个数和最优一致集
  71.                 if(in>in_max)
  72.                 {
  73.                         in_max = in;
  74.                         consensus_max=consensus;
  75.                         in_frac=((double)in_max)/((double)n);
  76.                 }
  77.                 else delete [] consensus;
  78.                 //根据当前最优一致集的元素个数是否大于要求的最小内点数,判断是否继续迭代
  79.                 if(in_max>in_min)
  80.                 {
  81.                         break;
  82.                 }
  83.                 //更新迭代次数k
  84.                 if(calc_max_k(in_frac, p_badxform, m)>5)
  85.                 {
  86.                         k = calc_max_k(in_frac, p_badxform, m);
  87.                 }
  88.         }
  89.         if(in_max>in_min)
  90.         {
  91.                 for(int j=0; j<in_max; j++)
  92.                 {
  93.                         FilteredPoints.push_back(keyPoints[consensus_max[j].queryIdx]);
  94.                         matchedFilteredPoints.push_back(matchedkeyPoints[consensus_max[j].trainIdx]);
  95.                         FilteredMatches.push_back(consensus_max[j]);
  96.                        
  97.                 }
  98.                 n_in=in_max;
  99.         }
  100.         else
  101.         {
  102.                 n_in=0;
  103.         }

  104. }

  105. //计算计算保证RANSAC最终计算出的转换矩阵错误的概率小于p_badxform所需的最小内点数目
  106. static int calc_min_inliers( int n, int m, double p_badsupp, double p_badxform )
  107. {
  108.   double pi, sum;
  109.   int i, j;

  110.   for( j = m+1; j <= n; j++ )
  111.     {
  112.       sum = 0;
  113.       for( i = j; i <= n; i++ )
  114.         {
  115.           pi = (i-m) * log( p_badsupp ) + (n-i+m) * log( 1.0 - p_badsupp ) +
  116.             log_factorial( n - m ) - log_factorial( i - m ) -
  117.             log_factorial( n - i );
  118.           /*
  119.            * Last three terms above are equivalent to log( n-m choose i-m )
  120.            */
  121.           sum += exp( pi );
  122.         }
  123.       if( sum < p_badxform )
  124.         break;
  125.     }
  126.   return j;
  127. }

  128. //计算阶乘的对数
  129. static inline double log_factorial( int n )
  130. {
  131.   double f = 0;
  132.   int i;

  133.   for( i = 1; i <= n; i++ )
  134.     f += log((double) i );

  135.   return f;
  136. }

  137. //计算迭代次数k的初始值,也是最大值,程序运行后不断更新k;
  138. int calc_max_k(double in_frac, double p_badxform, int m)
  139. {
  140.         double p;
  141.         p=pow(in_frac, m);
  142.         p=1-p;
  143.         double s=0;
  144.         int i=0;
  145.         for(i=0;i<10000;i++)
  146.         {
  147.                 s=pow(p, i);
  148.                 if(s<p_badxform)
  149.                         break;
  150.         }
  151.         return i;
  152. }

  153. //随机选择四个匹配作为计算单应性矩阵的样本值
  154. void draw_ransac_sample( vector<DMatch> unFilteredMatches, int m, int n, DMatch* sample )
  155. {
  156.         for(int i=0;i<m;i++)
  157.         {
  158.                 int id;
  159.                 for(int j=0;j<1000;j++)
  160.                 {
  161.                         id=rand()%n;
  162.                         if(id>(((int)unFilteredMatches.size())))
  163.                                 break;
  164.                 }
  165.                 sample[i]=unFilteredMatches[id];
  166.         }
  167. }

  168. //提取匹配关键点KeyPoints中的点坐标输入到Point2f点对中
  169. void extract_corresp_pts( vector<KeyPoint> kpts,
  170.                               vector<KeyPoint> mkpts,
  171.                                                   DMatch* sample, int m,
  172.                                                   vector<Point2f> &pts,
  173.                                                   vector<Point2f> &mpts )
  174. {
  175.         for(int i=0;i<m;i++)
  176.         {
  177.                 pts.push_back( kpts[sample[i].queryIdx].pt);
  178.                 mpts.push_back( mkpts[sample[i].trainIdx].pt);
  179.         }

  180. }

  181. //根据4对匹配点坐标计算单应性矩阵
  182. void xform_fn( vector<Point2f> pts, vector<Point2f> mpts, Mat &M )
  183. {
  184.         Mat mat(8,8,CV_32FC1,Scalar::all(0));
  185.         Mat mat_invert(8,8,CV_32FC1,Scalar::all(0));
  186.         //初始化系数矩阵行0,2,4,6
  187.         for(int i_rows = 0; i_rows < 4; i_rows++)
  188.         {

  189.                 mat.at<float>(2*i_rows,0) = pts[i_rows].x;//0列

  190.                 mat.at<float>(2*i_rows,1) = pts[i_rows].y;//1列
  191.                
  192.                 mat.at<float>(2*i_rows,2) = 1.0;//2列
  193.                
  194.                 mat.at<float>(2*i_rows,3) = 0.0;//3列
  195.                
  196.                 mat.at<float>(2*i_rows,4) = 0.0;//4列
  197.                
  198.                 mat.at<float>(2*i_rows,5) = 0.0;//5列
  199.                
  200.                 mat.at<float>(2*i_rows,6) = -pts[i_rows].x*mpts[i_rows].x;//6列
  201.                
  202.                 mat.at<float>(2*i_rows,7) = -pts[i_rows].y*mpts[i_rows].x;//7列


  203.         }

  204.         //初始化系数矩阵行1,3,5,7
  205.         for(int i_rows = 0; i_rows<4; i_rows++)
  206.         {
  207.                
  208.                 mat.at<float>(1+2*i_rows,0) = 0.0;//0列
  209.                
  210.                 mat.at<float>(1+2*i_rows,1) = 0.0;//1列
  211.                
  212.                 mat.at<float>(1+2*i_rows,2) = 0.0;//2列
  213.                
  214.                 mat.at<float>(1+2*i_rows,3) = pts[i_rows].x;//3列
  215.                
  216.                 mat.at<float>(1+2*i_rows,4) = pts[i_rows].y;//4列
  217.                
  218.                 mat.at<float>(1+2*i_rows,5) = 1.0;//5列
  219.                
  220.                 mat.at<float>(1+2*i_rows,6) = -pts[i_rows].x*mpts[i_rows].y;//6列
  221.                
  222.                 mat.at<float>(1+2*i_rows,7) = -pts[i_rows].y*mpts[i_rows].y;//7列

  223.         }
  224.         invert(mat,mat_invert);
  225.        

  226.         //计算得到向量or数组
  227.         float vct_mat_invert[8][8],vctr2[8];
  228.         for(int i_rows=0; i_rows<8; i_rows++)
  229.         {
  230.                 for(int j_cols=0; j_cols<8; j_cols++)
  231.                 {
  232.                         vct_mat_invert[i_rows][j_cols] = mat_invert.at<float>(i_rows,j_cols);
  233.                 }
  234.         }
  235.         for(int id=0; id<4;id++)
  236.         {
  237.                 vctr2[id*2]   = mpts[id].x;
  238.                 vctr2[id*2+1] = mpts[id].y;
  239.         }

  240.         //计算homo
  241.         Mat homo(3,3,CV_32FC1,Scalar::all(0));
  242.         for(int i_rows = 0;i_rows < 3;i_rows++)
  243.         {
  244.                 for(int j_cols = 0; j_cols<3 ; j_cols++)
  245.                 {
  246.                         if((i_rows*3+j_cols) < 8)
  247.                         {
  248.                                 homo.at<float>(i_rows,j_cols) = calc_vct_in_prdct(vct_mat_invert[i_rows*3+j_cols], vctr2, 8);
  249.                         }
  250.                         else homo.at<float>(2,2)=1.0;
  251.                        
  252.                 }
  253.         }
  254.         M=homo;

  255. }
  256. //计算向量(or数组)内积
  257. float calc_vct_in_prdct(float* vctr1, float* vctr2, int dim)
  258. {
  259.          float VectorInnerProduct=0.0;
  260.          for(int j=0;j<dim;j++)
  261.          {
  262.                  VectorInnerProduct= VectorInnerProduct+vctr1[j]*vctr2[j];
  263.          }
  264.          return VectorInnerProduct;
  265. }

  266. //计算在单应性矩阵下,一对匹配特征点的像素距离的平方,即误差平方,返回值即为误差平方
  267. float err_fn( KeyPoint pot, KeyPoint mpot, Mat M )
  268. {
  269.          if((((int)M.rows)>3)||(((int)M.cols)>3))
  270.                  return 1000.0;
  271.          float point[3],matched_point[3];
  272.          point[0] = pot.pt.x;
  273.          point[1] = pot.pt.y;
  274.          point[2] = 1.0;

  275.          matched_point[0] = mpot.pt.x;
  276.          matched_point[1] = mpot.pt.y;
  277.          matched_point[2] = 1.0;
  278.          
  279.          float transformed_point[3] = {0.0,0.0,0.0};
  280.          for(int i=0; i<3; i++)
  281.          {
  282.                  for(int j=0; j<3;j++)
  283.                  {
  284.                          transformed_point[i] = transformed_point[i] + M.at<float>(i,j)*point[j];
  285.                  }
  286.          }
  287.          //变换后的像素坐标归一化,即将各坐标都除以Z坐标
  288.          for(int j=0; j<3; j++)
  289.          {
  290.                  transformed_point[j] = transformed_point[j] / transformed_point[2];
  291.          }

  292.          float err_pixl_sqr = 0.0;
  293.          for(int i=0; i<3; i++)
  294.          {
  295.                  err_pixl_sqr = err_pixl_sqr + ( matched_point[i] - transformed_point[i] ) * ( matched_point[i] - transformed_point[i] );
  296.          }
  297.          return err_pixl_sqr;

  298. }

  299. //寻找一致集,返回一致集元素数
  300. int find_consensus( vector<KeyPoint> kpts, vector<KeyPoint> mkpts, vector<DMatch> uFMaches, int n, Mat M, int err_tol, DMatch* consensus)
  301. {
  302.         int num_matches = (int)uFMaches.size();
  303.         int num_consensus=0;
  304.         double err_sqr = pow((float)err_tol, 2);
  305.         for(int i=0; i<num_matches; i++)
  306.         {
  307.                 if(err_fn( kpts[uFMaches[i].queryIdx], mkpts[uFMaches[i].trainIdx],  M )<err_sqr)
  308.                 {
  309.                         *(consensus + num_consensus)=uFMaches[i];
  310.                         num_consensus++;
  311.                 }
  312.         }
  313.         return num_consensus;

  314. }
复制代码

下载: 代码stitch_sift20200421_vc10.7z (7.94 MB, 下载次数: 7)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表