00001 #include <numeric>
00002 #include <ros/ros.h>
00003 #include <algorithm>
00004
00005 #include <tf/transform_listener.h>
00006 #include <cv_bridge/cv_bridge.h>
00007 #include <image_transport/image_transport.h>
00008 #include <sensor_msgs/image_encodings.h>
00009 #include <geometry_msgs/PoseArray.h>
00010 #include <geometry_msgs/PolygonStamped.h>
00011 #include <geometry_msgs/Point.h>
00012 #include <visualization_msgs/Marker.h>
00013 #include <std_srvs/Empty.h>
00014 #include <std_msgs/Bool.h>
00015 #include <std_msgs/Int32.h>
00016 #include <cv_bridge/cv_bridge.h>
00017 #include <opencv/cv.h>
00018 #include <sensor_msgs/image_encodings.h>
00019 #include <image_geometry/pinhole_camera_model.h>
00020
00021 #include <hrl_clickable_display/ArrowOverlayCmd.h>
00022
00023 using namespace std;
00024
00025 namespace hrl_clickable_display {
00026
00027 class ArrowOverlay {
00028 public:
00029 ros::NodeHandle nh;
00030 ros::Subscriber command_sub;
00031 ros::Subscriber pixel3d_sub;
00032 image_transport::ImageTransport img_trans;
00033 image_transport::CameraSubscriber camera_sub;
00034 image_transport::Publisher overlay_pub;
00035 image_geometry::PinholeCameraModel cam_model;
00036 tf::TransformListener tf_listener;
00037 double ARROW_POINTS[7][3];
00038 bool auto_clear;
00039
00040 std::vector<geometry_msgs::PoseStamped> arrows;
00041
00042 ArrowOverlay();
00043 ~ArrowOverlay();
00044 void onInit();
00045 void doOverlay(const sensor_msgs::ImageConstPtr& img_msg,
00046 const sensor_msgs::CameraInfoConstPtr& info_msg);
00047 void processCommand(const ArrowOverlayCmd& msg);
00048 void pixelCallback(const geometry_msgs::PoseStamped& msg);
00049 };
00050
00051 ArrowOverlay::ArrowOverlay() : nh("~"), img_trans(nh) {
00052 }
00053
00054 ArrowOverlay::~ArrowOverlay() {
00055 }
00056
00057 void ArrowOverlay::onInit() {
00058 double A, B, C;
00059 bool debug;
00060 nh.param<double>("shaft_size", A, 0.1);
00061 nh.param<double>("head_width", B, 0.03);
00062 nh.param<double>("head_length", C, 0.03);
00063 nh.param<bool>("debug_mode", debug, false);
00064 nh.param<bool>("auto_clear", auto_clear, false);
00065 ARROW_POINTS[0][0] = 0; ARROW_POINTS[0][1] = 0; ARROW_POINTS[0][2] = 0;
00066 ARROW_POINTS[1][0] = 0; ARROW_POINTS[1][1] = 0; ARROW_POINTS[1][2] = A;
00067 ARROW_POINTS[2][0] = -B/2; ARROW_POINTS[2][1] = -B/2; ARROW_POINTS[2][2] = A;
00068 ARROW_POINTS[3][0] = B/2; ARROW_POINTS[3][1] = -B/2; ARROW_POINTS[3][2] = A;
00069 ARROW_POINTS[4][0] = B/2; ARROW_POINTS[4][1] = B/2; ARROW_POINTS[4][2] = A;
00070 ARROW_POINTS[5][0] = -B/2; ARROW_POINTS[5][1] = B/2; ARROW_POINTS[5][2] = A;
00071 ARROW_POINTS[6][0] = 0; ARROW_POINTS[6][1] = 0; ARROW_POINTS[6][2] = A+C;
00072
00073 camera_sub = img_trans.subscribeCamera<ArrowOverlay>
00074 ("/image_in", 1,
00075 &ArrowOverlay::doOverlay, this);
00076 overlay_pub = img_trans.advertise("/image_out", 1);
00077
00078 command_sub = nh.subscribe("arrow_command", 1,
00079 &ArrowOverlay::processCommand, this);
00080
00081 if(debug) {
00082 pixel3d_sub = nh.subscribe("/pixel3d", 1,
00083 &ArrowOverlay::pixelCallback, this);
00084 }
00085 ROS_INFO("[display_manager] ArrowOverlay loaded.");
00086 }
00087
00088 void ArrowOverlay::doOverlay(const sensor_msgs::ImageConstPtr& img_msg,
00089 const sensor_msgs::CameraInfoConstPtr& info_msg) {
00090
00091
00092 cam_model.fromCameraInfo(info_msg);
00093 cv_bridge::CvImagePtr cv_img = cv_bridge::toCvCopy(img_msg, sensor_msgs::image_encodings::RGB8);
00094
00095 for(uint32_t i=0;i<arrows.size();i++) {
00096
00097 tf::Pose arrow_pose;
00098 tf::poseMsgToTF(arrows[i].pose, arrow_pose);
00099 std::vector<cv::Point> cv_pts;
00100 for(int j=0;j<7;j++) {
00101
00102 btVector4 arr_pt;
00103 arr_pt.setX(ARROW_POINTS[j][0]);
00104 arr_pt.setY(ARROW_POINTS[j][1]);
00105 arr_pt.setZ(ARROW_POINTS[j][2]);
00106 arr_pt.setW(1);
00107 tf::Vector3 arr_pt_rot = arrow_pose * arr_pt;
00108 cv::Point3d proj_pt_cv(arr_pt_rot.getX(), arr_pt_rot.getY(), arr_pt_rot.getZ());
00109 cv::Point pt2d = cam_model.project3dToPixel(proj_pt_cv);
00110 cv_pts.push_back(pt2d);
00111 }
00112 const cv::Point** cv_poly_list = new const cv::Point*[6];
00113 cv::Point* shaft = new cv::Point[2];
00114 shaft[0] = cv_pts[0]; shaft[1] = cv_pts[1];
00115 cv::Point* base = new cv::Point[5];
00116 base[0] = cv_pts[2]; base[1] = cv_pts[3]; base[2] = cv_pts[4];
00117 base[3] = cv_pts[5]; base[4] = cv_pts[2];
00118 cv::Point* pyrm1 = new cv::Point[2];
00119 pyrm1[0] = cv_pts[2]; pyrm1[1] = cv_pts[6];
00120 cv::Point* pyrm2 = new cv::Point[2];
00121 pyrm2[0] = cv_pts[3]; pyrm2[1] = cv_pts[6];
00122 cv::Point* pyrm3 = new cv::Point[2];
00123 pyrm3[0] = cv_pts[4]; pyrm3[1] = cv_pts[6];
00124 cv::Point* pyrm4 = new cv::Point[2];
00125 pyrm4[0] = cv_pts[5]; pyrm4[1] = cv_pts[6];
00126 cv_poly_list[0] = shaft; cv_poly_list[1] = base; cv_poly_list[2] = pyrm1;
00127 cv_poly_list[3] = pyrm2; cv_poly_list[4] = pyrm3; cv_poly_list[5] = pyrm4;
00128 cv::Scalar color = CV_RGB(255, 0, 0);
00129 int npts[6] = {2, 5, 2, 2, 2, 2};
00130 cv::polylines(cv_img->image, cv_poly_list, npts, 6, 0, color, 1);
00131 }
00132
00133 overlay_pub.publish(cv_img->toImageMsg());
00134 }
00135
00136 void ArrowOverlay::processCommand(const ArrowOverlayCmd& msg) {
00137 if(msg.clear_arrows)
00138 arrows.clear();
00139 else {
00140 for(uint32_t i=0;i<msg.arrows.size();i++) {
00141 geometry_msgs::PoseStamped new_arrow;
00142 tf_listener.transformPose(cam_model.tfFrame(), ros::Time(0), msg.arrows[i], msg.arrows[i].header.frame_id, new_arrow);
00143 arrows.push_back(new_arrow);
00144 }
00145 }
00146 }
00147
00148 void ArrowOverlay::pixelCallback(const geometry_msgs::PoseStamped& msg) {
00149 if(auto_clear)
00150 arrows.clear();
00151 geometry_msgs::PoseStamped new_arrow;
00152 tf_listener.transformPose(cam_model.tfFrame(), ros::Time(0), msg, msg.header.frame_id, new_arrow);
00153 arrows.push_back(new_arrow);
00154 }
00155
00156 };
00157
00158 using namespace hrl_clickable_display;
00159
00160 int main(int argc, char **argv)
00161 {
00162 ros::init(argc, argv, "arrow_overlay");
00163 ArrowOverlay ao;
00164 ao.onInit();
00165 ros::spin();
00166 return 0;
00167 }