当前位置:   article > 正文

OpenCV常用图像拼接方法(三):基于特征匹配拼接_opencv 根据匹配特征点判断是左右还是上下拼接

opencv 根据匹配特征点判断是左右还是上下拼接

    OpenCV常用图像拼接方法将分为四个部分与大家共享,这里是第三种方法,欢迎关注后续。

    OpenCV的常用图像拼接方法(三):基于特征匹配的图像拼接,本次介绍SIFT特征匹配拼接方法,OpenCV版本为4.4.0。特点和适用范围:图像有足够重合相同特征区域,且待拼接图像之间无明显尺度变换和畸变。

优点:适应部分倾斜变化情况。缺点:需要有足够的相同特征区域进行匹配,速度较慢,拼接较大图片容易崩溃。

    如下是待拼接的两张图片:

 

特征匹配图:

 拼接结果图:

 拼接缝处理后(拼接处过渡更自然):

核心代码:

  1. /********************直接图像拼接函数*************************/
  2. bool ImageOverlap0(Mat &img1, Mat &img2)
  3. {
  4. Mat g1(img1, Rect(0, 0, img1.cols, img1.rows)); // init roi
  5. Mat g2(img2, Rect(0, 0, img2.cols, img2.rows));
  6. cvtColor(g1, g1, COLOR_BGR2GRAY);
  7. cvtColor(g2, g2, COLOR_BGR2GRAY);
  8. vector<cv::KeyPoint> keypoints_roi, keypoints_img; /* keypoints found using SIFT */
  9. Mat descriptor_roi, descriptor_img; /* Descriptors for SIFT */
  10. FlannBasedMatcher matcher; /* FLANN based matcher to match keypoints */
  11. vector<cv::DMatch> matches, good_matches;
  12. cv::Ptr<cv::SIFT> sift = cv::SIFT::create();
  13. int i, dist = 80;
  14. sift->detectAndCompute(g1, cv::Mat(), keypoints_roi, descriptor_roi); /* get keypoints of ROI image */
  15. sift->detectAndCompute(g2, cv::Mat(), keypoints_img, descriptor_img); /* get keypoints of the image */
  16. matcher.match(descriptor_roi, descriptor_img, matches); //实现描述符之间的匹配
  17. double max_dist = 0; double min_dist = 5000;
  18. //-- Quick calculation of max and min distances between keypoints
  19. for (int i = 0; i < descriptor_roi.rows; i++)
  20. {
  21. double dist = matches[i].distance;
  22. if (dist < min_dist) min_dist = dist;
  23. if (dist > max_dist) max_dist = dist;
  24. }
  25. // 特征点筛选
  26. for (i = 0; i < descriptor_roi.rows; i++)
  27. {
  28. if (matches[i].distance < 3 * min_dist)
  29. {
  30. good_matches.push_back(matches[i]);
  31. }
  32. }
  33. printf("%ld no. of matched keypoints in right image\n", good_matches.size());
  34. /* Draw matched keypoints */
  35. Mat img_matches;
  36. //绘制匹配
  37. drawMatches(img1, keypoints_roi, img2, keypoints_img,
  38. good_matches, img_matches, Scalar::all(-1),
  39. Scalar::all(-1), vector<char>(),
  40. DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
  41. imshow("matches", img_matches);
  42. vector<Point2f> keypoints1, keypoints2;
  43. for (i = 0; i < good_matches.size(); i++)
  44. {
  45. keypoints1.push_back(keypoints_img[good_matches[i].trainIdx].pt);
  46. keypoints2.push_back(keypoints_roi[good_matches[i].queryIdx].pt);
  47. }
  48. //计算单应矩阵(仿射变换矩阵)
  49. Mat H = findHomography(keypoints1, keypoints2, RANSAC);
  50. Mat H2 = findHomography(keypoints2, keypoints1, RANSAC);
  51. Mat stitchedImage; //定义仿射变换后的图像(也是拼接结果图像)
  52. Mat stitchedImage2; //定义仿射变换后的图像(也是拼接结果图像)
  53. int mRows = img2.rows;
  54. if (img1.rows > img2.rows)
  55. {
  56. mRows = img1.rows;
  57. }
  58. int count = 0;
  59. for (int i = 0; i < keypoints2.size(); i++)
  60. {
  61. if (keypoints2[i].x >= img2.cols / 2)
  62. count++;
  63. }
  64. //判断匹配点位置来决定图片是左还是右
  65. if (count / float(keypoints2.size()) >= 0.5) //待拼接img2图像在右边
  66. {
  67. cout << "img1 should be left" << endl;
  68. vector<Point2f>corners(4);
  69. vector<Point2f>corners2(4);
  70. corners[0] = Point(0, 0);
  71. corners[1] = Point(0, img2.rows);
  72. corners[2] = Point(img2.cols, img2.rows);
  73. corners[3] = Point(img2.cols, 0);
  74. stitchedImage = Mat::zeros(img2.cols + img1.cols, mRows, CV_8UC3);
  75. warpPerspective(img2, stitchedImage, H, Size(img2.cols + img1.cols, mRows));
  76. perspectiveTransform(corners, corners2, H);
  77. /*
  78. circle(stitchedImage, corners2[0], 5, Scalar(0, 255, 0), 2, 8);
  79. circle(stitchedImage, corners2[1], 5, Scalar(0, 255, 255), 2, 8);
  80. circle(stitchedImage, corners2[2], 5, Scalar(0, 255, 0), 2, 8);
  81. circle(stitchedImage, corners2[3], 5, Scalar(0, 255, 0), 2, 8); */
  82. cout << corners2[0].x << ", " << corners2[0].y << endl;
  83. cout << corners2[1].x << ", " << corners2[1].y << endl;
  84. imshow("temp", stitchedImage);
  85. //imwrite("temp.jpg", stitchedImage);
  86. Mat half(stitchedImage, Rect(0, 0, img1.cols, img1.rows));
  87. img1.copyTo(half);
  88. imshow("result", stitchedImage);
  89. }
  90. else //待拼接图像img2在左边
  91. {
  92. cout << "img2 should be left" << endl;
  93. stitchedImage = Mat::zeros(img2.cols + img1.cols, mRows, CV_8UC3);
  94. warpPerspective(img1, stitchedImage, H2, Size(img1.cols + img2.cols, mRows));
  95. imshow("temp", stitchedImage);
  96. //计算仿射变换后的四个端点
  97. vector<Point2f>corners(4);
  98. vector<Point2f>corners2(4);
  99. corners[0] = Point(0, 0);
  100. corners[1] = Point(0, img1.rows);
  101. corners[2] = Point(img1.cols, img1.rows);
  102. corners[3] = Point(img1.cols, 0);
  103. perspectiveTransform(corners, corners2, H2); //仿射变换对应端点
  104. /*
  105. circle(stitchedImage, corners2[0], 5, Scalar(0, 255, 0), 2, 8);
  106. circle(stitchedImage, corners2[1], 5, Scalar(0, 255, 255), 2, 8);
  107. circle(stitchedImage, corners2[2], 5, Scalar(0, 255, 0), 2, 8);
  108. circle(stitchedImage, corners2[3], 5, Scalar(0, 255, 0), 2, 8); */
  109. cout << corners2[0].x << ", " << corners2[0].y << endl;
  110. cout << corners2[1].x << ", " << corners2[1].y << endl;
  111. Mat half(stitchedImage, Rect(0, 0, img2.cols, img2.rows));
  112. img2.copyTo(half);
  113. imshow("result", stitchedImage);
  114. }
  115. imwrite("result.bmp", stitchedImage);
  116. return true;
  117. }

 拼接缝优化代码与完整源码素材将发布在知识星球主题中。

 公众号:OpenCV与AI深度学习

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/81402
推荐阅读
相关标签
  

闽ICP备14008679号