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
00039
00040 int object_id;
00041
00042
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
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
00070
00071 pcl::PointCloud<pcl::PointXYZRGBA> cloud;
00072
00073 pcl::fromROSMsg (*input, cloud);
00074
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
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
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
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
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
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());
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
00160 cvtColor(input,hsv,CV_BGR2HSV);
00161
00162
00163 if (inv_H) {
00164
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
00170
00171 addWeighted(lower_hue_range, 1.0, upper_hue_range, 1.0, 0.0, mask);
00172 }
00173 else{
00174
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
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
00201 vector<vector<Point> > contours;
00202 vector<Vec4i> hierarchy;
00203
00204 findContours(bw, contours,hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
00205
00206
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
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
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