Projektarbeit Line Following Robot bei Prof. Chowanetz im WS22/23
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

processing.cpp 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include "processing.h"
  2. Processing::Processing(/* args */)
  3. {
  4. }
  5. Processing::~Processing()
  6. {
  7. }
  8. void Processing::filterReflections(FrameData& frameData)
  9. {
  10. //Try to filter reflections from the frame data.
  11. std::vector<int> indicesToDelete;
  12. for(int i = 0; i < frameData.contours.size(); i++)
  13. {
  14. // First approach: correct contours nearly fill their bounding box.
  15. // So delete all contours with an area smaller than 75% of their bounding box
  16. double contourArea = cv::contourArea(frameData.contours[i], false);
  17. double boundingBoxArea = double(frameData.boundingBoxes[i].width*frameData.boundingBoxes[i].height);
  18. double minRatio = 0.75;
  19. if(boundingBoxArea/contourArea < minRatio)
  20. {
  21. indicesToDelete.push_back(i);
  22. continue;
  23. }
  24. // Second approach: The contour should be nearly convex
  25. // So delete all contours with an area smaller than 95% of their convex hull.
  26. std::vector<Point> hull;
  27. cv::convexHull(frameData.contours[i], hull);
  28. double hullArea = cv::contourArea(hull, false);
  29. double minRatioHull = 0.95;
  30. if(contourArea/boundingBoxArea < minRatio)
  31. {
  32. indicesToDelete.push_back(i);
  33. continue;
  34. }
  35. }
  36. //reverse the vector with the indices so the order isn't messed up when deleting:
  37. std::reverse(indicesToDelete.begin(), indicesToDelete.end());
  38. for(int index : indicesToDelete)
  39. {
  40. frameData.boundingBoxes.erase(frameData.boundingBoxes.begin() + index);
  41. frameData.contours.erase(frameData.contours.begin() + index);
  42. frameData.leftEdges.erase(frameData.leftEdges.begin() + index);
  43. frameData.middlePoints.erase(frameData.middlePoints.begin() + index);
  44. }
  45. return;
  46. }
  47. bool Processing::checkIntersection(const std::vector<std::vector<Point>>& lines, const std::vector<Point>& outline)
  48. {
  49. /* TODO:
  50. * Was ich mir hier vorstelle:
  51. * Wir haben die konturen und die hough linien
  52. * Konturen haben schwäche mit Reflektionen, hough linien sind unvollständig.
  53. * Irgendwie sollten die beiden Datensätze gemerged werden, um das "gute" aus beiden zu vereinen.
  54. * Evtl in richtung "Schau den Bereich der Contour (+ Toleranz?) im hough bild an. Wenn keine Linie im Bereich ist, ist die Contour eine Reflektion"
  55. *
  56. * Aktuell nehmen wir die abkürzung, die segmente rauszuwerfen, sobald keine Linie im Bild ist.
  57. * Funktioniert für unsere Daten auch ziemlich gut
  58. */
  59. if(lines.size() == 0)
  60. {
  61. return false;
  62. }
  63. return true;
  64. }
  65. void Processing::calcAngles(FrameData &data, int imageColums, int imageRows, bool turnLeft)
  66. {
  67. if(data.contours.size() > 0)
  68. {
  69. int index;
  70. // get the most left/right contour
  71. int leftmostEdge = imageColums;
  72. int rightmostEdge = 0;
  73. for (int i = 0; i < data.leftEdges.size(); i++)
  74. {
  75. int edge = data.leftEdges[i].x;
  76. if (edge <= leftmostEdge && turnLeft)
  77. {
  78. leftmostEdge = edge;
  79. index = i;
  80. }
  81. else if(edge >= rightmostEdge && !turnLeft)
  82. {
  83. rightmostEdge = edge;
  84. index = i;
  85. }
  86. }
  87. // Find the Top-Left and Bottom-Left Point of the Contour
  88. std::vector<cv::Point> leftMostContour = data.contours[index];
  89. /*
  90. Not going to dive into that part to fix it.
  91. Trying to use centroid instead.
  92. int xleftBottom = imageColums;
  93. int xleftTop = imageColums;
  94. int yBottom = data.boundingBoxes[index].y;
  95. int yTop = data.boundingBoxes[index].height;
  96. for (int i = 0; i < leftMostContour.size(); i++)
  97. {
  98. if(leftMostContour[i].y == 0 && leftMostContour[i].x < xleftBottom)
  99. {
  100. xleftBottom = leftMostContour[i].x;
  101. }
  102. else if(leftMostContour[i].y > yTop -4 && leftMostContour[i].x < xleftTop)
  103. {
  104. xleftTop = leftMostContour[i].x;
  105. }
  106. }
  107. // calculate angle
  108. int deltaX = abs(xleftBottom - xleftTop);
  109. int deltaY = yTop;
  110. angle = Calcs::calcAngle(deltaX, deltaY);
  111. */
  112. //Get the contours center using moments:
  113. cv::Moments moments=cv::moments(leftMostContour);
  114. LFRPoint contourCenter(moments.m10/moments.m00, moments.m01/moments.m00);
  115. LFRPoint imageCenter(double(imageColums)/2.0, double(imageRows)/2.0);
  116. LFRPoint focusPoint(imageCenter.x, imageCenter.y+1000.0);
  117. LFRVector a(imageCenter-focusPoint);
  118. LFRVector b(contourCenter-focusPoint);
  119. double angle = a.angle(b);
  120. if (b.x < 0.0)
  121. {
  122. angle *= -1.0;
  123. }
  124. //Write to Data
  125. data.angle = angle;
  126. data.index = index;
  127. }
  128. }
  129. void Processing::processImage(Mat& inputPicture, int thresholdBinary, int gaussKernelSize)
  130. {
  131. //Idea here is: Processing module consists of two methods:
  132. // One (this) to do all kinds of stuff to the picture (grayscale conversion, threshold, gauss etc etc)
  133. // And one (the other one) to segment the lines.
  134. // No return value here as the input is passed by reference -> directly modified.
  135. cvtColor(inputPicture, inputPicture, COLOR_BGR2GRAY);
  136. GaussianBlur(inputPicture, inputPicture, Size(gaussKernelSize, gaussKernelSize), 0);
  137. threshold(inputPicture, inputPicture, thresholdBinary, 255, THRESH_BINARY);
  138. //Perform an opening
  139. Mat kernel(5,5, CV_8UC1,1);
  140. morphologyEx(inputPicture, inputPicture, 2, kernel);
  141. }
  142. FrameData Processing::calculateLineSegments(Mat& inputPicture, const cv::Rect& roi)
  143. {
  144. FrameData data;
  145. Mat inputPictureRoi = inputPicture(roi);
  146. cv::findContours(inputPictureRoi, data.contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
  147. vector<Vec4i> lines;
  148. std::vector<std::vector<Point>> houghLines;
  149. Canny(inputPicture, inputPicture, 50, 100, 3);
  150. HoughLinesP(inputPicture, lines, 1, CV_PI/180, 100, 30, 150);
  151. //Draw lines
  152. inputPicture = Mat::zeros(inputPicture.size().height, inputPicture.size().width, CV_8UC1);
  153. for( size_t i = 0; i < lines.size(); i++ )
  154. {
  155. line( inputPicture, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(255,255,255), 3, 8 );
  156. std::vector<Point> line;
  157. line.push_back(Point(lines[i][0], lines[i][1]));
  158. line.push_back(Point(lines[i][2], lines[i][3]));
  159. houghLines.push_back(line);
  160. }
  161. //Delete the areas that are too small
  162. auto iterator = data.contours.begin();
  163. while(iterator != data.contours.end())
  164. {
  165. if (contourArea(*iterator) < 7000)
  166. {
  167. iterator = data.contours.erase(iterator);
  168. }
  169. else if (!checkIntersection(houghLines, *iterator))
  170. {
  171. iterator = data.contours.erase(iterator);
  172. }
  173. else
  174. {
  175. //Check for intersection with lines:
  176. Rect boundingBox = boundingRect(*iterator);
  177. boundingBox.x += roi.x;
  178. boundingBox.y += roi.y;
  179. data.boundingBoxes.push_back(boundingBox);
  180. data.middlePoints.push_back(Point(boundingBox.x+boundingBox.width/2, boundingBox.y+boundingBox.height/2));
  181. data.leftEdges.push_back(Point(boundingBox.x, boundingBox.y+boundingBox.height/2));
  182. ++iterator;
  183. }
  184. }
  185. return data;
  186. }