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 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "processing.h"
  2. Processing::Processing(/* args */)
  3. {
  4. }
  5. Processing::~Processing()
  6. {
  7. }
  8. static double angle( Point pt1, Point pt2, Point pt0 )
  9. {
  10. double dx1 = pt1.x - pt0.x;
  11. double dy1 = pt1.y - pt0.y;
  12. double dx2 = pt2.x - pt0.x;
  13. double dy2 = pt2.y - pt0.y;
  14. return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
  15. }
  16. void Processing::filterReflections(FrameData& frameData)
  17. {
  18. //Try to filter reflections from the frame data.
  19. std::vector<int> indicesToDelete;
  20. for(int i = 0; i < frameData.contours.size(); i++)
  21. {
  22. // First approach: correct contours nearly fill their bounding box.
  23. // So delete all contours with an area smaller than 75% of their bounding box
  24. double contourArea = cv::contourArea(frameData.contours[i], false);
  25. double boundingBoxArea = double(frameData.boundingBoxes[i].width*frameData.boundingBoxes[i].height);
  26. double minRatio = 0.75;
  27. if(boundingBoxArea/contourArea < minRatio)
  28. {
  29. indicesToDelete.push_back(i);
  30. continue;
  31. }
  32. // Second approach: The contour should be nearly convex
  33. // So delete all contours with an area smaller than 95% of their convex hull.
  34. std::vector<Point> hull;
  35. cv::convexHull(frameData.contours[i], hull);
  36. double hullArea = cv::contourArea(hull, false);
  37. double minRatioHull = 0.95;
  38. if(contourArea/boundingBoxArea < minRatio)
  39. {
  40. indicesToDelete.push_back(i);
  41. continue;
  42. }
  43. }
  44. //reverse the vector with the indices so the order isn't messed up when deleting:
  45. std::reverse(indicesToDelete.begin(), indicesToDelete.end());
  46. for(int index : indicesToDelete)
  47. {
  48. frameData.boundingBoxes.erase(frameData.boundingBoxes.begin() + index);
  49. frameData.contours.erase(frameData.contours.begin() + index);
  50. frameData.leftEdges.erase(frameData.leftEdges.begin() + index);
  51. frameData.middlePoints.erase(frameData.middlePoints.begin() + index);
  52. }
  53. return;
  54. }
  55. bool Processing::checkIntersection(const std::vector<std::vector<Point>>& lines, const std::vector<Point>& outline)
  56. {
  57. /* TODO:
  58. * Was ich mir hier vorstelle:
  59. * Wir haben die konturen und die hough linien
  60. * Konturen haben schwäche mit Reflektionen, hough linien sind unvollständig.
  61. * Irgendwie sollten die beiden Datensätze gemerged werden, um das "gute" aus beiden zu vereinen.
  62. * Evtl in richtung "Schau den Bereich der Contour (+ Toleranz?) im hough bild an. Wenn keine Linie im Bereich ist, ist die Contour eine Reflektion"
  63. *
  64. * Aktuell nehmen wir die abkürzung, die segmente rauszuwerfen, sobald keine Linie im Bild ist.
  65. * Funktioniert für unsere Daten auch ziemlich gut
  66. */
  67. if(lines.size() == 0)
  68. {
  69. return false;
  70. }
  71. return true;
  72. }
  73. void Processing::processImage(Mat& inputPicture, int thresholdBinary, int gaussKernelSize)
  74. {
  75. //Idea here is: Processing module consists of two methods:
  76. // One (this) to do all kinds of stuff to the picture (grayscale conversion, threshold, gauss etc etc)
  77. // And one (the other one) to segment the lines.
  78. // No return value here as the input is passed by reference -> directly modified.
  79. cvtColor(inputPicture, inputPicture, COLOR_BGR2GRAY);
  80. GaussianBlur(inputPicture, inputPicture, Size(gaussKernelSize, gaussKernelSize), 0);
  81. threshold(inputPicture, inputPicture, thresholdBinary, 255, THRESH_BINARY);
  82. //Perform an opening
  83. Mat kernel(5,5, CV_8UC1,1);
  84. morphologyEx(inputPicture, inputPicture, 2, kernel);
  85. }
  86. FrameData Processing::calculateLineSegments(Mat& inputPicture, const cv::Rect& roi)
  87. {
  88. FrameData data;
  89. Mat inputPictureRoi = inputPicture(roi);
  90. cv::findContours(inputPictureRoi, data.contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
  91. vector<Vec4i> lines;
  92. std::vector<std::vector<Point>> houghLines;
  93. Canny(inputPicture, inputPicture, 50, 100, 3);
  94. HoughLinesP(inputPicture, lines, 1, CV_PI/180, 100, 30, 150);
  95. //Draw lines
  96. inputPicture = Mat::zeros(inputPicture.size().height, inputPicture.size().width, CV_8UC1);
  97. for( size_t i = 0; i < lines.size(); i++ )
  98. {
  99. line( inputPicture, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(255,255,255), 3, 8 );
  100. std::vector<Point> line;
  101. line.push_back(Point(lines[i][0], lines[i][1]));
  102. line.push_back(Point(lines[i][2], lines[i][3]));
  103. houghLines.push_back(line);
  104. }
  105. //Delete the areas that are too small
  106. auto iterator = data.contours.begin();
  107. while(iterator != data.contours.end())
  108. {
  109. if (contourArea(*iterator) < 3500)
  110. {
  111. iterator = data.contours.erase(iterator);
  112. }
  113. else if (!checkIntersection(houghLines, *iterator))
  114. {
  115. iterator = data.contours.erase(iterator);
  116. }
  117. else
  118. {
  119. //Check for intersection with lines:
  120. Rect boundingBox = boundingRect(*iterator);
  121. boundingBox.x += roi.x;
  122. boundingBox.y += roi.y;
  123. data.boundingBoxes.push_back(boundingBox);
  124. data.middlePoints.push_back(Point(boundingBox.x+boundingBox.width/2, boundingBox.y+boundingBox.height/2));
  125. data.leftEdges.push_back(Point(boundingBox.x, boundingBox.y+boundingBox.height/2));
  126. ++iterator;
  127. }
  128. }
  129. return data;
  130. }