NimbRo ROS Soccer Package
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
GoalDetector.hpp
1 //GoalDetector.hpp
2 // Created on: May 12, 2015
3 // Author: Hafez Farazi <farazi@ais.uni-bonn.de>
4 #pragma once
5 #include <opencv2/opencv.hpp>
6 #include <math.h>
7 #include <vision_module/Tools/Parameters.hpp>
8 #include <vision_module/Tools/General.hpp>
9 #include <vision_module/Projections/CameraProjections.hpp>
10 #include <vision_module/SoccerObjects/IDetector.hpp>
11 #include <vision_module/Tools/SortFuntions.hpp>
12 #include <vision_module/Tools/LinearBoundaryChecker.hpp>
13 #include <algorithm> // std::sort
14 using namespace cv;
20 class GoalDetector: public IDetector
21 {
22 public:
23 
24  bool GetPosts(Mat& cannyImg, Mat& rawHSV, Mat &gray, const Mat &binaryFrame,
25  CameraProjections &projection, vector<Point> fieldHull,
26  vector<LineSegment> &resLines, vector<LineSegment> &alllLines,
27  vector<Point2f> &goalPosition, bool SHOWGUI, Mat &guiImg)
28  {
29 
30  if (binaryFrame.empty())
31  {
32  return false;
33  }
34  cv::Rect rec;
35  rec.x = 0;
36  rec.y = 0;
37  rec.width = params.camera->width();
38  rec.height = params.camera->height();
39  const int MinLineLength = params.goal->MinLineLength();
40  const int DistanceToMerge = params.goal->DistanceToMerge();
41  const int MaxOutField = params.goal->MaxOutField();
42  const int MinNearFieldUpPoint = -20;
43 
44  vector<cv::Vec4i> linesP;
45 
46  HoughLinesP(cannyImg, linesP, 1, M_PI / 45, 10, MinLineLength, 20);
47  vector<LineSegment> allVerLines;
48  for (size_t i = 0; i < linesP.size(); i++)
49  {
50  cv::Vec4i lP = linesP[i];
51  LineSegment tmpLine(cv::Point2d(lP[0], lP[1]),
52  cv::Point2d(lP[2], lP[3]));
53  double leftAvg = 0;
54  double rightAvg = 0;
55  if (tmpLine.GetAbsMinAngleDegree(
56  LineSegment(cv::Point(0, 0), cv::Point(0, 100))) < 15)
57  {
58  vector<cv::Point2d> midds = tmpLine.GetMidPoints(5);
59  int maxMidPoint = midds.size();
60  int vote_for_doubleLeft = 0;
61  int vote_for_doubleRight = 0;
62 
63  cv::Point down =
64  (tmpLine.P1.y < tmpLine.P2.y) ? tmpLine.P2 : tmpLine.P1;
65  double jumpDouble = params.goal->jumpMax();
66  cv::Point2f downReal;
67  if (!projection.GetOnRealCordinate_single(down, downReal))
68  {
69  ROS_ERROR("Erorr in programming!");
70  return false;
71  }
72  double downDistance2Field = pointPolygonTest(fieldHull, down,
73  true);
74  if (downDistance2Field < MaxOutField)
75  continue;
76  double distance = GetDistance(downReal);
77  if (distance < 2)
78  {
79  jumpDouble = 40;
80  }
81  else if (distance >= 2 && distance < 3)
82  {
83  jumpDouble = 23;
84  }
85  else
86  {
87  jumpDouble = 15;
88  }
89 
90  for (size_t j = 0; j < midds.size(); j++)
91  {
92 
93  LineSegment tocheck = tmpLine.PerpendicularLineSegment(
94  jumpDouble, midds[j]);
95 
96  cv::Point left =
97  (tocheck.P1.x < tocheck.P2.x) ?
98  tocheck.P1 : tocheck.P2;
99  cv::Point right =
100  (tocheck.P1.x < tocheck.P2.x) ?
101  tocheck.P2 : tocheck.P1;
102  cv::LineIterator itLeft(cannyImg, midds[j], left, 8);
103  cv::LineIterator itRight(cannyImg, midds[j], right, 8);
104  cv::LineIterator itHSVLeft(rawHSV, midds[j], left, 8);
105  cv::LineIterator itHSVRight(rawHSV, midds[j], right, 8);
106 
107  int safeToShow = 0;
108  if (tocheck.P1.x >= 0 && tocheck.P1.y >= 0
109  && tocheck.P1.x < params.camera->width()
110  && tocheck.P1.y < params.camera->height())
111  {
112  safeToShow++;
113  }
114  if (tocheck.P2.x >= 0 && tocheck.P2.y >= 0
115  && tocheck.P2.x < params.camera->width()
116  && tocheck.P2.y < params.camera->height())
117  {
118  safeToShow++;
119  }
120 
121 
122  for (int k = 0; k < itLeft.count;
123  k++, ++itLeft, ++itHSVLeft)
124  {
125  if (k < 2)
126  continue;
127  uchar val = *(*itLeft);
128  cv::Vec3b hsvC = (cv::Vec3b) *itHSVLeft;
129 
130  if (val > 0 && k > params.goal->minDoubleLength())
131  {
132  if (safeToShow >= 2 && SHOWGUI
133  && params.goal->showVote())
134  {
135  cv::line(guiImg, midds[j], itHSVLeft.pos(),
136  redColor(), 1);
137  }
138  leftAvg += k;
139  vote_for_doubleLeft++;
140  break;
141  }
142 
143  if (hsvC[0] >= params.goal->h0()
144  && hsvC[0] <= params.goal->h1()
145  && hsvC[1] >= params.goal->s0()
146  && hsvC[1] <= params.goal->s1()
147  && hsvC[2] >= params.goal->v0()
148  && hsvC[2] <= params.goal->v1())
149  {
150 
151  }
152  else
153  {
154  break;
155  }
156  }
157 
158  for (int k = 0; k < itRight.count;
159  k++, ++itRight, ++itHSVRight)
160  {
161  if (k < 2)
162  continue;
163  uchar val = *(*itRight);
164  cv::Vec3b hsvC = (cv::Vec3b) *itHSVRight;
165 
166  if (val > 0 && k > params.goal->minDoubleLength())
167  {
168  if (safeToShow >= 2 && SHOWGUI
169  && params.goal->showVote())
170  {
171  cv::line(guiImg, midds[j], itHSVRight.pos(),
172  redColor(), 1);
173  }
174  rightAvg += k;
175  vote_for_doubleRight++;
176  break;
177  }
178 
179  if (hsvC[0] >= params.goal->h0()
180  && hsvC[0] <= params.goal->h1()
181  && hsvC[1] >= params.goal->s0()
182  && hsvC[1] <= params.goal->s1()
183  && hsvC[2] >= params.goal->v0()
184  && hsvC[2] <= params.goal->v1())
185  {
186 
187  }
188  else
189  {
190  break;
191  }
192  }
193 
194  }
195 
196  bool leftOK = (vote_for_doubleLeft / (float) maxMidPoint) * 100.
197  > params.goal->doubleVote();
198 
199  bool rightOk = (vote_for_doubleRight / (float) maxMidPoint)
200  * 100. > params.goal->doubleVote();
201 
202  if (leftOK || rightOk)
203  {
204  {
205  LineSegment tmpLineChanged = tmpLine;
206 
207  if (leftOK)
208  {
209  int amount = abs(leftAvg / vote_for_doubleLeft)
210  / 2.;
211  tmpLineChanged.P1.x -= amount;
212  tmpLineChanged.P2.x -= amount;
213  }
214  else if (rightOk)
215  {
216  int amount = abs(rightAvg / vote_for_doubleRight)
217  / 2.;
218  tmpLineChanged.P1.x += amount;
219  tmpLineChanged.P2.x += amount;
220  }
221  tmpLineChanged.Clip(rec);
222  allVerLines.push_back(tmpLineChanged);
223  }
224  }
225  }
226  }
227 
228  vector<LineSegment> allVerLines2;
229  MergeLinesMax(allVerLines, 30, DistanceToMerge, allVerLines2, rec);
230 
231  for (size_t i = 0; i < allVerLines2.size(); i++)
232  {
233  LineSegment tmpLine = allVerLines2[i];
234  cv::Point up =
235  (tmpLine.P1.y > tmpLine.P2.y) ? tmpLine.P2 : tmpLine.P1;
236  cv::Point down =
237  (tmpLine.P1.y < tmpLine.P2.y) ? tmpLine.P2 : tmpLine.P1;
238 
239  double verLen = tmpLine.GetLength();
240  if (pointPolygonTest(fieldHull, up, true) > MinNearFieldUpPoint)
241  continue;
242 
243 
244  cv::Point2f downReal;
245  if (!projection.GetOnRealCordinate_single(down, downReal))
246  {
247  ROS_ERROR("Erorr in programming!");
248  return false;
249  }
250 
251  if (!checkDistance_Box(downReal, verLen))
252  continue;
253  double downDistance2Field = pointPolygonTest(fieldHull, down, true);
254  if (downDistance2Field < MaxOutField)
255  continue;
256  if (GetDistance(downReal) > 5)
257  continue;
258  goalPosition.push_back(downReal);
259  resLines.push_back(LineSegment(down, up));
260  }
261 
262  if (SHOWGUI && params.goal->showVote())
263  {
264  for (size_t i = 0; i < allVerLines2.size(); i++)
265  {
266  cv::line(guiImg, allVerLines2[i].P1, allVerLines2[i].P2,
267  blueColor(), 1);
268  }
269  }
270  if (SHOWGUI && params.goal->showResult())
271  {
272  for (size_t i = 0; i < resLines.size(); i++)
273  {
274  cv::line(guiImg, resLines[i].P1, resLines[i].P2, blueColor(),
275  2);
276  }
277  }
278  return resLines.size() > 0;
279  }
280 
281  bool checkDistance_Box(Point2f downPointInReal, double length)
282  {
283 
284  LineSegment lowerBound(
285  Point2f(params.goal->NearestDistance(), params.goal->NearMinLen()),
286  Point2f(params.goal->FarestDistance(), params.goal->FarMinLen()));
287  LineSegment higherBound(
288  Point2f(params.goal->NearestDistance(), params.goal->NearMaxLen()),
289  Point2f(params.goal->FarestDistance(), params.goal->FarMaxLen()));
290  LinearBoundaryChecker checker(lowerBound, higherBound);
291 
292  double distanceToRobot = GetDistance(downPointInReal);
293 
294  return checker.CheckInside(distanceToRobot, length);
295  }
296 
297  inline bool Init()
298  {
299  bool result=true;
300  if(!readFromFile<Point3d>(params.goal->distSizeVecPath, params.goal->distSizeVec))
301  {
302  ROS_ERROR("Create or modify %s!",params.goal->distSizeVecPath.c_str());
303  result=false;
304  }
305  std::sort(params.goal->distSizeVec.begin(),
306  params.goal->distSizeVec.end(), [](const Point3d& a, const Point3d& b)
307  {
308  return a.z < b.z;
309  });
310  return result;
311  }
312 
313 };
For pixel projections.
Definition: CameraProjections.hpp:50
A class representing line segments.
Definition: LineSegment.hpp:17
A class for check if a point is between two given line segments.
Definition: LinearBoundaryChecker.hpp:15
For detecting potential goal posts.
Definition: GoalDetector.hpp:20