当前位置:   article > 正文

opencv ORB特征提取与匹配-实现图像拼接

opencv orb特征提取

本文基于opencv对两张存在交集的图片进行了拼接,这两张图片拍摄角度不同,并且画面存在一定的交集,该功能可以用代码实现两张图片的拼接。通过设计两张特定的拼接掩膜(mask),来过度拼接处的像素突变,拼接效果很好。

步骤如下:

加载图片

  1. Mat room1 = imread("E:\\opencv_tutorial_data-master\\images\\room1 (2).jpg");
  2. Mat room2 = imread("E:\\opencv_tutorial_data-master\\images\\room2 (2).jpg");
  3. //由于手机拍摄的照片像素过大不方便显示,所以对图片进行resize
  4. resize(room1, room1, Size((int)(room1.cols / 2), (int)(room1.rows / 2)), 0.5, 0.5);
  5. resize(room2, room2, Size((int)(room2.cols / 2), (int)(room2.rows / 2)), 0.5, 0.5);
  6. if (room1.empty() == true || room2.empty() == true) {
  7. cout << "error" << endl;
  8. return -1;
  9. }
  10. imshow("room1", room1);
  11. imshow("room2", room2);


room1

 room2

orb特征提取

  1. //创建ORB特征点提取对象,设置提取点数
  2. auto orb = ORB::create(500);
  3. //存放提取的特征点
  4. vector<KeyPoint> kpts_orb_room1;
  5. vector<KeyPoint> kpts_orb_room2;
  6. //存放特征点描述子
  7. Mat dec_orb_room1, dec_orb_room2;
  8. //特征点提取和描述子计算
  9. orb->detectAndCompute(room1, Mat(), kpts_orb_room1, dec_orb_room1);
  10. orb->detectAndCompute(room2, Mat(), kpts_orb_room2, dec_orb_room2);

特征点暴力匹配

  1. //创建暴力匹配子对象
  2. auto bf_matcher = BFMatcher::create(NORM_HAMMING, false);
  3. //存放描述子匹配关系
  4. vector<DMatch> matches_bf;
  5. //特征点描述子匹配
  6. bf_matcher->match(dec_orb_room1, dec_orb_room2, matches_bf);
  7. //特征点筛选
  8. float good_rate = 0.025f;//设置筛选率为0.025
  9. int num_good_matchs = matches_bf.size()*good_rate;
  10. std::sort(matches_bf.begin(), matches_bf.end());
  11. matches_bf.erase(matches_bf.begin() + num_good_matchs, matches_bf.end());
  12. //绘制筛选后匹配结果
  13. Mat result_bf;
  14. drawMatches(room1, kpts_orb_room1, room2, kpts_orb_room2, matches_bf, result_bf);

匹配结果 

生成掩膜

  1. //获取全景图的大小
  2. int mix_high = max(room1.rows,room2.rows);
  3. int mix_widht = room1.cols + room2.cols;
  4. Mat mix_room_01 = Mat::zeros(Size(mix_widht, mix_high),CV_8UC3);
  5. Rect roi;
  6. roi.x = 0;
  7. roi.y = 0;
  8. roi.width = room1.cols;
  9. roi.height = room1.rows;
  10. //获取room2与room1的对齐图像
  11. room1.copyTo(mix_room_01(roi));
  12. imshow("mix_room_01", mix_room_01);
  13. Mat mix_room_02;
  14. warpPerspective(room2, mix_room_02, h,Size(mix_widht, mix_high));
  15. imshow("mix_room2", mix_room_02);
  16. //计算重合区域mask
  17. Mat mask = Mat::zeros(Size(mix_widht, mix_high),CV_8UC1);
  18. generate_mask(mix_room_02,mask);
  19. imshow("mask",mask);
  20. //创建遮罩层并根据mask完成权重初始化
  21. Mat mask1= Mat::ones(Size(mix_widht, mix_high), CV_32FC1);
  22. Mat mask2= Mat::ones(Size(mix_widht, mix_high), CV_32FC1);
  23. //room1 mask1
  24. linesapce(mask1,1,0,room1.cols,mask);
  25. imshow("mask1", mask1);
  26. //room2 mask2
  27. linesapce(mask2, 0, 1, room2.cols, mask);
  28. imshow("mask2", mask2);
  1. void generate_mask(Mat&img, Mat&mask) {
  2. int w = img.cols;
  3. int h = img.rows;
  4. for (int row = 0; row < h;row++) {
  5. for (int col = 0; col < w; col++) {
  6. Vec3b p = img.at<Vec3b>(row,col);
  7. int b = p[0];
  8. int g = p[1];
  9. int r = p[2];
  10. if (b == g && g == r && r == 0) {
  11. mask.at<uchar>(row, col) = 255;
  12. }
  13. }
  14. }
  15. }
  16. void linesapce(Mat&image, float begin, float finish, int w1, Mat&mask) {
  17. int offstx = 0;
  18. float interval = 0;
  19. float delta = 0;
  20. for (int i = 0; i < image.rows; i++) {
  21. offstx = 0;
  22. interval = 0;
  23. delta = 0;
  24. for (int j = 0; j < image.cols; j++) {
  25. int pv = mask.at<uchar>(i, j);
  26. if (pv == 0 && offstx == 0) {
  27. offstx = j;
  28. delta = w1 - offstx;
  29. interval = (finish-begin) / (delta - 1);
  30. image.at<float>(i, j) = begin + (j - offstx)*interval;
  31. }
  32. else if(pv==0&&offstx>0&&(j-offstx)<delta){
  33. image.at<float>(i, j) = begin + (j - offstx)*interval;
  34. }
  35. }
  36. }
  37. }

融合

  1. //左侧融合
  2. Mat m1;
  3. vector<Mat> mv;
  4. mv.push_back(mask1);
  5. mv.push_back(mask1);
  6. mv.push_back(mask1);
  7. merge(mv,m1);
  8. mix_room_01.convertTo(mix_room_01,CV_32F);
  9. multiply(mix_room_01,m1, mix_room_01);
  10. //右侧融合
  11. Mat m2;
  12. mv.clear();
  13. mv.push_back(mask2);
  14. mv.push_back(mask2);
  15. mv.push_back(mask2);
  16. merge(mv, m2);
  17. mix_room_02.convertTo(mix_room_02, CV_32F);
  18. multiply(mix_room_02, m2, mix_room_02);
  19. //合并
  20. Mat mix_room;
  21. add(mix_room_01, mix_room_02, mix_room);
  22. mix_room.convertTo(mix_room,CV_8U);
  23. imshow("mix_room", mix_room);
  24. imshow("result_bf", result_bf);
  25. waitKey(0);
  26. return 0;

 最终效果!!!

 完整代码

  1. #include <iostream>
  2. #include<opencv2\opencv.hpp>
  3. #include<opencv2\xfeatures2d.hpp>
  4. #include<vector>
  5. using namespace std;
  6. using namespace cv;
  7. using namespace xfeatures2d;
  8. void linesapce(Mat&image,float begin,float finish,int w1,Mat&mask);
  9. void generate_mask(Mat&img,Mat&mask);
  10. int main()
  11. {
  12. Mat room1 = imread("E:\\opencv_tutorial_data-master\\images\\room1 (2).jpg");
  13. Mat room2 = imread("E:\\opencv_tutorial_data-master\\images\\room2 (2).jpg");
  14. resize(room1, room1, Size((int)(room1.cols / 2), (int)(room1.rows / 2)), 0.5, 0.5);
  15. resize(room2, room2, Size((int)(room2.cols / 2), (int)(room2.rows / 2)), 0.5, 0.5);
  16. if (room1.empty() == true || room2.empty() == true) {
  17. cout << "error" << endl;
  18. return -1;
  19. }
  20. imshow("room1", room1);
  21. imshow("room2", room2);
  22. //创建ORB特征点提取对象,设置提取点数
  23. auto orb = ORB::create(500);
  24. //存放提取的特征点
  25. vector<KeyPoint> kpts_orb_room1;
  26. vector<KeyPoint> kpts_orb_room2;
  27. //存放特征点描述子
  28. Mat dec_orb_room1, dec_orb_room2;
  29. //特征点提取和描述子计算
  30. orb->detectAndCompute(room1, Mat(), kpts_orb_room1, dec_orb_room1);
  31. orb->detectAndCompute(room2, Mat(), kpts_orb_room2, dec_orb_room2);
  32. /*---------FLANN 匹配-------------*/
  33. /*
  34. if ((dec_orb_book.type() != CV_32F) && (dec_orb_book_in_scene.type() != CV_32F)) {
  35. dec_orb_book.convertTo(dec_orb_book, CV_32F);
  36. dec_orb_book_in_scene.convertTo(dec_orb_book_in_scene, CV_32F);
  37. }
  38. auto flann_matcher = FlannBasedMatcher::create();
  39. vector<DMatch> matches_flann;
  40. flann_matcher->match(dec_orb_book, dec_orb_book_in_scene, matches_flann);
  41. Mat result_flann;
  42. drawMatches(book, kpts_orb_book, book_in_scene, kpts_orb_book_in_scene, matches_flann, result_flann);
  43. imshow("result_flann", result_flann);
  44. */
  45. /*--------------------------------*/
  46. /*---------暴力 匹配-------------*/
  47. //创建暴力匹配子对象
  48. auto bf_matcher = BFMatcher::create(NORM_HAMMING, false);
  49. //存放描述子匹配关系
  50. vector<DMatch> matches_bf;
  51. //特征点描述子匹配
  52. bf_matcher->match(dec_orb_room1, dec_orb_room2, matches_bf);
  53. //特征点筛选
  54. float good_rate = 0.025f;
  55. int num_good_matchs = matches_bf.size()*good_rate;
  56. std::sort(matches_bf.begin(), matches_bf.end());
  57. matches_bf.erase(matches_bf.begin() + num_good_matchs, matches_bf.end());
  58. //绘制筛选后匹配结果
  59. Mat result_bf;
  60. drawMatches(room1, kpts_orb_room1, room2, kpts_orb_room2, matches_bf, result_bf);
  61. //获取两张图的特征点
  62. vector<Point2f>room1_points;
  63. vector<Point2f>room2_points;
  64. for (size_t t = 0; t < matches_bf.size(); t++) {
  65. room1_points.push_back(kpts_orb_room1[matches_bf[t].queryIdx].pt);
  66. room2_points.push_back(kpts_orb_room2[matches_bf[t].trainIdx].pt);
  67. }
  68. //根据对应的特征点获取从demo->scene的变换矩阵
  69. Mat h = findHomography(room2_points, room1_points, RANSAC);
  70. //获取全景图的大小
  71. int mix_high = max(room1.rows,room2.rows);
  72. int mix_widht = room1.cols + room2.cols;
  73. Mat mix_room_01 = Mat::zeros(Size(mix_widht, mix_high),CV_8UC3);
  74. Rect roi;
  75. roi.x = 0;
  76. roi.y = 0;
  77. roi.width = room1.cols;
  78. roi.height = room1.rows;
  79. //获取room2与room1的对齐图像
  80. room1.copyTo(mix_room_01(roi));
  81. imshow("mix_room_01", mix_room_01);
  82. Mat mix_room_02;
  83. warpPerspective(room2, mix_room_02, h,Size(mix_widht, mix_high));
  84. imshow("mix_room2", mix_room_02);
  85. //计算重合区域mask
  86. Mat mask = Mat::zeros(Size(mix_widht, mix_high),CV_8UC1);
  87. generate_mask(mix_room_02,mask);
  88. imshow("mask",mask);
  89. //创建遮罩层并根据mask完成权重初始化
  90. Mat mask1= Mat::ones(Size(mix_widht, mix_high), CV_32FC1);
  91. Mat mask2= Mat::ones(Size(mix_widht, mix_high), CV_32FC1);
  92. //room1 mask1
  93. linesapce(mask1,1,0,room1.cols,mask);
  94. imshow("mask1", mask1);
  95. //room2 mask2
  96. linesapce(mask2, 0, 1, room2.cols, mask);
  97. imshow("mask2", mask2);
  98. //左侧融合
  99. Mat m1;
  100. vector<Mat> mv;
  101. mv.push_back(mask1);
  102. mv.push_back(mask1);
  103. mv.push_back(mask1);
  104. merge(mv,m1);
  105. mix_room_01.convertTo(mix_room_01,CV_32F);
  106. multiply(mix_room_01,m1, mix_room_01);
  107. //右侧融合
  108. Mat m2;
  109. mv.clear();
  110. mv.push_back(mask2);
  111. mv.push_back(mask2);
  112. mv.push_back(mask2);
  113. merge(mv, m2);
  114. mix_room_02.convertTo(mix_room_02, CV_32F);
  115. multiply(mix_room_02, m2, mix_room_02);
  116. //合并
  117. Mat mix_room;
  118. add(mix_room_01, mix_room_02, mix_room);
  119. mix_room.convertTo(mix_room,CV_8U);
  120. imshow("mix_room", mix_room);
  121. imshow("result_bf", result_bf);
  122. waitKey(0);
  123. return 0;
  124. }
  125. void generate_mask(Mat&img, Mat&mask) {
  126. int w = img.cols;
  127. int h = img.rows;
  128. for (int row = 0; row < h;row++) {
  129. for (int col = 0; col < w; col++) {
  130. Vec3b p = img.at<Vec3b>(row,col);
  131. int b = p[0];
  132. int g = p[1];
  133. int r = p[2];
  134. if (b == g && g == r && r == 0) {
  135. mask.at<uchar>(row, col) = 255;
  136. }
  137. }
  138. }
  139. }
  140. void linesapce(Mat&image, float begin, float finish, int w1, Mat&mask) {
  141. int offstx = 0;
  142. float interval = 0;
  143. float delta = 0;
  144. for (int i = 0; i < image.rows; i++) {
  145. offstx = 0;
  146. interval = 0;
  147. delta = 0;
  148. for (int j = 0; j < image.cols; j++) {
  149. int pv = mask.at<uchar>(i, j);
  150. if (pv == 0 && offstx == 0) {
  151. offstx = j;
  152. delta = w1 - offstx;
  153. interval = (finish-begin) / (delta - 1);
  154. image.at<float>(i, j) = begin + (j - offstx)*interval;
  155. }
  156. else if(pv==0&&offstx>0&&(j-offstx)<delta){
  157. image.at<float>(i, j) = begin + (j - offstx)*interval;
  158. }
  159. }
  160. }
  161. }

参考资料:

腾讯课堂贾志刚老师课程

《opencv4入门到精通》

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

闽ICP备14008679号