-
Notifications
You must be signed in to change notification settings - Fork 51
Feat/368 stop bar detector #384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 9 commits
3662642
6a72c02
e69cada
8e99802
0287417
a6e4d15
033268d
8d800ed
7ebf503
fed5362
ca95f2f
1d0c6a5
29b6d6b
4c828fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| <launch> | ||
| <node name="stopbar_detector" pkg="rr_iarrc" type="stopbar_detector" output="screen" required="true"> | ||
| <!-- Output Topics --> | ||
| <param name="stopbar_near" type="string" value="/stopbar_near"/> | ||
| <param name="stopbar_angle" type="string" value="/stopbar_angle"/> | ||
|
|
||
| <!-- Camera Params--> | ||
| <param name="overhead_image_subscription" type="string" value="/camera_center/lines/detection_img_transformed" /> | ||
| <param name="pixels_per_meter" type="int" value="50" /> | ||
|
|
||
| <!-- Stop Bar Detector Params --> | ||
| <param name="stopBarGoalAngle" type="double" value="0.0" /> <!-- angle in degrees --> | ||
| <param name="stopBarGoalAngleRange" type="double" value="25.0" /> <!-- we can come at the line from many angles! --> | ||
| <param name="stopBarTriggerDistance" type="double" value="3.5" /> <!-- distance in meters --> | ||
| <param name="sleep_adjust" type="double" value=".325"/> | ||
|
|
||
| <!-- Hough Line Params--> | ||
| <param name="houghThreshold" type="int" value="65" /> <!-- see opencv HoughLinesP for more info --> | ||
| <param name="houghMinLineLength" type="double" value="50" /> | ||
| <param name="houghMaxLineGap" type="double" value="10" /> | ||
| </node> | ||
| </launch> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| add_executable(stopbar_detector stopbar_detector.cpp) | ||
| target_link_libraries(stopbar_detector ${catkin_LIBRARIES}) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| #include <cv_bridge/cv_bridge.h> | ||
| #include <ros/package.h> | ||
| #include <ros/publisher.h> | ||
| #include <ros/ros.h> | ||
| #include <rr_msgs/speed.h> | ||
| #include <sensor_msgs/Image.h> | ||
| #include <std_msgs/Bool.h> | ||
| #include <std_msgs/Float64.h> | ||
| #include <stdlib.h> | ||
|
|
||
| #include <opencv2/highgui/highgui.hpp> | ||
| #include <opencv2/imgcodecs.hpp> | ||
| #include <opencv2/imgproc/imgproc.hpp> | ||
| #include <opencv2/opencv.hpp> | ||
|
|
||
| cv_bridge::CvImagePtr cv_ptrLine; | ||
| ros::Publisher pub_line; | ||
| ros::Publisher pub_near_stopbar; | ||
| ros::Publisher pub_angle; | ||
|
|
||
| std_msgs::Bool stop_bar_near; | ||
| std_msgs::Float64 stop_bar_angle; | ||
|
|
||
| double stopBarGoalAngle; | ||
| double stopBarGoalAngleRange; | ||
| double stopBarTriggerDistance; | ||
| int houghThreshold; | ||
| double houghMinLineLength; | ||
| double houghMaxLineGap; | ||
| int pixels_per_meter; | ||
| double sleepConstant; | ||
|
|
||
| double speed; | ||
|
|
||
| cv::Mat kernel(int x, int y) { | ||
| return cv::getStructuringElement(cv::MORPH_RECT, cv::Size(x, y)); | ||
| } | ||
|
|
||
| /* | ||
| * Uses probablistic Hough to find line segments and determine if they are the | ||
| * stop bar An angle close to 0 is horizontal. | ||
| * | ||
| * @param frame The input overhead image to search inside | ||
| * @param output debug image | ||
| * @param stopBarGoalAngle The angle of line relative to horizontal that makes a | ||
| * stop bar | ||
| * @param stopBarGoalAngleRange Allowable error around stopBarGoalAngle | ||
| * @param triggerDistance Distance to the line that we will send out the message | ||
| * to take action | ||
| * @param threshold HoughLinesP threshold that determines # of votes that make a | ||
| * line | ||
| * @param minLineLength HoughLinesP minimum length of a line segment | ||
| * @param maxLineGap HoughLinesP maxmimum distance between points in the same | ||
| * line | ||
| */ | ||
| bool findStopBarFromHough(cv::Mat& frame, cv::Mat& output, double& stopBarAngle, double stopBarGoalAngle, | ||
| double stopBarGoalAngleRange, double triggerDistance, int threshold, double minLineLength, | ||
| double maxLineGap) { | ||
| cv::Mat edges; | ||
| int ddepth = CV_8UC1; | ||
| cv::Laplacian(frame, edges, ddepth); // use edge to get better Hough results | ||
| convertScaleAbs(edges, edges); | ||
| edges = frame; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this override |
||
| cv::dilate(edges, edges, kernel(4, 4)); // clearer debug image and slightly better detection | ||
| cv::cvtColor(edges, output, cv::COLOR_GRAY2BGR); // for debugging | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Call |
||
|
|
||
| // Standard Hough Line Transform | ||
| std::vector<cv::Vec4i> lines; // will hold the results of the detection | ||
| double rho = 1; // distance resolution | ||
| double theta = CV_PI / 180; // angular resolution (in radians) pi/180 is one degree res | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kinda magic numbers... Maybe const global variables? Doesn't matter that much |
||
|
|
||
| cv::HoughLinesP(edges, lines, rho, theta, threshold, minLineLength, | ||
| maxLineGap); // Like hough but for line segments | ||
| for (size_t i = 0; i < lines.size(); i++) { | ||
| cv::Vec4i l = lines[i]; | ||
| cv::Point p1(l[0], l[1]); | ||
| cv::Point p2(l[2], l[3]); | ||
| cv::line(output, p1, p2, cv::Scalar(0, 0, 255), 2, cv::LINE_AA); | ||
|
|
||
| // calc angle and decide if it is a stop bar | ||
| double distanceX = p2.x - p1.x; | ||
| double distanceY = p2.y - p1.y; | ||
| double currAngle = atan(fabs(distanceY / distanceX)) * 180 / CV_PI; // in degrees | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this break if |
||
|
|
||
| cv::Point midpoint = (p1 + p2) * 0.5; | ||
|
|
||
| if (fabs(stopBarGoalAngle - currAngle) <= stopBarGoalAngleRange) { // allows some amount of angle error | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| // get distance to the line | ||
| float dist = static_cast<float>(edges.rows - midpoint.y) / pixels_per_meter; | ||
|
|
||
| if (dist <= triggerDistance) { | ||
| // places circle in the center of the line and displays angle of line in debug image | ||
| cv::circle(output, midpoint, 3, cv::Scalar(255, 0, 0), -1); | ||
| std::stringstream streamAngle; | ||
| streamAngle << std::fixed << std::setprecision(2) << currAngle; // show angle with a couple decimals | ||
| cv::putText(output, streamAngle.str(), midpoint, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 255, 0), 1); | ||
|
|
||
| // draw line to stopbar in debug image and displays the distance in meters to it | ||
| cv::line(output, midpoint, cv::Point(midpoint.x, edges.rows), cv::Scalar(0, 255, 255), 1, cv::LINE_AA); | ||
| std::stringstream streamDist; | ||
| streamDist << std::fixed << std::setprecision(2) << dist; // show distance with a couple decimals | ||
| cv::putText(output, streamDist.str(), cv::Point(midpoint.x, edges.rows - dist / 2), | ||
| cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 255, 0), 1); | ||
|
|
||
| stopBarAngle = currAngle; | ||
| if (speed != 0) { | ||
| double timeToStopBar = (dist / speed) * sleepConstant; | ||
| ros::Duration(timeToStopBar).sleep(); | ||
| } | ||
| return true; // stop bar detected close to us! | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return false; // not close enough or no stop bar here | ||
| } | ||
|
|
||
| void stopBar_callback(const sensor_msgs::ImageConstPtr& msg) { | ||
| cv_ptrLine = cv_bridge::toCvCopy(msg, "mono8"); | ||
| cv::Mat frame = cv_ptrLine->image; | ||
| cv::Mat debug; | ||
| double stopBarAngle; | ||
| bool stopBarDetected = | ||
| findStopBarFromHough(frame, debug, stopBarAngle, stopBarGoalAngle, stopBarGoalAngleRange, | ||
| stopBarTriggerDistance, houghThreshold, houghMinLineLength, houghMaxLineGap); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are some of these variables passed if they are global? |
||
|
|
||
| // debugging draw a line where we trigger | ||
| cv::Point leftPoint(0, debug.rows - 1 - stopBarTriggerDistance * pixels_per_meter); | ||
| cv::Point rightPoint(debug.cols - 1, debug.rows - 1 - stopBarTriggerDistance * pixels_per_meter); | ||
| cv::line(debug, leftPoint, rightPoint, cv::Scalar(0, 255, 0), 1, cv::LINE_AA); | ||
|
|
||
| stop_bar_near.data = stopBarDetected; | ||
| if (stopBarDetected) | ||
| stop_bar_angle.data = stopBarAngle; | ||
| pub_near_stopbar.publish(stop_bar_near); | ||
| pub_angle.publish(stop_bar_angle); | ||
| if (pub_line.getNumSubscribers() > 0) { | ||
| sensor_msgs::Image outmsg; | ||
| cv_ptrLine->image = debug; | ||
| cv_ptrLine->encoding = "bgr8"; | ||
| cv_ptrLine->toImageMsg(outmsg); | ||
| pub_line.publish(outmsg); | ||
| } | ||
| } | ||
|
|
||
| void speed_callback(const rr_msgs::speed& speedMsg) { | ||
| speed = speedMsg.speed; | ||
| } | ||
|
|
||
| int main(int argc, char** argv) { | ||
| ros::init(argc, argv, "sign_detector"); | ||
|
|
||
| ros::NodeHandle nh; | ||
| ros::NodeHandle nhp("~"); | ||
|
|
||
| std::string overhead_image_sub; | ||
| std::string stopbar_near_topic; | ||
| std::string stopbar_angle_topic; | ||
| std::string speed_topic; | ||
|
|
||
| nhp.param("stopbar_near", stopbar_near_topic, std::string("/stopbar_near")); | ||
| nhp.param("stopbar_angle", stopbar_angle_topic, std::string("/stopbar_angle")); | ||
| nhp.param("sleep_adjust", sleepConstant, 1.0); | ||
|
|
||
| nhp.param("overhead_image_subscription", overhead_image_sub, std::string("/lines/detection_img_transformed")); | ||
|
|
||
| nhp.param("speed_subscription", speed_topic, std::string("/speed")); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you are going to do slash + topic name ( |
||
|
|
||
| nhp.param("stopBarGoalAngle", stopBarGoalAngle, 0.0); // angle in degrees | ||
| nhp.param("stopBarGoalAngleRange", stopBarGoalAngleRange, 15.0); // angle in degrees | ||
| nhp.param("stopBarTriggerDistance", stopBarTriggerDistance, 0.5); // distance in meters | ||
| nhp.param("pixels_per_meter", pixels_per_meter, 100); | ||
| nhp.param("houghThreshold", houghThreshold, 50); | ||
| nhp.param("houghMinLineLength", houghMinLineLength, 0.0); | ||
| nhp.param("houghMaxLineGap", houghMaxLineGap, 0.0); | ||
|
|
||
| pub_line = nh.advertise<sensor_msgs::Image>("/stopbar_detector/stop_bar", | ||
| 1); // debug publish of image | ||
| pub_near_stopbar = nhp.advertise<std_msgs::Bool>(stopbar_near_topic, 1); | ||
| pub_angle = nhp.advertise<std_msgs::Float64>(stopbar_angle_topic, 1); | ||
| auto speed_sub = nhp.subscribe(speed_topic, 1, speed_callback); | ||
| auto stopBar = nh.subscribe(overhead_image_sub, 1, stopBar_callback); | ||
|
|
||
| ros::spin(); | ||
| return 0; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did you even test this? Aka what launch file did you run to get this topic?