cvutils.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include <iostream>
  2. #ifdef HAS_OPENCV3
  3. #include <opencv2/core.hpp> //Any OPENCV3 code
  4. #else
  5. #include <opencv2/core/core.hpp> //Any Opencv2 code
  6. #endif
  7. #include "geometry.h"
  8. #include "cvutils.h"
  9. #define likely(x) __builtin_expect(!!(x), 1)
  10. #define unlikely(x) __builtin_expect(!!(x), 0)
  11. // takes the two points that are more distant from the next, ie:
  12. // i st distance(hull[i], hull[i+1]) is maximum and 2nd maximum
  13. unsigned* max2_distance(std::vector<cv::Point> hull)
  14. {
  15. #ifdef _DEBUG
  16. std::cout << "Hull = ";
  17. for(auto p: hull) {
  18. std::cout << p << " ";
  19. }
  20. std::cout << std::endl;
  21. #endif
  22. unsigned *idx = (unsigned*) calloc(2, sizeof(int));
  23. double distance[2] = {0};
  24. for( unsigned i=0; hull.size()>i; i++ )
  25. {
  26. cv::Point thispoint=hull[i];
  27. cv::Point nextpoint=hull[(i+1)%hull.size()];
  28. double d=dist(thispoint,nextpoint);
  29. if( d>distance[0] ) //the biggest till now
  30. {
  31. idx[1]=idx[0];
  32. idx[0]=i;
  33. distance[1]=distance[0];
  34. distance[0]=d;
  35. }
  36. else if( d>distance[1] ) // it is the second biggest till now
  37. {
  38. idx[1]=i;
  39. distance[1]=d;
  40. }
  41. }
  42. return idx;
  43. }
  44. /* check if a,b,newpoint belong to the same line (with minor approximation) */
  45. bool similar_fit(cv::Point a, cv::Point b, cv::Point newpoint) {
  46. return similar_fit(a, b, newpoint, 5);
  47. }
  48. bool similar_fit(cv::Point a, cv::Point b, cv::Point newpoint, float tolerance_degrees) {
  49. double angle = inner_angle(a, b, newpoint) * 180 / M_PI;
  50. if( angle > (180-tolerance_degrees) && angle < (180+tolerance_degrees) ) {
  51. return true;
  52. }
  53. return false;
  54. }
  55. bool similar_fit(std::vector<cv::Point> group, cv::Point newpoint) {
  56. // TODO: it should perform a fit instead of just taking first and last
  57. assert(group.size()>=2);
  58. return similar_fit(group[0], group[group.size()-1], newpoint);
  59. }
  60. /* simplify_hull will group all the points of the hull in groups that fit
  61. * each group is a "line"
  62. */
  63. std::vector<std::vector<cv::Point>>
  64. simplify_hull(std::vector<cv::Point> hull) {
  65. return simplify_hull( hull, 0 );
  66. }
  67. std::vector<std::vector<cv::Point>>
  68. simplify_hull(std::vector<cv::Point> hull, double mindistance) {
  69. //each element is a group of point; a group of point is a vector of points that were
  70. //contigous and that "fit together"
  71. std::vector<std::vector<cv::Point>> pointgroups;
  72. std::vector<cv::Point> *group = new std::vector<cv::Point>();
  73. cv::Point last, current;
  74. group->push_back(hull[0]);
  75. group->push_back(hull[1]);
  76. for( unsigned i=2; hull.size()>i; i++ )
  77. {
  78. current = hull[i];
  79. last = (*group)[group->size()-1];
  80. if( similar_fit((*group)[0], last, hull[i]) )
  81. {
  82. group->push_back( hull[i] );
  83. }
  84. else
  85. {
  86. if( dist((*group)[0],last)>=mindistance )
  87. pointgroups.push_back(*group);
  88. group = new std::vector<cv::Point>();
  89. group->push_back(last);
  90. group->push_back(hull[i]);
  91. }
  92. }
  93. pointgroups.push_back(*group);
  94. //TODO: first and last might just be the same
  95. return pointgroups;
  96. }
  97. /* find_longest_line: walks along the hull starting at "begin" and ending at "end", and find the
  98. * longest (well, not strictl: it's a very simple eurhistics) group of points
  99. * that are aligned we don't care about the number of points, but about the
  100. * euclidean distance between the first and the last
  101. * arg hull: the whole convex hull
  102. * arg begin: index of the array to start from
  103. * arg end: index of the array to end. It can be lower than start, in which case the hull is used
  104. * "circularly"
  105. * returns: a vector of useful points. Just use the first and the last, do not expect that the points in
  106. * between are added to the vector
  107. */
  108. std::vector<cv::Point> //two points, actually
  109. find_longest_line(std::vector<cv::Point> hull, unsigned begin, unsigned end) //the hull can be open
  110. {
  111. std::vector<cv::Point> bestline, thisline;
  112. int bestdistance = 0;
  113. thisline.push_back(hull[(begin)%hull.size()]);
  114. thisline.push_back(hull[(begin+1)%hull.size()]);
  115. for(unsigned i=(begin+2)%hull.size(); i!=end; i++)
  116. {
  117. assert(2<=thisline.size());
  118. if(i==hull.size()) {
  119. i=0;
  120. }
  121. assert(i < hull.size());
  122. if(similar_fit(thisline, hull[i])) {
  123. thisline.push_back(hull[i]);
  124. } else { // considering if the just-finished line is the best
  125. double thisdistance = dist(thisline[0],thisline[thisline.size()-1]);
  126. if(thisdistance>bestdistance) {
  127. bestline = thisline;
  128. bestdistance = thisdistance;
  129. }
  130. thisline.clear();
  131. assert(bestline.size()>=2);
  132. thisline.push_back(hull[(i-1)%hull.size()]);
  133. thisline.push_back(hull[i]);
  134. };
  135. }
  136. double thisdistance = dist(thisline[0],thisline[thisline.size()-1]);
  137. if(thisdistance>bestdistance) { // this is relevant if the best line ends at the last point
  138. bestline = thisline;
  139. bestdistance = thisdistance;
  140. }
  141. assert(bestline.size()>=2);
  142. return bestline;
  143. }