epipolar_lines.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html
  4. #include "opencv2/calib3d.hpp"
  5. #include "opencv2/highgui.hpp"
  6. #include "opencv2/imgproc.hpp"
  7. #include <vector>
  8. #include <iostream>
  9. using namespace cv;
  10. int main(int args, char** argv) {
  11. std::string img_name1, img_name2;
  12. if (args < 3) {
  13. CV_Error(Error::StsBadArg,
  14. "Path to two images \nFor example: "
  15. "./epipolar_lines img1.jpg img2.jpg");
  16. } else {
  17. img_name1 = argv[1];
  18. img_name2 = argv[2];
  19. }
  20. Mat image1 = imread(img_name1);
  21. Mat image2 = imread(img_name2);
  22. Mat descriptors1, descriptors2;
  23. std::vector<KeyPoint> keypoints1, keypoints2;
  24. Ptr<SIFT> detector = SIFT::create();
  25. detector->detect(image1, keypoints1);
  26. detector->detect(image2, keypoints2);
  27. detector->compute(image1, keypoints1, descriptors1);
  28. detector->compute(image2, keypoints2, descriptors2);
  29. FlannBasedMatcher matcher(makePtr<flann::KDTreeIndexParams>(5), makePtr<flann::SearchParams>(32));
  30. // get k=2 best match that we can apply ratio test explained by D.Lowe
  31. std::vector<std::vector<DMatch>> matches_vector;
  32. matcher.knnMatch(descriptors1, descriptors2, matches_vector, 2);
  33. std::vector<Point2d> pts1, pts2;
  34. pts1.reserve(matches_vector.size()); pts2.reserve(matches_vector.size());
  35. for (const auto &m : matches_vector) {
  36. // compare best and second match using Lowe ratio test
  37. if (m[0].distance / m[1].distance < 0.75) {
  38. pts1.emplace_back(keypoints1[m[0].queryIdx].pt);
  39. pts2.emplace_back(keypoints2[m[0].trainIdx].pt);
  40. }
  41. }
  42. std::cout << "Number of points " << pts1.size() << '\n';
  43. Mat inliers;
  44. const auto begin_time = std::chrono::steady_clock::now();
  45. const Mat F = findFundamentalMat(pts1, pts2, RANSAC, 1., 0.99, 2000, inliers);
  46. std::cout << "RANSAC fundamental matrix time " << static_cast<int>(std::chrono::duration_cast<std::chrono::microseconds>
  47. (std::chrono::steady_clock::now() - begin_time).count()) << "\n";
  48. Mat points1 = Mat((int)pts1.size(), 2, CV_64F, pts1.data());
  49. Mat points2 = Mat((int)pts2.size(), 2, CV_64F, pts2.data());
  50. vconcat(points1.t(), Mat::ones(1, points1.rows, points1.type()), points1);
  51. vconcat(points2.t(), Mat::ones(1, points2.rows, points2.type()), points2);
  52. RNG rng;
  53. const int circle_sz = 3, line_sz = 1, max_lines = 300;
  54. std::vector<int> pts_shuffle (points1.cols);
  55. for (int i = 0; i < points1.cols; i++)
  56. pts_shuffle[i] = i;
  57. randShuffle(pts_shuffle);
  58. int plot_lines = 0, num_inliers = 0;
  59. double mean_err = 0;
  60. for (int pt : pts_shuffle) {
  61. if (inliers.at<uchar>(pt)) {
  62. const Scalar col (rng.uniform(0,256), rng.uniform(0,256), rng.uniform(0,256));
  63. const Mat l2 = F * points1.col(pt);
  64. const Mat l1 = F.t() * points2.col(pt);
  65. double a1 = l1.at<double>(0), b1 = l1.at<double>(1), c1 = l1.at<double>(2);
  66. double a2 = l2.at<double>(0), b2 = l2.at<double>(1), c2 = l2.at<double>(2);
  67. const double mag1 = sqrt(a1*a1 + b1*b1), mag2 = (a2*a2 + b2*b2);
  68. a1 /= mag1; b1 /= mag1; c1 /= mag1; a2 /= mag2; b2 /= mag2; c2 /= mag2;
  69. if (plot_lines++ < max_lines) {
  70. line(image1, Point2d(0, -c1/b1),
  71. Point2d((double)image1.cols, -(a1*image1.cols+c1)/b1), col, line_sz);
  72. line(image2, Point2d(0, -c2/b2),
  73. Point2d((double)image2.cols, -(a2*image2.cols+c2)/b2), col, line_sz);
  74. }
  75. circle (image1, pts1[pt], circle_sz, col, -1);
  76. circle (image2, pts2[pt], circle_sz, col, -1);
  77. mean_err += (fabs(points1.col(pt).dot(l2)) / mag2 + fabs(points2.col(pt).dot(l1) / mag1)) / 2;
  78. num_inliers++;
  79. }
  80. }
  81. std::cout << "Mean distance from tentative inliers to epipolar lines " << mean_err/num_inliers
  82. << " number of inliers " << num_inliers << "\n";
  83. // concatenate two images
  84. hconcat(image1, image2, image1);
  85. const int new_img_size = 1200 * 800; // for example
  86. // resize with the same aspect ratio
  87. resize(image1, image1, Size((int) sqrt ((double) image1.cols * new_img_size / image1.rows),
  88. (int)sqrt ((double) image1.rows * new_img_size / image1.cols)));
  89. imshow("epipolar lines, image 1, 2", image1);
  90. imwrite("epipolar_lines.png", image1);
  91. waitKey(0);
  92. }