lines.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #include<cmath>
  2. #include<algorithm>
  3. #ifdef HAS_OPENCV3
  4. #include <opencv2/core.hpp> //Any OPENCV3 code
  5. #else
  6. #include <opencv2/core/core.hpp> //Any Opencv2 code
  7. #endif
  8. #include"lines.h"
  9. #include "geometry.h"
  10. #include "cvutils.h"
  11. using namespace cv;
  12. #define likely(x) __builtin_expect(!!(x), 1)
  13. #define unlikely(x) __builtin_expect(!!(x), 0)
  14. // all those colors are still visible on b/w (the first component is not so low)
  15. auto WHITE = cv::Scalar(255,255,255);
  16. auto BLUE = cv::Scalar(200,50,50);
  17. auto MAGENTA = cv::Scalar(110,10,200);
  18. auto BROWN = cv::Scalar(90,100,60);
  19. auto BLACK = cv::Scalar(0,0,0);
  20. auto YELLOW = cv::Scalar(20,200,200);
  21. int main(int argc, char *argv[])
  22. {
  23. char const *fname = "files/masckera.png";
  24. if( 1<argc )
  25. fname = argv[1];
  26. if( 2<argc) {
  27. std::cerr << "Too many arguments" << std::endl;
  28. return EXIT_FAILURE;
  29. }
  30. cv::Mat img;
  31. img=cv::imread(fname,CV_LOAD_IMAGE_GRAYSCALE);
  32. if( img.empty() ) {
  33. std::cerr << "Error opening image, aborting" << std::endl;
  34. return EXIT_FAILURE;
  35. }
  36. std::vector< std::vector<cv::Point> > contours;
  37. std::vector<cv::Vec4i> hierarchy;
  38. cv::findContours(img,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
  39. unsigned short dotwidth = img.cols >> 6; // divide by 64, so efficient
  40. cv::drawContours(img,contours,-1,BROWN,dotwidth>>4);
  41. if( 0==contours.size() ) {
  42. std::cerr << "No contours found" << std::endl;
  43. return EXIT_FAILURE;
  44. }
  45. auto contour = contours[0];
  46. if( 1!=contours.size() )
  47. {
  48. // choosing the biggest contour in the image
  49. // you can test it with files/2contours.png
  50. for(auto cont: contours) {
  51. if(cont.size() > contour.size())
  52. contour = cont;
  53. }
  54. }
  55. std::vector<cv::Point> hull;
  56. cv::convexHull(cv::Mat(contour),hull,false);
  57. //these are the "horizontal" lines
  58. unsigned *maxdistances = max2_distance(hull);
  59. cv::Point corn_1, corn_2, corn_3, corn_4;
  60. corn_1 = hull[maxdistances[0]];
  61. corn_2 = hull[(maxdistances[0]+1)%hull.size()];
  62. corn_3 = hull[maxdistances[1]];
  63. corn_4 = hull[(maxdistances[1]+1)%hull.size()];
  64. #ifdef _DEBUG
  65. img = cv::imread(fname,CV_LOAD_IMAGE_COLOR); // uncomment to this to display image with colors
  66. std::cout << "Maxdist1:" << maxdistances[0] << " " << corn_1 << corn_2 << std::endl;
  67. std::cout << "Maxdist2:" << maxdistances[1] << " " << corn_3 << corn_4 << std::endl;
  68. cv::namedWindow("win", CV_GUI_NORMAL);
  69. // cv::imshow("4 corners",img);
  70. // cv::waitKey(0);
  71. #endif
  72. std::vector<std::vector<cv::Point>> verticals;
  73. verticals.push_back(find_longest_line(hull, (maxdistances[0]+1)%hull.size(), maxdistances[1]));
  74. std::cout << maxdistances[1] << std::endl;
  75. std::cout << maxdistances[1]+1 << std::endl;
  76. std::cout << (maxdistances[1]+1)%hull.size() << std::endl;
  77. verticals.push_back(find_longest_line(hull, (maxdistances[1]+1)%hull.size(), maxdistances[0]));
  78. free(maxdistances);
  79. // theta is the angle of the line connecting point 1 and 2; it will be the
  80. // rotation of our new coordinate system
  81. auto cs = CoordinateSystem(corn_1, corn_2);
  82. assert(cs.map(corn_1).x == 0);
  83. assert(cs.map(corn_1).y == 0);
  84. assert(cs.map(corn_2).x > 0);
  85. assert(cs.map(corn_2).y == 0);
  86. cv::Vec<double,3> diag1, diag2;
  87. diag1 = get_line(cs.map(corn_1), cs.map(corn_3));
  88. diag2 = get_line(cs.map(corn_4), cs.map(corn_2));
  89. std::cout << "mapped diag1: " << diag1 << std::endl;
  90. std::cout << "mapped diag2: " << diag2 << std::endl;
  91. std::vector<cv::Point> points1, points2;
  92. for(cv::Point p: contour)
  93. { // the point is interesting where it is above both lines or below both lines
  94. cv::Point mapped = cs.map(p);
  95. if(is_above_line(diag1, mapped)) {
  96. if(is_above_line(diag2, mapped)) {
  97. points1.push_back(p);
  98. }
  99. } else {
  100. if(!is_above_line(diag2, mapped)) {
  101. points2.push_back(p);
  102. }
  103. }
  104. }
  105. #ifdef _DEBUG
  106. cv::Point middle1 = further_point_from_line(get_line(corn_1, corn_2), points2);
  107. cv::Point middle2 = further_point_from_line(get_line(corn_3, corn_4), points1);
  108. cv::line(img, corn_1, middle1, MAGENTA, dotwidth>>3);
  109. cv::line(img, corn_2, middle1, MAGENTA, dotwidth>>3);
  110. cv::line(img, middle1, middle2, BLACK, dotwidth>>4);
  111. cv::line(img, corn_3, middle2, MAGENTA, dotwidth>>3);
  112. cv::line(img, corn_4, middle2, MAGENTA, dotwidth>>3);
  113. cv::line(img, corn_2, corn_3, BLUE, dotwidth>>4);
  114. cv::line(img, corn_1, corn_4, BLUE, dotwidth>>4);
  115. std::cout << middle1 << middle2 << std::endl;
  116. cv::imshow("win",img);
  117. while(1)
  118. {
  119. if( (char)cv::waitKey(0) == 113 )
  120. break;
  121. }
  122. img.release();
  123. #endif
  124. return EXIT_SUCCESS;
  125. }
  126. // vim: set noet ts=4 sw=4: