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.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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 angle = 0;
  70. int index;
  71. if(turnLeft){
  72. // get the most left/right contour
  73. int leftmostEdge = imageColums;
  74. for (int i = 0; i < data.leftEdges.size(); i++)
  75. {
  76. int edge = data.leftEdges[i].x;
  77. if (edge <= leftmostEdge)
  78. {
  79. leftmostEdge = edge;
  80. index = i;
  81. }
  82. }
  83. }else
  84. {
  85. int rightmostEdge = 0;
  86. for (int i = 0; i < data.leftEdges.size(); i++)
  87. {
  88. int edge = data.leftEdges[i].x;
  89. if (edge >= rightmostEdge)
  90. {
  91. rightmostEdge = edge;
  92. index = i;
  93. }
  94. }
  95. }
  96. // Find the Top-Left and Buttom-Left Point of the Contour
  97. std::vector<cv::Point> leftMostContour = data.contours[index];
  98. int xleftButtom = imageColums;
  99. int xleftTop = imageColums;
  100. int yButtom = data.boundingBoxes[index].y;
  101. int yTop = data.boundingBoxes[index].height;
  102. for (int i = 0; i < leftMostContour.size(); i++){
  103. if(leftMostContour[i].y == 0 && leftMostContour[i].x < xleftButtom)
  104. {
  105. xleftButtom = leftMostContour[i].x;
  106. }else if(leftMostContour[i].y > yTop -4 && leftMostContour[i].x < xleftTop){
  107. xleftTop = leftMostContour[i].x;
  108. }
  109. }
  110. // calculate angle
  111. int deltaX = abs(xleftButtom - xleftTop);
  112. int deltaY = yTop;
  113. angle = Calcs::calcAngle(deltaX, deltaY);
  114. //Write to Data
  115. data.angle = angle;
  116. data.index = index;
  117. }
  118. }
  119. void Processing::processImage(Mat& inputPicture, int thresholdBinary, int gaussKernelSize)
  120. {
  121. //Idea here is: Processing module consists of two methods:
  122. // One (this) to do all kinds of stuff to the picture (grayscale conversion, threshold, gauss etc etc)
  123. // And one (the other one) to segment the lines.
  124. // No return value here as the input is passed by reference -> directly modified.
  125. cvtColor(inputPicture, inputPicture, COLOR_BGR2GRAY);
  126. GaussianBlur(inputPicture, inputPicture, Size(gaussKernelSize, gaussKernelSize), 0);
  127. threshold(inputPicture, inputPicture, thresholdBinary, 255, THRESH_BINARY);
  128. //Perform an opening
  129. Mat kernel(5,5, CV_8UC1,1);
  130. morphologyEx(inputPicture, inputPicture, 2, kernel);
  131. }
  132. FrameData Processing::calculateLineSegments(Mat& inputPicture, const cv::Rect& roi)
  133. {
  134. FrameData data;
  135. Mat inputPictureRoi = inputPicture(roi);
  136. cv::findContours(inputPictureRoi, data.contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
  137. vector<Vec4i> lines;
  138. std::vector<std::vector<Point>> houghLines;
  139. Canny(inputPicture, inputPicture, 50, 100, 3);
  140. HoughLinesP(inputPicture, lines, 1, CV_PI/180, 100, 30, 150);
  141. //Draw lines
  142. inputPicture = Mat::zeros(inputPicture.size().height, inputPicture.size().width, CV_8UC1);
  143. for( size_t i = 0; i < lines.size(); i++ )
  144. {
  145. line( inputPicture, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(255,255,255), 3, 8 );
  146. std::vector<Point> line;
  147. line.push_back(Point(lines[i][0], lines[i][1]));
  148. line.push_back(Point(lines[i][2], lines[i][3]));
  149. houghLines.push_back(line);
  150. }
  151. //Delete the areas that are too small
  152. auto iterator = data.contours.begin();
  153. while(iterator != data.contours.end())
  154. {
  155. if (contourArea(*iterator) < 7000)
  156. {
  157. iterator = data.contours.erase(iterator);
  158. }
  159. else if (!checkIntersection(houghLines, *iterator))
  160. {
  161. iterator = data.contours.erase(iterator);
  162. }
  163. else
  164. {
  165. //Check for intersection with lines:
  166. Rect boundingBox = boundingRect(*iterator);
  167. boundingBox.x += roi.x;
  168. boundingBox.y += roi.y;
  169. data.boundingBoxes.push_back(boundingBox);
  170. data.middlePoints.push_back(Point(boundingBox.x+boundingBox.width/2, boundingBox.y+boundingBox.height/2));
  171. data.leftEdges.push_back(Point(boundingBox.x, boundingBox.y+boundingBox.height/2));
  172. ++iterator;
  173. }
  174. }
  175. return data;
  176. }