53#include <opencv2/imgproc/imgproc.hpp>
54#include <opencv2/imgproc/imgproc_c.h>
59#define HEADING_DIFFERENCE_PER_PIXEL 27.0/160.0*M_PI/180.0
62#define BEOBOT2_PIXEL_TO_MM_ROAD_BOTTOM_RATIO 9.525
67 static inline bool coordsOk(
int const x,
int const y,
int const w,
int const h)
68 {
return (x >= 0 && x < w && y >= 0 && y <
h); }
78 double denom,numera,numerb;
82 denom = (p4.
j-p3.
j) * (p2.
i-p1.
i) - (p4.
i-p3.
i) * (p2.
j-p1.
j);
83 numera = (p4.
i-p3.
i) * (p1.
j-p3.
j) - (p4.
j-p3.
j) * (p1.
i-p3.
i);
84 numerb = (p2.
i-p1.
i) * (p1.
j-p3.
j) - (p2.
j-p1.
j) * (p1.
i-p3.
i);
87 if (fabs(numera) < EPS && fabs(numerb) < EPS && fabs(denom) < EPS)
89 x = (p1.
i + p2.
i) / 2;
90 y = (p1.
j + p2.
j) / 2;
95 if (fabs(denom) < EPS) {
102 mua = numera / denom;
103 mub = numerb / denom;
104 if (mua < 0 || mua > 1 || mub < 0 || mub > 1) {
109 x = p1.
i + mua * (p2.
i - p1.
i);
110 y = p1.
j + mua * (p2.
j - p1.
j);
122 T Ax = pt1.
i; T Ay = pt1.
j;
123 T Bx = pt2.
i; T By = pt2.
j;
128 return (Bx-Ax)*(j-Ay) - (By-Ay)*(i-Ax);
144 double xi;
double yi;
146 if (x1 == x2){ xi = x1; yi = y3; }
147 else if(y1 == y2){ xi = x3; yi = y1; }
150 double x2m1 = x2 - x1;
151 double y2m1 = y2 - y1;
153 double x3m1 = x3 - x1;
154 double y3m1 = y3 - y1;
156 double distSq = x2m1*x2m1+y2m1*y2m1;
157 double u = (x3m1*x2m1 + y3m1*y2m1)/distSq;
167 return pow(dx*dx+dy*dy, .5F);
175 return distance(pt1, pt2, pt, midPt);
182 jevois::Component(instance), itsTPXfilter(2, 1, 0), itsKalmanNeedInit(true)
200 itsTPXfilter.transitionMatrix = (cv::Mat_<float>(2, 2) << 1, 1, 0, 1);
202 cv::setIdentity(
itsTPXfilter.processNoiseCov, cv::Scalar::all(0.1F * 0.1F));
203 cv::setIdentity(
itsTPXfilter.measurementNoiseCov, cv::Scalar::all(2.0F * 2.0F));
204 cv::setIdentity(
itsTPXfilter.errorCovPost, cv::Scalar::all(0.1F * 0.1F));
215 roadfinder::horizon::freeze(
true);
216 roadfinder::support::freeze(
true);
217 roadfinder::spacing::freeze(
true);
223 roadfinder::horizon::freeze(
false);
224 roadfinder::support::freeze(
false);
225 roadfinder::spacing::freeze(
false);
259 static int currRequestID = 0;
274 int const spacing = roadfinder::spacing::get();
275 int const hline = roadfinder::horizon::get();
276 for (
int i = -4 * spacing; i <= img.cols + 4 * spacing; i += spacing)
283 int const sobelApertureSize = 7;
284 int const highThreshold = 400 * sobelApertureSize * sobelApertureSize;
285 int const lowThreshold = int(highThreshold * 0.4F);
287 cv::Canny(img, cvEdgeMap, lowThreshold, highThreshold, sobelApertureSize);
295 std::future<void> track_fut;
355 if (max_l < likelihood) { max_l = likelihood; max_il = i; }
356 if (max_p < posterior) { max_p = posterior; max_ip = i; }
365 int l_size = likelihood / max_l * 10;
366 int p_size = posterior / max_l * 10;
368 if (l_size < 2) l_size = 2;
369 if (p_size < 2) p_size = 2;
395 line.roadBottomPoint.i, line.roadBottomPoint.j, 0, color);
397 line.onScreenRoadBottomPoint.i, line.onScreenRoadBottomPoint.j, 0, color);
447 size_t num_healthy_lines = 0;
448 size_t num_new_lines = 0;
449 size_t num_noisy_lines = 0;
450 size_t num_healthy_active = 0;
451 int const width = edgeMap.cols;
int const height = edgeMap.rows;
452 int const horiline = roadfinder::horizon::get();
454 for (
Line const & line : lines)
456 if (line.scores.size() > 0) ++num_noisy_lines;
457 else if (line.start_scores.size() > 0) ++num_new_lines;
458 else { ++num_healthy_lines;
if (line.isActive) ++num_healthy_active; }
461 if (num_healthy_lines == 0 && num_new_lines == 0 && num_healthy_lines == 0)
463 vanishing_point = prev_vanishing_point;
465 target_point = road_center_point;
470 std::vector<Line> temp_lines;
float weight = 0.0;
471 if (num_healthy_lines > 0)
473 for (
Line const & line : lines)
474 if (line.scores.size() == 0 && line.start_scores.size() == 0) temp_lines.push_back(line);
477 else if (num_new_lines > 0)
479 for (
Line const & line : lines)
if (line.start_scores.size() > 0) temp_lines.push_back(line);
483 else if (num_noisy_lines > 0)
485 for (
Line const & line : lines)
if (line.scores.size() > 0) temp_lines.push_back(line);
491 target_point = road_center_point;
495 if (num_healthy_lines > 0 && num_healthy_active == 0)
498 for (
Line & line : lines)
500 if (line.scores.size() == 0 && line.start_scores.size() == 0)
502 line.isActive =
true;
503 line.angleToCenter = M_PI/2 - line.angle;
504 line.pointToServo = line.onScreenRoadBottomPoint;
511 float total_weight = 0.0f;
512 float total_angle = 0.0f;
515 float total_curr_offset = 0.0f;
516 for (
Line const & line : lines)
517 if (line.scores.size() == 0 && line.start_scores.size() == 0 && line.isActive)
522 float angle = line.angle;
523 float cangle = line.angleToCenter;
524 float weight = line.score;
526 float ccangle = cangle + angle;
528 total_angle += ccangle * weight;
529 total_weight += weight;
532 float dist = height - horiline;
534 float cos_ang = cos(M_PI/2 - ccangle);
535 if (cos_ang != 0.0F) tpi = dist / cos_ang * sin(M_PI/2 - ccangle);
536 tpi += vanishing_point.
i;
539 float c_offset = 0.0f;
544 float offset = line.offset;
545 if (fabs(pt_ts.
i) < 0.05F || fabs(pt_ts.
i - width) < 0.05F)
550 c_pt = intersectPoint(h_pt, c_pt, h1, h2);
552 c_offset = c_pt.
i - pt_ts.
i;
553 total_curr_offset += (c_offset + offset) * weight;
557 float avg_weight = 0.0F;
558 if (num_a_line > 0) avg_weight = total_weight / num_a_line;
559 confidence = avg_weight;
560 if (avg_weight == 0)
return road_center_point;
563 float avg_angle = 0.0F;
564 if (total_weight > 0) avg_angle = total_angle / total_weight;
565 float dist = height - horiline;
567 float cos_ang = cos(M_PI/2 - avg_angle);
568 if (fabs(cos_ang) > 0.001F) tpi = dist / cos_ang * sin(M_PI/2 - avg_angle);
569 tpi += float(width) / 2.0F;
573 float avg_offset = 0.0F;
574 if (total_weight > 0) avg_offset = total_curr_offset / total_weight;
575 float cpi = float(width) / 2.0F + avg_offset;
579 for (
Line & line : lines)
581 if (avg_weight > 0.0 && line.scores.size() == 0 && line.start_scores.size() == 0 && !line.isActive)
584 float angle = line.angle;
585 float ccangle = avg_angle - angle;
586 line.angleToCenter = ccangle;
587 line.pointToServo = line.onScreenRoadBottomPoint;
588 line.offset = avg_offset;
589 line.isActive =
true;
593 return road_center_point;
600 size_t n_in_lines = lines.size();
603 std::vector<bool> is_healthy(n_in_lines);
604 for (
size_t i = 0; i < n_in_lines; ++i)
605 is_healthy[i] = (lines[i].scores.size() == 0 && lines[i].start_scores.size() == 0);
607 std::vector<int> road_match_index(n_road_lines, -1);
608 std::vector<int> in_match_index(n_in_lines, -1);
610 std::vector<std::vector<float> > match_dists;
611 for (
size_t i = 0; i < n_in_lines; ++i) match_dists.push_back(std::vector<float>(n_road_lines));
614 for (
size_t i = 0; i < n_in_lines; ++i)
616 if (!is_healthy[i])
continue;
621 for (
size_t j = 0; j < n_road_lines; ++j)
629 if (hdist > 50) match_dists[i][j] = dist + hdist;
630 else match_dists[i][j] = dist;
635 for (
size_t i = 0; i < n_in_lines; ++i)
637 if (!is_healthy[i])
continue;
640 int m1_index = -1;
float m1_dist = -1.0;
641 int m2_index = -1;
float m2_dist = -1.0;
642 for (
size_t j = 0; j < n_road_lines; ++j)
644 if (road_match_index[j] != -1)
continue;
646 float dist = match_dists[i][j];
647 if (m1_index == -1 || dist < m1_dist)
649 m2_index = m1_index; m2_dist = m1_dist;
650 m1_index = j ; m1_dist = dist;
652 else if (m2_index == -1 || dist < m2_dist)
654 m2_index = j ; m2_dist = dist;
659 int ml1_index = -1;
float ml1_dist = -1.0;
660 int ml2_index = -1;
float ml2_dist = -1.0;
661 for (
size_t j = 0; j < n_road_lines; ++j)
664 if (road_match_index[j] != -1 || nmatch < 10)
continue;
666 float dist = match_dists[i][j];
667 if (ml1_index == -1 || dist < ml1_dist)
669 ml2_index = ml1_index; ml2_dist = ml1_dist;
670 ml1_index = j ; ml1_dist = dist;
672 else if (ml2_index == -1 || dist < ml2_dist)
674 ml2_index = j ; ml2_dist = dist;
682 if (ml1_dist != -1.0F)
683 if (ml1_dist < 15.0F || ((ml2_dist != -1.0 || ml1_dist/ml2_dist < .1) && ml1_dist < 30.0F))
687 if (j == -1 && m1_dist != -1.0F)
688 if (m1_dist < 5.0F || ((m2_dist != -1.0 || m1_dist/m2_dist < .1) && m1_dist < 20.0F))
693 road_match_index[j] = i;
694 in_match_index[i] = j;
701 lines[i].isActive =
true;
726 if (index > lindex+300)
734 else { l_itr++; p_itr++; i_itr++; n_itr++; }
740 for (
size_t i = 0; i < n_in_lines; ++i)
742 if (!is_healthy[i])
continue;
743 if (in_match_index[i] != -1)
continue;
763 float total_weight = 0.0F;
764 float total_hi = 0.0F;
766 for (
Line const & l : lines)
768 float hi = l.horizonPoint.
i;
769 float weight = l.score;
771 total_hi += hi*weight;
772 total_weight += weight;
776 float wavg_hi = 0.0F;
777 float avg_weight = 0.0F;
780 wavg_hi = total_hi / total_weight;
781 avg_weight = total_weight / num_hi;
783 confidence = avg_weight;
785 return Point2D<int>(wavg_hi, roadfinder::horizon::get());
791 int const threshold = 10, minLineLength = 5, maxGap = 2;
792 std::vector<cv::Vec4i> segments;
793 cv::HoughLinesP(cvImage, segments, 1, CV_PI/180, threshold, minLineLength, maxGap);
797 for (cv::Vec4i
const & seg : segments)
802 int dx = pt2.
i - pt1.
i;
803 int dy = pt2.
j - pt1.
j;
805 float length = pow(dx * dx + dy * dy, .5);
806 float angle = atan2(dy, dx) * 180.0F /M_PI;
808 int horizon_y = roadfinder::horizon::get();
809 int horizon_s_y = horizon_y + roadfinder::support::get();
810 bool good_horizon_support =
811 (pt1.
j > horizon_y && pt2.
j > horizon_y) && (pt1.
j > horizon_s_y || pt2.
j > horizon_s_y);
813 bool non_vertical = !((angle > 80.0F && angle < 100.0F) || (angle < -80.0F && angle > -100.0F));
815 if (length > 5.0F && good_horizon_support && non_vertical)
825 int const horiline = roadfinder::horizon::get();
826 int const vpdt = roadfinder::distthresh::get();
832 std::vector<float> curr_vp_likelihood(num_vp, 0.0F);
833 std::vector<std::vector<uint> > curr_vp_support(num_vp);
855 int p_int_i = int(p_int.
i);
856 if (!((p1.
i <= p2.
i && p2.
i <= p_int_i && p_int_i <= vp.
i+10) ||
857 (p1.
i >= p2.
i && p2.
i >= p_int_i && p_int_i >= vp.
i-10) ))
861 float d_val = 1.0 - dist / vpdt;
864 curr_vp_support[i].push_back(j);
867 curr_vp_likelihood[i] += d_val*length;
877 float likelihood = curr_vp_likelihood[i];
882 if (!(vanishingPoint.
i == -1 && vanishingPoint.
j == -1))
884 float di = fabs(vp.
i - vanishingPoint.
i);
885 prior = 1.0 - di / (edgeMap.cols / 4);
886 if (prior < .1) prior = .1;
894 for (
uint j = 0; j < curr_vp_support[i].size(); ++j)
903 if (max_p < posterior) { max_p = posterior; max_i = i; }
909 std::list<Segment> supporting_segments;
911 for (
uint i = 0; i < n_segments; ++i) supporting_segments.push_back(
itsVanishingPoints[max_i].supportingSegments[i]);
912 supporting_segments.sort();
913 supporting_segments.reverse();
915 std::vector<Line> current_lines;
916 std::vector<bool> is_used(n_segments,
false);
919 std::list<Segment>::iterator itr = supporting_segments.begin(), stop = supporting_segments.end();
926 if (is_used[index]){ index++;
continue; }
927 is_used[index] =
true;
931 float total_length = 0.0F;
uint num_segments = 0;
932 Line l =
findLine2(s2, edgeMap, supporting_segments, is_used, total_length, num_segments);
944 if (score >= .5) current_lines.push_back(l);
952 return current_lines;
956std::vector<Point2D<int> >
959 std::vector<uint> startIndexes;
960 return getPixels(p1, p2, edgeMap, startIndexes);
964std::vector<Point2D<int> >
966 std::vector<uint> & startIndexes)
968 std::vector<Point2D<int> > points;
971 const int w = edgeMap.cols,
h = edgeMap.rows;
972 int dx = p2.
i - p1.
i, ax = abs(dx) << 1, sx = dx < 0 ? -1 : 1;
973 int dy = p2.
j - p1.
j, ay = abs(dy) << 1, sy = dy < 0 ? -1 : 1;
974 int x = p1.
i, y = p1.
j;
977 bool start_segment =
true; startIndexes.clear();
981 int d = ay - (ax >> 1);
986 if (coordsOk(x, y, w,
h))
988 if (edgeMap.at<
byte>(y, x) > 0)
990 else if (points.size() > 0)
992 uint size = points.size();
996 for (
int di = 0; di <= 1; di++)
997 for (
int dj = 0; dj <= 1; dj++)
999 if (di == 0 && dj == 0)
continue;
1000 if (!coordsOk(x+di, y+dj, w,
h))
continue;
1002 if (edgeMap.at<
byte>(y+dj, x+di) && abs((x+di)-ppt.
i) <= 1 && abs((y+dj)-ppt.
j) <= 1)
1003 { points.push_back(
Point2D<int>(x+di, y+dj)); adding =
true; }
1007 if (start_segment && adding) { startIndexes.push_back(points.size()-1); start_segment =
false; }
1008 else if (!start_segment && !adding &&
Point2D<int>(x, y).
distance(points[points.size()-1]) > 1.5)
1009 start_segment =
true;
1012 if (x == p2.
i)
break;
1013 if (d >= 0) { y += sy; d -= ax; }
1019 int d = ax - (ay >> 1);
1022 bool adding =
false;
1024 if (x >= 0 && x < w && y >= 0 && y <
h)
1026 if (edgeMap.at<
byte>(y, x) > 0)
1027 { points.push_back(
Point2D<int>(x,y)); adding =
true; }
1028 else if (points.size() > 0)
1030 uint size = points.size();
1034 for (
int di = 0; di <= 1; di++)
1035 for (
int dj = 0; dj <= 1; dj++)
1037 if (di == 0 && dj == 0)
continue;
1038 if (!coordsOk(x+di, y+dj, w,
h))
continue;
1040 if (edgeMap.at<
byte>(y+dj, x+di) && abs((x+di)-ppt.
i) <= 1 && abs((y+dj)-ppt.
j) <= 1)
1041 { points.push_back(
Point2D<int>(x+di,y+dj)); adding =
true; }
1045 if (start_segment && adding) { startIndexes.push_back(points.size()-1); start_segment =
false; }
1046 else if (!start_segment && !adding &&
Point2D<int>(x, y).
distance(points[points.size()-1]) > 1.5)
1047 start_segment =
true;
1050 if (y == p2.
j)
break;
1051 if (d >= 0) { x += sx; d -= ay; }
1059std::vector<Point2D<int> >
1062 std::vector<Point2D<int> > points;
1065 const int w = edgeMap.cols,
h = edgeMap.rows;
1066 int dx = p2.
i - p1.
i, ax = abs(dx) << 1, sx = dx < 0 ? -1 : 1;
1067 int dy = p2.
j - p1.
j, ay = abs(dy) << 1, sy = dy < 0 ? -1 : 1;
1068 int x = p1.
i, y = p1.
j;
1073 int d = ay - (ax >> 1);
1076 if (x >= 0 && x < w && y >= 0 && y <
h && edgeMap.at<
byte>(y, x) > 0) points.push_back(
Point2D<int>(x, y));
1077 if (x == p2.
i)
break;
else if (d >= 0) { y += sy; d -= ax; }
1083 int d = ax - (ay >> 1);
1086 if (x >= 0 && x < w && y >= 0 && y <
h && edgeMap.at<
byte>(y, x) > 0) points.push_back(
Point2D<int>(x, y));
1087 if (y == p2.
j)
break;
else if (d >= 0) { x += sx; d -= ay; }
1097 std::vector<bool> & is_used,
float & totalLength,
uint & numSegments)
1102 std::vector<Point2D<int> > points =
getPixels(p1, p2, edgeMap);
1104 float const distance_threshold = 7.0F;
float const distance_threshold2 = 5.0F;
1107 size_t index = 0; totalLength = s.
length; numSegments = 1;
1109 std::list<Segment>::const_iterator itr = supportingSegments.begin();
1110 for (
size_t i = 0; i < is_used.size(); ++i)
1116 if (is_used[i])
continue;
1118 int mid_left_count = 0, mid_right_count = 0;
1119 bool is_inline =
true, is_close_inline =
true;
1120 std::vector<Point2D<int> > curr_points =
getPixels(p2_1, p2_2, edgeMap);
1122 for (
size_t j = 0; j < curr_points.size(); ++j)
1124 float const dist = distance(p1, p2, curr_points[j]);
1125 int const wsid = side(p1, p2, curr_points[j]);
1127 if (wsid <= 0) ++mid_left_count;
1128 if (wsid >= 0) ++mid_right_count;
1129 if (dist > distance_threshold2) { is_close_inline =
false; }
1130 if (dist > distance_threshold) { is_inline =
false; j = curr_points.size(); }
1134 if (is_close_inline || (is_inline && mid_left_count >= 2 && mid_right_count >= 2))
1136 for (
size_t j = 0; j < curr_points.size(); ++j) points.push_back(curr_points[j]);
1137 is_used[i] =
true; totalLength += length; ++numSegments;
1139 std::vector<Point2D<int> > curr_points2 =
getPixels(p2_1, p2_2, edgeMap);
1140 for (
size_t j = 0; j < curr_points2.size(); ++j) points.push_back(curr_points2[j]);
1144 updateLine(l, points, totalLength, edgeMap.cols, edgeMap.rows);
1147 float dist = point1.
distance(point2);
1148 float score = l.
score / dist;
1155 int const width,
int const height)
1157 if (points.empty()) { l.
score = -1.0F;
return; }
1159 int const horiline = roadfinder::horizon::get();
1160 int const horisupp = horiline + roadfinder::support::get();
1178 else if (tr2.
i > width)
1184 else if (tr1.
i > width)
1190 else if (tr3.
i > width)
1196 float dy = p2.
j - p1.
j;
1197 float dx = p2.
i - p1.
i;
1200 float angle = atan2(dy, dx);
1201 if (angle < 0.0) angle = M_PI + angle;
1208 int const width,
int const height)
1212 CvPoint* cvPoints = (CvPoint*)malloc(points.size() *
sizeof(
Point2D<int>));
1213 for (
size_t i = 0; i < points.size(); ++i) { cvPoints[i].x = points[i].i; cvPoints[i].y = points[i].j; }
1216 CvMat point_mat = cvMat(1, points.size(), CV_32SC2, cvPoints);
1217 cvFitLine(&point_mat, CV_DIST_L2, 0, 0.01, 0.01, line);
1222 float const d = sqrtf(line[0]*line[0] + line[1]*line[1]);
1223 line[0] /= d; line[1] /= d;
1225 float const t = width + height;
1226 p1.
i = line[2] - line[0] * t;
1227 p1.
j = line[3] - line[1] * t;
1228 p2.
i = line[2] + line[0] * t;
1229 p2.
j = line[3] + line[1] * t;
1236 std::vector<Point2D<int> > points;
1237 return getLineFitness(horizonPoint, roadBottomPoint, edgeMap, points, visual);
1242 cv::Mat
const & edgeMap, std::vector<
Point2D<int> > & points,
1246 int min_effective_segment_size = 5;
1254 std::vector<uint> start_indexes;
1255 points =
getPixels(p1, p2, edgeMap, start_indexes);
1261 uint num_segments = start_indexes.size();
1262 float max_length = 0.0F;
1263 int total = 0;
int max = 0;
1264 float eff_length = 0;
1265 for (
uint i = 1; i < num_segments; ++i)
1267 int size = start_indexes[i] - start_indexes[i-1];
1268 if (max < size) max = size;
1271 uint i1 = start_indexes[i-1];
1272 uint i2 = start_indexes[i ]-1;
1276 if (max_length < length) max_length = length;
1278 if (size >= min_effective_segment_size) eff_length+= length;
1281 if (num_segments > 0)
1283 int size = int(points.size()) - int(start_indexes[num_segments-1]);
1285 if (max < size) max = size;
1288 uint i1 = start_indexes[num_segments-1 ];
1289 uint i2 = points.size()-1;
1295 if (max_length < length) max_length = length;
1297 if (size >= min_effective_segment_size) eff_length+= length;
1300 if (max_length > 0.0)
1302 uint lsize = lpoints.size();
1303 uint rsize = rpoints.size();
1306 if (dist <= 50.0 || points.size() < 2*(lsize+rsize)) score = 0.0;
1307 else score = eff_length/dist;
1324 for (
Line & line : currentLines)
1326 Point2D<int> pi1(line.onScreenHorizonSupportPoint + 0.5F);
1329 float max_score = 0.0F;
1330 std::vector<Point2D<int> > max_points;
1332 for (
int di1 = -10; di1 <= 10; di1 += 2)
1333 for (
int di2 = -10; di2 <= 10; di2 += 2)
1337 std::vector<Point2D<int> > points;
1341 Line l;
updateLine(l, points, score, edgeMap.cols, edgeMap.rows);
1351 if (score > max_score) { max_score = score; max_points = points; }
1355 if (max_score > 0)
updateLine(line, max_points, max_score, edgeMap.cols, edgeMap.rows);
else line.score = max_score;
1356 line.segments.clear();
1360 std::vector<Line> temp_lines;
1361 for (
Line & line : currentLines)
1363 uint num_sscore = line.start_scores.size();
1368 line.start_scores.push_back(line.score);
1372 for (
uint j = 0; j < num_sscore; ++j)
if (line.start_scores[j] > .5) num_high++;
1374 if (num_high > 5) { line.start_scores.clear(); num_sscore = 0; }
1375 if (num_sscore < 7) temp_lines.push_back(line);
1377 else temp_lines.push_back(line);
1379 currentLines.clear();
1380 for (
uint i = 0; i < temp_lines.size(); ++i) currentLines.push_back(temp_lines[i]);
1384 for (
Line & line : currentLines)
1386 if (line.score < 0.3 || line.scores.size() > 0) line.scores.push_back(line.score);
1388 uint num_low = 0;
int size = line.scores.size();
bool all_good_values =
true;
1389 for (
int j = 0; j < size; ++j)
if (line.scores[j] < 0.3) { num_low++; all_good_values =
false; }
1395 if (all_good_values) line.scores.clear();
1398 std::vector<float> vals;
1401 for (
int j = size-7; j < size; ++j) vals.push_back(line.scores[j]);
1405 temp_lines.push_back(line);
1409 currentLines.clear();
1410 for (
uint i = 0; i < temp_lines.size(); ++i) currentLines.push_back(temp_lines[i]);
1423 int width,
int height)
1425 std::vector<Line> combLines;
1426 std::vector<bool> cline_isadded(currentLines.size(),
false);
1430 for (
size_t j = 0; j < prevLines.size(); ++j)
1432 Point2D<float> const & pp1 = prevLines[j].onScreenHorizonSupportPoint;
1433 Point2D<float> const & pp2 = prevLines[j].onScreenRoadBottomPoint;
1434 float const score_pl = prevLines[j].score;
1436 float min_dist = 1.0e30F;
int min_i = -1;
1437 std::vector<size_t> match_index;
1438 for (
size_t i = 0; i < currentLines.size(); ++i)
1440 Point2D<float> const & cp1 = currentLines[i].onScreenHorizonSupportPoint;
1441 Point2D<float> const & cp2 = currentLines[i].onScreenRoadBottomPoint;
1447 if (dist < 7.0F) { match_index.push_back(i);
if (dist < min_dist) { min_dist = dist; min_i = i; } }
1451 if (match_index.size() > 0)
1454 float score_mcl = currentLines[min_i].score;
1456 if (score_pl > score_mcl)
1457 combLines.push_back(prevLines[j]);
1460 updateLine(l, currentLines[min_i].points, score_mcl, width, height);
1464 if (ss_size > 0) l.
start_scores[ss_size-1] = score_mcl;
1466 l.
scores = prevLines[j].start_scores;
1467 size_t s_size = l.
scores.size();
1468 if (s_size > 0) l.
scores[s_size-1] = score_mcl;
1470 l.
isActive = prevLines[j].isActive;
1473 l.
offset = prevLines[j].offset;
1474 l.
index = prevLines[j].index;
1475 combLines.push_back(l);
1479 for (
uint i = 0; i < match_index.size(); ++i) cline_isadded[match_index[i]] =
true;
1481 else combLines.push_back(prevLines[j]);
1484 for (
uint i = 0; i < cline_isadded.size(); ++i)
if (!cline_isadded[i]) combLines.push_back(currentLines[i]);
1492 std::vector<Line> newLines; std::vector<bool> line_isadded(lines.size(),
false);
1494 for (
size_t j = 0; j < lines.size(); ++j)
1496 if (line_isadded[j])
continue;
1498 Line line_added = lines[j];
1502 for (
size_t i = j + 1; i < lines.size(); ++i)
1504 if (line_isadded[i])
continue;
1506 Point2D<float> const & cp1 = lines[i].onScreenHorizonSupportPoint;
1508 float const score_cl2 = lines[i].score;
1516 line_isadded[i] =
true;
1517 if (line_added.
score < score_cl2) line_added = lines[i];
1520 newLines.push_back(line_added);
#define JEVOIS_WAIT_GET_FUTURE(f)
unsigned int uint
Canonical unsigned int.
This is a basic class to encode 2D integer coordinates.
promote_trait< T, float >::TP distance(const Point2D< T > &p) const
the euclidean distance from p
bool isValid() const
test whether i and j are both positive
void trackVanishingLines(cv::Mat const &edgeMap, std::vector< Line > ¤tLines, jevois::RawImage &visual)
track vanishing lines by to fit to the new, inputted, edgemap
std::vector< VanishingPoint > itsVanishingPoints
vanishing points being considered
std::vector< Segment > itsCurrentSegments
current segments found using CVHoughlines
Point2D< float > computeRoadCenterPoint(cv::Mat const &edgeMap, std::vector< Line > &lines, Point2D< int > &vanishing_point, Point2D< float > &road_center_point, float &confidence)
computes the road center point to servo to
void process(cv::Mat const &img, jevois::RawImage &visual)
Compute the vanishing point location using the full blown algorithm.
std::vector< Line > computeVanishingLines(cv::Mat const &edgeMap, Point2D< int > const &vanishingPoint, jevois::RawImage &visual)
main function to detect the road
std::vector< Point2D< int > > getPixels(Point2D< int > const &p1, Point2D< int > const &p2, cv::Mat const &edgeMap)
get pixels for segment defined by p1 and p2 have added complexity to search within 1....
std::pair< Point2D< int >, float > getCurrVanishingPoint() const
Get the current vanishing point and confidence.
std::vector< Line > combine(std::vector< Line > &prevLines, std::vector< Line > const ¤tLines, int width, int height)
combine two lines sets, discard duplicates and overlaps
std::vector< Point2D< int > > getPixelsQuick(Point2D< int > const &p1, Point2D< int > const &p2, cv::Mat const &edgeMap)
get pixels that make up the segment defined by p1 and p2
Point2D< float > itsTargetPoint
target servo point
void resetRoadModel()
Reset all tracker internals and start fresh (e.g., when changing goal direction)
Point2D< float > getCurrCenterPoint() const
Get the current road center point.
void projectForwardVanishingLines(std::vector< Line > &lines, std::vector< cv::Mat > const &edgeMaps, jevois::RawImage &visual)
update the lines with the inputted set of edgemaps
void updateRoadModel(std::vector< Line > &lines, int index)
update road model and incoming lines NOTE: also change the line parameters to sync them this avoids d...
Point2D< int > getVanishingPoint(std::vector< Line > const &lines, float &confidence)
estimate the vanishing point from the tracked lines
float getLineFitness(Point2D< int > const &horizonPoint, Point2D< int > const &roadBottomPoint, cv::Mat const &edgeMap, jevois::RawImage &visual)
compute how well the line equation fit the edgels in edgemap
Line findLine2(Segment const &s, cv::Mat const &edgeMap, std::list< Segment > const &supportingSegments, std::vector< bool > &is_used, float &totalLength, uint &numSegments)
find lines given the found supporting segments
std::vector< Line > itsCurrentLines
the current lines being tracked
uint itsNumIdentifiedLines
indicate how many unique lines have been identified NOTE: never reset
RoadFinder(std::string const &instance)
constructor
void preUninit() override
This class has state and does not support some online param changes.
Point2D< int > itsVanishingPoint
current vanishing point
cv::KalmanFilter itsTPXfilter
virtual ~RoadFinder()
desctructor
void computeHoughSegments(cv::Mat const &cvImage)
compute the hough segments in the image
void fitLine(std::vector< Point2D< int > > const &points, Point2D< float > &p1, Point2D< float > &p2, int const width, int const height)
openCV wrapper function to fit a line to an input vector of points
std::vector< bool > itsVanishingPointStability
vanishing point score tracker
Point2D< float > itsAccumulatedTrajectory
the accumulated trajectory
void postInit() override
This class has state and does not support some online param changes.
bool itsTrackingFlag
indicate whether tracking
float itsVanishingPointConfidence
current vanishing point
Point2D< float > getCurrTargetPoint() const
Get the current target point.
void updateLine(Line &l, std::vector< Point2D< int > > const &points, float score, int const width, int const height)
update the information in by updating the input points, score and various handy coordinate locations
Point2D< float > itsCenterPoint
current center of road point
float getFilteredTargetX() const
Get the kalman-fitered target X, can be used to set robot steering.
std::vector< Line > discardDuplicates(std::vector< Line > const ¤tLines)
discard duplicate lines in a set
void checkpoint(char const *description)
void drawDisk(RawImage &img, int x, int y, unsigned int rad, unsigned int col)
void drawLine(RawImage &img, int x1, int y1, int x2, int y2, unsigned int thick, unsigned int col)
unsigned short constexpr MedPurple
unsigned short constexpr LightPink
unsigned short constexpr White
unsigned short constexpr DarkGrey
unsigned short constexpr LightTeal
unsigned short constexpr MedGreen
unsigned short constexpr DarkPink
unsigned short constexpr DarkGreen
unsigned short constexpr LightGreen
unsigned short constexpr LightGrey
keeps all the ready to use information of a supporting line as it pertains to describing the road
std::vector< float > scores
tracking information to monitor health of the line
std::vector< float > start_scores
Point2D< float > onScreenRoadBottomPoint
Point2D< float > onScreenHorizonSupportPoint
Point2D< float > horizonPoint
quick information for various locations with respect to the road
Point2D< float > onScreenHorizonPoint
bool isActive
tracks whether the line can be used for finding the road center
std::vector< Point2D< int > > points
the points that are fit to the line
Point2D< float > roadBottomPoint
float length
basic information to specify the line
std::vector< Segment > segments
original supporting segments out of sync after initial frame
Point2D< float > pointToServo
Point2D< float > horizonSupportPoint
std::vector< Point2D< float > > lastSeenHorizonPoint
std::vector< Line > lines
std::vector< Point2D< float > > lastSeenLocation
std::vector< int > numMatches
std::vector< int > lastActiveIndex
a segment is defined by the two end-points
Keeps all the supporting information about a specific vanishing point.