#include #include #include #include #include using namespace std; using namespace cv; int find_intersection_index(int x0, int y0, int x1, int y1, int** contour_map, bool stop_at_endpoint=true) // bresenham aus der dt. wikipedia // returns: the point's index where the intersection happened, or a negative number if no intersection. { int dx = abs(x1-x0), sx = x00) return contour_map[x0][y0]; // found intersection? if (contour_map[x0][y0+1]>0) return contour_map[x0][y0+1]; if (contour_map[x0+1][y0]>0) return contour_map[x0+1][y0]; if (stop_at_endpoint && x0==x1 && y0==y1) break; e2 = 2*err; if (e2 > dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */ if (e2 < dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */ } return -1; } Mat circle_mat(int radius) { Mat result(radius*2+1, radius*2+1, CV_8U); for (int x=0; x<=result.cols/2; x++) for (int y=0; y<=result.rows/2; y++) { unsigned char& p1 = result.at(result.cols/2 + x, result.rows/2 + y); unsigned char& p2 = result.at(result.cols/2 - x, result.rows/2 + y); unsigned char& p3 = result.at(result.cols/2 + x, result.rows/2 - y); unsigned char& p4 = result.at(result.cols/2 - x, result.rows/2 - y); if ( x*x + y*y < radius*radius ) p1=p2=p3=p4=255; else p1=p2=p3=p4=0; } return result; } void hue2rgb(float hue, int* r, int* g, int* b) { double ff; int i; if (hue >= 360.0) hue = 0.0; hue /= 60.0; i = (int)hue; ff = hue - i; int x=ff*255; switch(i) { case 0: *r = 255; *g = x; *b = 0; break; case 1: *r = 255-x; *g = 255; *b = 0; break; case 2: *r = 0; *g = 255; *b = x; break; case 3: *r = 0; *g = 255-x; *b = 255; break; case 4: *r = x; *g = 0; *b = 255; break; case 5: default: *r = 255; *g = 0; *b = 255-x; break; } } double linear(double x, double x1, double y1, double x2, double y2, bool clip=false, double clipmin=INFINITY, double clipmax=INFINITY) { if (clipmin==INFINITY) clipmin=y1; if (clipmax==INFINITY) clipmax=y2; if (clipmin>clipmax) { int tmp=clipmin; clipmin=clipmax; clipmax=tmp; } double result = (y2-y1)*(x-x1)/(x2-x1)+y1; if (clip) { if (result>clipmax) return clipmax; else if (result(row); for (int col=0; col(row); for (int col=0; col200) tmp=200; if (*data==largest_region) tmp=255; *data=tmp; } data++; } } } double only_retain_largest_region(Mat img, int* size) // img is a binary image // in *size, if non-NULL, the size of the largest area is stored. // returns: ratio between the second-largest and largest region // 0.0 means "that's the only region", 1.0 means "both had the same size!" // can be interpreted as 1.0 - "confidence". { int n_regions = annotate_regions(img); // calculate the area of each region int* area_cnt = new int[n_regions]; for (int i=0;i(row); for (int col=0; colmaxa) { maxa=area_cnt[i]; maxi2=maxi; maxi=i; } } // lösche alle bis auf die größte fläche for (int row = 0; row(row); for (int col=0; col > contours; vector hierarchy; findContours(img, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE, Point(0, 0)); // Draw contours drawing = Mat::zeros( img.size(), CV_8UC3 ); for( int i = 0; i< contours.size(); i++ ) { Scalar color; if (hierarchy[i][3]<0) // no parent color=Scalar(255,255,255); else // this is a sub-contour which is actually irrelevant for our needs color=Scalar(255,0,0); drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() ); } for (int road_contour_idx=0; road_contour_idx& contour = contours[road_contour_idx]; // just a shorthand if (!contour.size()>0) continue; // should never happen. // find highest and lowest contour point. (where "low" means high y-coordinate) int low_y=0, low_idx=-1; int high_y=drawing.rows; for (int j=0;j low_y) { low_y=contour[j].y; low_idx=j; } if (contour[j].y < high_y) high_y=contour[j].y; } assert(low_idx!=0); // make the contour go "from bottom upwards and then downwards back to bottom". std::rotate(contour.begin(),contour.begin()+low_idx,contour.end()); // create contour map for (int j=0;j= contour.size()) j1-=contour.size(); int j2=(j-smoothen); while (j2 < 0) j2+=contour.size(); // calculate angle, adjust it to be within [0, 360) angles[j] = atan2(contour[j1].y - contour[j2].y, contour[j1].x - contour[j2].x) * 180/3.141592654; if (angles[j]<0) angles[j]+=360; // irrelevant drawing stuff int r,g,b; hue2rgb(angles[j], &r, &g, &b); circle(drawing, contour[j], 2, Scalar(b,g,r)); int x=drawing.cols-drawing.cols*(j-first_nonbottom_idx)/(contour.size()-first_nonbottom_idx); line(drawing,Point(x,0), Point(x,10), Scalar(b,g,r)); } // calculate derivative of angle for each nonbottom contour point double* angle_derivative = new double[contour.size()]; for (int j=first_nonbottom_idx+ANG_SMOOTH; j=360) ang_diff-=360; if (ang_diff>=180) ang_diff=360-ang_diff; angle_derivative[j] = (double)ang_diff / ANG_SMOOTH; // irrelevant drawing stuff int x=drawing.cols-drawing.cols*(j-first_nonbottom_idx)/(contour.size()-first_nonbottom_idx); int c=abs(20* ang_diff/ANG_SMOOTH); Scalar col=(c<256) ? Scalar(255-c,255-c,255) : Scalar(255,0,255); line(drawing, Point(x,12), Point(x,22), col); int y=25+40-2*ang_diff/ANG_SMOOTH; line(drawing, Point(x,y), Point(x,y), Scalar(255,255,255)); circle(drawing, contour[j], 2, col); } // poorly extrapolate the ANG_SMOOTH margins for (int j=first_nonbottom_idx; j= MAX_HYST * max_deriv \forall i \in [a,b] and // ang_deriv[a-1,2,3], ang_deriv[b+1,2,3] < MAX_HYST * max_deriv // where max_deriv = max_{i \in [a,b]} ang_deriv[i]; for (int j=3; j lastmax) lastmax=angle_derivative[j]; if (angle_derivative[j] < MAX_HYST*lastmax && // found the end of the max. region angle_derivative[j+1] < MAX_HYST*lastmax && angle_derivative[j+2] < MAX_HYST*lastmax) { if (lastmax > 5) // threshold the maximum. { // search backward for the begin of that maximum region int j0; for (j0=j-1; j0>=0; j0--) if (angle_derivative[j0] < MAX_HYST*lastmax && angle_derivative[j0-1] < MAX_HYST*lastmax && angle_derivative[j0-2] < MAX_HYST*lastmax) break; // maximum region is [j0; j] double median_of_max_region = (double)angle_derivative[(j+j0)/2]; // calculate quality of that maximum. quality is high, if // 1) the maximum has a high value AND // 2) the corresponding point's y-coordinates are near the top image border AND // 3) the corresponding point's x-coordinates are near the middle of the image, if in doubt int middle_x = drawing.cols/2; int distance_from_middle_x = abs(drawing.cols/2 - contour[j].x); double quality = median_of_max_region * linear( contour[j].y, high_y, 1.0, high_y+ (drawing.rows-high_y)/10, 0.0, true) // excessively punish points far away from the top border * linear( distance_from_middle_x, 0.8*middle_x, 1.0, middle_x, 0.6, true); // moderately punish point far away from the x-middle. // keep track of the best point if (quality>bestquality) { bestquality=quality; bestquality_max=lastmax; bestquality_j=(j+j0)/2; bestquality_width=j-j0; } // irrelevant drawing stuff int x=drawing.cols-drawing.cols*((j+j0)/2-first_nonbottom_idx)/(contour.size()-first_nonbottom_idx); line(drawing, Point(x,25+40-3*quality), Point(x, 25+40), Scalar(0,255,0)); circle(drawing, contour[(j+j0)/2], 1, Scalar(128,0,0)); } lastmax=-999999; // reset lastmax, so the search can go on } } // now bestquality_j holds the index of the point with the best quality. circle(drawing, contour[bestquality_j], 3, Scalar(255,255,0)); circle(drawing, contour[bestquality_j], 2, Scalar(255,255,0)); circle(drawing, contour[bestquality_j], 1, Scalar(255,255,0)); circle(drawing, contour[bestquality_j], 0, Scalar(255,255,0)); int antisaturation = 200-(200* bestquality/10.0); if (antisaturation<0) antisaturation=0; for (int j=0;j=0; xx--) { int intersection2 = find_intersection_index(drawing.cols/2, drawing.rows-drawing.rows/5, xx, contour[bestquality_j].y, contour_map); if (intersection2<0) // won't happen anyway break; if (intersection2>=bestquality_j) // now we intersect the opposite (=left) border { if (contour[intersection2].y>=lastheight) // we intersect at a lower = worse point? xx++; // then undo last step break; } lastheight=contour[intersection2].y; } } else if (intersection > bestquality_j) // too far on the left == intersecting the left border { // rotate the line to the right till it gets better for (; xx=lastheight) // we intersect at a lower = worse point? xx--; // then undo last step break; } lastheight=contour[intersection2].y; } } // else // we directly met the bestquality point, i.e. where we wanted to go to. // do nothing // drawing stuff: // now find the intrsection point of our line with the contour (just for drawing it nicely) int steering_point = find_intersection_index(drawing.cols/2, drawing.rows-drawing.rows/5, xx, contour[bestquality_j].y, contour_map, false); if (steering_point>=0) // should be always true line(drawing, contour[steering_point], Point(drawing.cols/2, drawing.rows-drawing.rows/5), Scalar(0,255,255)); } cout << "bestquality_width="<> frame; Mat thres(frame.rows, frame.cols, CV_8UC1); Mat tmp(frame.rows, frame.cols, CV_8UC1); int** contour_map; contour_map=new int*[frame.cols]; for (int i=0;i> frame; if (frameno<190) { frameno++; continue; } cvtColor(frame, tmp, CV_RGB2GRAY); threshold(tmp, thres, 132, 255, THRESH_BINARY); dilate(thres,tmp,Mat()); erode(tmp,thres,Mat()); erode(thres,tmp,Mat()); dilate(tmp,thres,Mat()); int area_abs; double area_ratio = only_retain_largest_region(thres, &area_abs); dilate(thres, tmp, erode_kernel); erode(tmp, thres, erode_kernel); Mat drawing; find_steering_point(thres, contour_map, drawing); area_history_sum-=area_history[area_history_ptr]; area_history[area_history_ptr]=area_abs; area_history_sum+=area_abs; area_history_ptr=(area_history_ptr+1)%AREA_HISTORY; int prev_area=area_history_sum/AREA_HISTORY; cout << "\r\e[2A area = "<0.1) { cout << "\nALERT: possibly split road!\n\n\n" << flush; alertcnt=0; } if (abs(100*area_abs/prev_area -100) >=10) { cout << "\nALERT: too fast road area change!\n\n\n" << flush; alertcnt=0; } alertcnt++; if (alertcnt == 20) cout << "\n\n\n\n\n\n------------------------\n\n\n"; cout << "frame #"<