find_objects.cpp
Go to the documentation of this file.
00001 
00002 
00003 
00004 #include <ros/ros.h>
00005 #include <std_msgs/String.h>
00006 #include <std_msgs/Bool.h>
00007 #include <image_transport/image_transport.h>
00008 #include <opencv2/highgui/highgui.hpp>
00009 #include <cv_bridge/cv_bridge.h>
00010 #include <geometry_msgs/PointStamped.h>
00011 
00012 #include <pcl_conversions/pcl_conversions.h>
00013 #include <tf/transform_listener.h>
00014 #include <robotican_common/FindObjectDynParamConfig.h>
00015 #include <dynamic_reconfigure/server.h>
00016 
00017 #include <tf/transform_broadcaster.h>
00018 #include "tf/message_filter.h"
00019 #include "message_filters/subscriber.h"
00020 #include <ar_track_alvar_msgs/AlvarMarkers.h>
00021 #include <robotican_common/switch_topic.h>
00022 
00023 using namespace cv;
00024 
00025 bool debug_vision=false;
00026 
00027 
00028 bool find_object(Mat input, pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud,Point3d *obj,std::string frame);
00029 void cloud_cb(const sensor_msgs::PointCloud2ConstPtr& input);
00030 void dynamicParamCallback(robotican_common::FindObjectDynParamConfig &config, uint32_t level);
00031 void arm_msgCallback(const boost::shared_ptr<const geometry_msgs::PoseStamped>& point_ptr);
00032 
00033 
00034 
00035 
00036 tf::TransformListener *listener_ptr;
00037 
00038 //bool timeout=true;
00039 
00040 int object_id;
00041 
00042 //ros::Time detect_t;
00043 
00044 std::string depth_topic1,depth_topic2,depth_topic;
00045 bool have_object=false;
00046 
00047 ros::Publisher object_pub;
00048 image_transport::Publisher result_image_pub;
00049 image_transport::Publisher object_image_pub;
00050 image_transport::Publisher bw_image_pub;
00051 ros::Publisher pose_pub;
00052 //red
00053 int minH=3,maxH=160;
00054 int minS=70,maxS=255;
00055 
00056 int minV=10,maxV=255;
00057 int minA=200,maxA=50000;
00058 int gaussian_ksize=0;
00059 int gaussian_sigma=0;
00060 int morph_size=0;
00061 
00062 int inv_H=1;
00063 
00064 
00065 
00066 
00067 void cloud_cb(const sensor_msgs::PointCloud2ConstPtr& input) {
00068 
00069         //pcl - point clound library with lot of algorithms
00070 
00071     pcl::PointCloud<pcl::PointXYZRGBA> cloud;
00072     //convert ros point cloud msg to pcl point cloud 
00073     pcl::fromROSMsg (*input, cloud); 
00074     //create projection image from p.c.
00075     pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudp (new pcl::PointCloud<pcl::PointXYZRGBA> (cloud));
00076 
00077     if (cloudp->empty()) {
00078 
00079         ROS_WARN("empty cloud");
00080         return;
00081     }
00082         //creating new ros sensor msg - picture is relative to depth camera tf
00083     sensor_msgs::ImagePtr image_msg(new sensor_msgs::Image);
00084     pcl::toROSMsg (*input, *image_msg);
00085     image_msg->header.stamp = input->header.stamp;
00086     image_msg->header.frame_id = input->header.frame_id;
00087         
00088         
00089     cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(image_msg, sensor_msgs::image_encodings::BGR8);
00090     Mat result=cv_ptr->image;
00091 
00092     Point3d obj;
00093     //find object
00094     have_object= find_object(result,cloudp,&obj,input->header.frame_id);
00095 
00096     waitKey(1);
00097 
00098 
00099 
00100     if (have_object) {
00101 
00102         //publish geometry msg containing object's location
00103         geometry_msgs::PoseStamped target_pose;
00104         target_pose.header.frame_id=input->header.frame_id;
00105         target_pose.header.stamp=ros::Time::now();
00106         target_pose.pose.position.x =obj.x;
00107         target_pose.pose.position.y = obj.y;
00108         target_pose.pose.position.z = obj.z;
00109         target_pose.pose.orientation.w=1;
00110          pose_pub.publish(target_pose);
00111 
00112     }
00113 
00114 
00115 }
00116 
00117 void obj_msgCallback(const boost::shared_ptr<const geometry_msgs::PoseStamped>& point_ptr)
00118 {
00119         //get object location msg
00120     try
00121     {
00122         geometry_msgs::PoseStamped base_object_pose;
00123         listener_ptr->transformPose("base_footprint", *point_ptr, base_object_pose);
00124         base_object_pose.pose.orientation= tf::createQuaternionMsgFromRollPitchYaw(0.0,0.0,0.0);
00125 
00126                 //simulate alvar msgs, to get tf
00127         ar_track_alvar_msgs::AlvarMarkers msg;
00128         msg.header.stamp=base_object_pose.header.stamp;
00129         msg.header.frame_id="base_footprint";
00130 
00131         ar_track_alvar_msgs::AlvarMarker m;
00132         m.id=object_id;
00133         m.header.stamp=base_object_pose.header.stamp;
00134         m.header.frame_id="base_footprint";
00135       m.pose=base_object_pose;
00136         msg.markers.push_back(m);
00137 
00138         m.pose.pose.position.z-=0.1;
00139         m.id=2;
00140          msg.markers.push_back(m);
00141 
00142         object_pub.publish(msg);
00143 
00144 
00145     }
00146     catch (tf::TransformException &ex)
00147     {
00148         printf ("Failure %s\n", ex.what()); //Print exception which was caught
00149     }
00150 }
00151 
00152 bool find_object(Mat input, pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudp,Point3d *pr,std::string frame) {
00153 
00154     Mat hsv,filtered,bw,mask;
00155 
00156     cv_bridge::CvImage out_msg;
00157     out_msg.header.stamp=ros::Time::now();
00158     out_msg.header.frame_id=  frame;
00159         //use hsv colores - no light sensitivity
00160     cvtColor(input,hsv,CV_BGR2HSV);
00161 
00162 
00163     if (inv_H) {
00164                 //edges of spectrom - red colore
00165         Mat lower_hue_range;
00166         Mat upper_hue_range;
00167         inRange(hsv, cv::Scalar(0, minS, minV), cv::Scalar(minH, maxS, maxV), lower_hue_range);
00168         inRange(hsv, cv::Scalar(maxH, minS, minV), cv::Scalar(179, maxS, maxV), upper_hue_range);
00169         // Combine the above two images
00170 
00171         addWeighted(lower_hue_range, 1.0, upper_hue_range, 1.0, 0.0, mask);
00172     }
00173     else{
00174         //if not red use (middle of spectrom):
00175         inRange(hsv,Scalar(minH,minS,minV),Scalar(maxH,maxS,maxV),mask);
00176     }
00177     hsv.copyTo(filtered,mask);
00178     cvtColor(filtered,filtered,CV_HSV2BGR);
00179         
00180     out_msg.image    = filtered;
00181     out_msg.encoding = "bgr8";
00182     object_image_pub.publish(out_msg.toImageMsg());
00183     //convert to bw image, gaussian - blur, morphologic actions
00184     mask.copyTo(bw);
00185     if (gaussian_ksize>0) {
00186         if (gaussian_ksize % 2 == 0) gaussian_ksize++;
00187         GaussianBlur( bw, bw, Size(gaussian_ksize,gaussian_ksize), gaussian_sigma , 0);
00188     }
00189 
00190 
00191     if (morph_size>0) {
00192         Mat element = getStructuringElement( MORPH_ELLIPSE, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
00193         morphologyEx( bw, bw, MORPH_CLOSE, element, Point(-1,-1), 1 );
00194     }
00195 
00196     out_msg.image    = bw;
00197     out_msg.encoding = sensor_msgs::image_encodings::TYPE_8UC1;
00198     bw_image_pub.publish(out_msg.toImageMsg());
00199 
00200         //get image contours
00201     vector<vector<Point> > contours;
00202     vector<Vec4i> hierarchy;
00203 
00204     findContours(bw, contours,hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
00205         
00206         //get largest contour
00207     double largest_area=0;
00208     int largest_contour_index=0;
00209     for( int i = 0; i< contours.size(); i++ )
00210     {
00211         double area0 = abs(contourArea(contours[i]));
00212         if(area0>largest_area){
00213             largest_area=area0;
00214             largest_contour_index=i;
00215         }
00216     }
00217     bool ok=false;
00218     if ((largest_area>minA)&&(largest_area<maxA)) {
00219 
00220         //draw contours and details about object
00221         drawContours(input, contours, (int)largest_contour_index,  Scalar(255,0,0), 3, 8, hierarchy, 0);
00222         Moments mu=moments( contours[largest_contour_index], true );
00223         Point2f mc = Point2f( mu.m10/mu.m00 , mu.m01/mu.m00 );
00224         circle( input, mc, 4, Scalar(0,0,255), -1, 8, 0 );
00225         int pcl_index = ((int)(mc.y)*input.cols) + (int)(mc.x);
00226         circle( input, mc, 8, Scalar(0,255,0), -1, 8, 0 );
00227 
00228         pr->x=cloudp->points[pcl_index].x;
00229         pr->y=cloudp->points[pcl_index].y;
00230         pr->z=cloudp->points[pcl_index].z;
00231         char str[100];
00232         if (isnan (pr->x) || isnan (pr->y) || isnan (pr->z) ) {
00233             sprintf(str,"NaN");
00234             ok=false;
00235         }
00236         else {
00237             sprintf(str,"[%.3f,%.3f,%.3f] A=%lf",pr->x,pr->y,pr->z,largest_area);
00238             ok=true;
00239         }
00240         putText( input, str, mc, CV_FONT_HERSHEY_COMPLEX, 0.4, Scalar(255,255,255), 1, 8);
00241 
00242     }
00243 
00244 
00245     out_msg.image    = input;
00246     out_msg.encoding = "bgr8";
00247     result_image_pub.publish(out_msg.toImageMsg());
00248 
00249     return ok;
00250 }
00251 
00252 void dynamicParamCallback(robotican_common::FindObjectDynParamConfig &config, uint32_t level) {
00253     minH = config.H_min;
00254     maxH = config.H_max;
00255 
00256     minS = config.S_min;
00257     maxS = config.S_max;
00258 
00259     minV = config.V_min;
00260     maxV = config.V_max;
00261 
00262     minA = config.A_min;
00263     maxA = config.A_max;
00264 
00265     gaussian_ksize = config.gaussian_ksize;
00266     gaussian_sigma = config.gaussian_sigma;
00267 
00268     morph_size = config.morph_size;
00269 
00270     inv_H = config.invert_Hue;
00271 }
00272 
00273 
00274 void on_trackbar( int, void* ){}
00275 
00276 bool switch_pcl_topic(robotican_common::switch_topic::Request &req, robotican_common::switch_topic::Response &res) {
00277 
00278     if (req.num==1) depth_topic=depth_topic1;
00279     else if (req.num==2) depth_topic=depth_topic2;
00280     res.success=true;
00281 return true;
00282 }
00283 
00284 int main(int argc, char **argv) {
00285 
00286     ros::init(argc, argv, "find_objects_node");
00287     ros::NodeHandle n;
00288     ros::NodeHandle pn("~");
00289         
00290     pn.param<int>("object_id", object_id, 1);
00291     pn.param<std::string>("depth_topic1", depth_topic1, "/kinect2/qhd/points");
00292     pn.param<std::string>("depth_topic2", depth_topic2, "/kinect2/qhd/points");
00293     depth_topic=depth_topic1;
00294 
00295     dynamic_reconfigure::Server<robotican_common::FindObjectDynParamConfig> dynamicServer;
00296     dynamic_reconfigure::Server<robotican_common::FindObjectDynParamConfig>::CallbackType callbackFunction;
00297 
00298     callbackFunction = boost::bind(&dynamicParamCallback, _1, _2);
00299     dynamicServer.setCallback(callbackFunction);
00300 
00301     image_transport::ImageTransport it_(pn);
00302 
00303     result_image_pub = it_.advertise("result", 1);
00304     object_image_pub = it_.advertise("hsv_filterd", 1);
00305     bw_image_pub = it_.advertise("bw", 1);
00306     ros::Subscriber pcl_sub = n.subscribe(depth_topic, 1, cloud_cb);
00307     ROS_INFO_STREAM(depth_topic);
00308 
00309     object_pub=n.advertise<ar_track_alvar_msgs::AlvarMarkers>("detected_objects", 2, true);
00310 
00311     pose_pub=pn.advertise<geometry_msgs::PoseStamped>("object_pose",10);
00312 
00313         //convert depth cam tf to base foot print tf (moveit work with base foot print tf)
00314     tf::TransformListener listener;
00315     listener_ptr=&listener;
00316 
00317     message_filters::Subscriber<geometry_msgs::PoseStamped> point_sub_;
00318     point_sub_.subscribe(pn, "object_pose", 10);
00319 
00320     tf::MessageFilter<geometry_msgs::PoseStamped> tf_filter(point_sub_, listener, "base_footprint", 10);
00321     tf_filter.registerCallback( boost::bind(obj_msgCallback, _1) );
00322 
00323 
00324 ros::ServiceServer switch_sub = n.advertiseService("switch_pcl_topic", &switch_pcl_topic);
00325 
00326 ros::Rate r(10);
00327     ROS_INFO("Ready to find objects!");
00328     while (ros::ok()) {
00329     if (pcl_sub.getTopic()!=depth_topic) {
00330         pcl_sub = n.subscribe(depth_topic, 1, cloud_cb);
00331          ROS_INFO("switching pcl topic");
00332     }
00333      ros::spinOnce();
00334      r.sleep();
00335     }
00336 
00337     return 0;
00338 }
00339 


robotican_common
Author(s):
autogenerated on Fri Oct 27 2017 03:02:37