$search
00001 00034 #define RANDOM_PUSHING 0 00035 00036 #include <ros/ros.h> 00037 #include "sensor_msgs/PointCloud2.h" 00038 #include <pcl_ros/transforms.h> 00039 00040 #include <pcl/sample_consensus/method_types.h> 00041 #include <pcl/sample_consensus/model_types.h> 00042 #include <pcl/segmentation/sac_segmentation.h> 00043 #include <pcl/ModelCoefficients.h> 00044 #include <pcl/filters/extract_indices.h> 00045 #include <pcl/features/normal_3d.h> 00046 00047 #include <pcl/io/pcd_io.h> 00048 00049 #include "roi_pcl_filter.h" 00050 00051 #include "cv_bridge/CvBridge.h" 00052 #include <opencv/cv.h> 00053 #include <opencv/highgui.h> 00054 #include "sensor_msgs/Image.h" 00055 #include "sensor_msgs/CameraInfo.h" 00056 #include <image_geometry/pinhole_camera_model.h> 00057 #include <tf_conversions/tf_eigen.h> 00058 #include <eigen_conversions/eigen_msg.h> 00059 #include <stdio.h> 00060 #include <stdlib.h> 00061 #include <time.h> 00062 00063 #include <pr2_interactive_segmentation/cornerPokePoseFind.h> 00064 #include <pr2_interactive_segmentation/cornerFind.h> 00065 #include <boost/foreach.hpp> 00066 00067 00068 //#include <camera_self_filter/mask.h> 00069 00070 #define X_OUTPUT 1 00071 00072 using std::cout; 00073 using std::endl; 00074 using std::ostream; 00075 using namespace std; 00076 00077 struct randomPoint{ 00078 cv::Point push_point; 00079 Eigen::Vector2f direction; 00080 }; 00081 00082 00083 ostream& operator<< (ostream& out, const tf::Transform tf){ 00084 Eigen::Affine3d tf_eigen; 00085 tf::TransformTFToEigen(tf,tf_eigen); 00086 out << tf_eigen.matrix(); 00087 return out; 00088 00089 } 00090 00091 00092 class PokePointFinder{ 00093 00094 typedef pcl::PointXYZRGB Point; 00095 00096 ros::NodeHandle _nh; 00097 ros::NodeHandle _nh_private; 00098 ros::ServiceServer _getMaskServer; 00099 ros::ServiceClient _corner_finder; 00100 sensor_msgs::CameraInfoConstPtr _cam_info; 00101 image_geometry::PinholeCameraModel _model; 00102 00103 std::string base_frame; 00104 00105 double _tolerance_x; 00106 double _tolerance_y; 00107 double _max_height_z; 00108 double virtual_cam_z; 00109 double virtual_cam_x; 00110 double push_distance; 00111 int random_pushing; 00112 int morphology_param; 00113 double table_height; 00114 00115 float dot_threshold; 00116 00117 tf::TransformListener listener_; 00118 sensor_msgs::CvBridge _bridge; 00119 ROI_Filter<Point> roi_filter; 00120 00121 tf::Transform tf_virtual_cam; 00122 tf::Transform tf_virtual_cam_transl; 00123 00124 pcl::ModelCoefficients::Ptr coefficients; 00125 std::string point_cloud; 00126 00127 ros::Publisher pub; 00128 00129 public: 00130 PokePointFinder():_nh_private("~"){ 00131 _nh_private.param("tolerance_x", _tolerance_x, 0.10); 00132 _nh_private.param("tolerance_y", _tolerance_y, 0.10); 00133 _nh_private.param("max_height_z", _max_height_z, 0.7); 00134 00135 00136 _nh_private.param("virtual_cam_z", virtual_cam_z, 1.5); 00137 _nh_private.param("virtual_cam_x",virtual_cam_x, .70); 00138 00139 _nh_private.param("random_pushing",random_pushing,0); 00140 _nh_private.param("push_distance",push_distance,20.0); 00141 _nh_private.param("morphology_param",morphology_param,8); 00142 _nh_private.param("table_height",table_height,0.75); 00143 table_height=table_height-0.1; 00144 00145 std::string camera_name; 00146 _nh_private.param<std::string>("camera_name",camera_name, "/kinect/rgb"); 00147 _nh_private.param<std::string>("base_frame",base_frame, "base_link"); 00148 00149 00150 pub = _nh.advertise<geometry_msgs::PoseStamped>("poke_point_finder_node/concave_pose", 1000); 00151 00152 00153 _nh_private.param<std::string>("point_cloud",point_cloud, "/kinect/rgb/points"); 00154 00155 double dot_threshold_d; 00156 _nh_private.param("dot_threshold",dot_threshold_d , 0.5); 00157 dot_threshold = dot_threshold_d; 00158 00159 _cam_info = ros::topic::waitForMessage<sensor_msgs::CameraInfo>(camera_name +"/camera_info", ros::Duration(5.0)); 00160 _model.fromCameraInfo(_cam_info); 00161 00162 // service to advertise 00163 00164 _getMaskServer = _nh.advertiseService("findPokePose", &PokePointFinder::getPokePointServiceCB, this); 00165 00166 // _self_mask_client = _nh.serviceClient<camera_self_filter::mask>("self_mask"); 00167 00168 00169 //create location of cam over table 00170 tf_virtual_cam.setIdentity(); 00171 tf_virtual_cam_transl.setIdentity(); 00172 tf_virtual_cam_transl.setOrigin(tf::Vector3(virtual_cam_x, 0.0, virtual_cam_z)); 00173 //optical frame is rotated by 180 degree around y-axis 00174 btMatrix3x3 rot (0, -1, 0, 00175 -1, 0, 0, 00176 0, 0 , -1); 00177 tf::Quaternion q; 00178 rot.getRotation(q); 00179 tf_virtual_cam.setRotation(q); 00180 00181 00182 cout<<"tf_virtual_cam"<<endl<<tf_virtual_cam<<endl; 00183 cout<<"tf_virtual_cam_transl"<<endl<<tf_virtual_cam_transl<<endl; 00184 cout<<"base_frame "<<base_frame<<endl; 00185 00186 00187 00188 _corner_finder = _nh.serviceClient<pr2_interactive_segmentation::cornerFind>("find_corners"); 00189 if (!_corner_finder.waitForExistence(ros::Duration(5.0))){ 00190 ROS_ERROR("find_corners service not found"); 00191 exit(1); 00192 } 00193 00194 00195 00196 } 00197 00198 00199 bool getRandomPoint (cv::Mat& topview, randomPoint& random) 00200 { 00201 00202 cv::Point2f center; 00203 float radius; 00204 cv::Mat topview2 = cv::Mat::zeros(topview.rows, topview.cols, CV_8UC3); 00205 topview.copyTo(topview2); 00206 std::vector<std::vector <cv::Point> > contours_old; 00207 00208 00209 cv::threshold(topview,topview,100,255,CV_THRESH_BINARY); 00210 cv::Canny(topview, topview2,10,50,3); 00211 cv::findContours(topview, contours_old, CV_RETR_LIST, 00212 CV_CHAIN_APPROX_NONE); 00213 cv::imshow("image", topview2); 00214 cv::waitKey(); 00215 00216 cv::minEnclosingCircle(cv::Mat(contours_old.back()), center, radius); 00217 cv::cvtColor(topview2, topview2, CV_GRAY2BGR); 00218 cv::circle(topview2, center, (int) radius, cv::Scalar(0, 255, 0), 3); 00219 cv::imshow("image", topview2); 00220 cv::waitKey(); 00221 Eigen::Vector2f direction_use(1,1); 00222 int i_rand_use=0; 00223 00224 while (1) { 00225 00226 srand(time(NULL)); 00227 00228 int max = contours_old.back().size(); 00229 int counter = 0; 00230 int i_rand = rand() % max; 00231 00232 while (contours_old.back()[i_rand].y - center.y < 0) { 00233 i_rand = rand() % max; 00234 counter++; 00235 } 00236 00237 center.x = (int) center.x; 00238 center.y = (int) center.y; 00239 00240 cv::circle(topview2, contours_old.back()[i_rand], 5, 00241 cv::Scalar(0, 0, 255), 3); 00242 Eigen::Vector2f direction( 00243 (int) center.x - contours_old.back()[i_rand].x, 00244 (int) center.y - contours_old.back()[i_rand].y); 00245 direction.normalize(); 00246 00247 direction = 40 * direction; 00248 00249 00250 00251 cv::Point2f direct(direction[0] + contours_old.back()[i_rand].x, 00252 direction[1] + contours_old.back()[i_rand].y); 00253 00254 direct.x = (int) direct.x; 00255 direct.y = (int) direct.y; 00256 //DEBUG 00257 /*std::cout << std::endl; 00258 std::cout << "coordinates of the point"; 00259 std::cout << std::endl; 00260 std::cout << contours_old.back()[i_rand].x; 00261 std::cout << std::endl; 00262 00263 std::cout << contours_old.back()[i_rand].y; 00264 std::cout << std::endl; 00265 00266 std::cout << "coordinates of direct point"; 00267 std::cout << std::endl; 00268 00269 std::cout << direct.x; 00270 std::cout << std::endl; 00271 std::cout << direct.y; 00272 std::cout << std::endl; 00273 */ 00274 cv::circle(topview2, direct, 5, cv::Scalar(0, 0, 255), 3); 00275 00276 cv::line(topview2, contours_old.back()[i_rand], direct, 00277 cv::Scalar(255, 0, 0), 7); 00278 00279 00280 direction_use=direction; 00281 i_rand_use=i_rand; 00282 00283 00284 cv::imshow("image", topview2); 00285 char c = cv::waitKey(); 00286 if ((char) c == 27) 00287 break; 00288 } 00289 00290 00291 random.push_point=contours_old.back()[i_rand_use]; 00292 random.direction=direction_use; 00293 00294 00295 00296 00297 00298 00299 00300 return true; 00301 00302 } 00303 00304 00305 00306 00307 00308 00309 bool getPokePointServiceCB(pr2_interactive_segmentation::cornerPokePoseFind::Request& req, pr2_interactive_segmentation::cornerPokePoseFind::Response& res){ 00310 cv::Mat top_view_rgb; 00311 getTopView(top_view_rgb); 00312 pr2_interactive_segmentation::cornerFind::Response res_corner; 00313 pcl::PointCloud<pcl::PointNormal> grasps; 00314 if (random_pushing!=0) 00315 { 00316 randomPoint random; 00317 getRandomPoint(top_view_rgb, random); 00318 get3dRandomPoint(random,grasps); 00319 } 00320 else 00321 { 00322 getCornersToPush(top_view_rgb, res_corner); 00323 get3dPoints(res_corner, grasps); 00324 } 00325 00326 //convert grasps into poses 00327 std::vector<Eigen::Matrix4f> grasp_poses; 00328 convertPointNormalstoGraps(grasps, grasp_poses); 00329 00330 BOOST_FOREACH(Eigen::Matrix4f& pose, grasp_poses){ 00331 Eigen::Affine3d e2; 00332 e2.matrix() = pose.cast<double>(); 00333 geometry_msgs::Pose p_msgs; 00334 00335 tf::poseEigenToMsg(e2,p_msgs); 00336 00337 //DEBUG 00338 //tf::Transform grasp_tf; 00339 //geometry_msgs::PoseStamped msg; 00340 //msg.pose=p_msgs; 00341 //msg.header.frame_id="base_link"; 00342 //msg.header.stamp=ros::Time::now(); 00343 //msg.header.seq=0; 00344 //pub.publish(msg); 00345 00346 res.corner_poses.push_back(p_msgs); 00347 } 00348 00349 //do the same for convex 00350 std::swap(res_corner.corner, res_corner.corner_convex); 00351 std::swap(res_corner.push_direction, res_corner.push_direction_convex); 00352 00353 pcl::PointCloud<pcl::PointNormal> grasps_convex; 00354 get3dPoints(res_corner, grasps_convex); 00355 std::vector<Eigen::Matrix4f> grasp_poses_convex; 00356 convertPointNormalstoGraps(grasps_convex, grasp_poses_convex); 00357 00358 BOOST_FOREACH(Eigen::Matrix4f& pose, grasp_poses_convex){ 00359 Eigen::Affine3d e2; 00360 e2.matrix() = pose.cast<double>(); 00361 geometry_msgs::Pose p_msgs; 00362 tf::poseEigenToMsg(e2,p_msgs); 00363 res.corner_poses_convex.push_back(p_msgs); 00364 } 00365 00366 res.header.frame_id = base_frame; 00367 res.header.stamp = ros::Time::now(); 00368 00369 return true; 00370 00371 } 00372 00373 00374 bool getTopView(cv::Mat& topview){ 00375 00376 00377 00378 sensor_msgs::PointCloud2ConstPtr cloud_msg = ros::topic::waitForMessage<sensor_msgs::PointCloud2>(point_cloud, ros::Duration(5.0)); 00379 pcl::PointCloud<Point> cloud, cloud_in; 00380 pcl::fromROSMsg<Point>(*cloud_msg, cloud_in); 00381 00382 ROS_INFO("got cloud with %d points in %s",cloud_in.points.size(), cloud_in.header.frame_id.c_str() ); 00383 00384 pcl::PassThrough<Point> pass; 00385 pass.setInputCloud (cloud_in.makeShared()); 00386 pass.setFilterFieldName ("x"); 00387 pass.setFilterLimits (-0.35, 0.35); 00388 //pass.setFilterLimitsNegative (true); 00389 pass.filter (cloud); 00390 00391 00392 //get self mask 00393 // camera_self_filter::mask servicecall; 00394 // servicecall.request.header.frame_id = cloud.header.frame_id; 00395 // servicecall.request.header.stamp = cloud.header.stamp; 00396 // _self_mask_client.call(servicecall); 00397 // sensor_msgs::ImageConstPtr selfMaskPtr = boost::make_shared<sensor_msgs::Image>(servicecall.response.mask_image); 00398 // IplImage* ipl_self = _bridge.imgMsgToCv(selfMaskPtr, "passthrough"); 00399 // cv::Mat temp(ipl_self); 00400 // cv::Mat self_mask = temp.clone(); 00401 00402 //get all transforms 00403 00404 00405 tf::StampedTransform tf_realcam_in_base; 00406 00407 listener_.waitForTransform(base_frame, cloud_msg->header.frame_id, ros::Time(0), ros::Duration(5.0)); 00408 listener_.lookupTransform(base_frame, cloud_msg->header.frame_id, ros::Time(0), tf_realcam_in_base); 00409 cout<<"base_frame "<<base_frame<<endl; 00410 cout<<"cloud_msg->header.frame_id "<<cloud_msg->header.frame_id<<endl; 00411 00412 00413 00414 cout<<"tf_realcam_in_base"<<endl<<tf_realcam_in_base<<endl; 00415 00416 //transform cloud into baselink 00417 pcl::PointCloud<Point> cloud_in_virt_cam; 00418 00419 tf::Transform full_tf = tf_virtual_cam.inverse() * tf_virtual_cam_transl.inverse() * tf_realcam_in_base; 00420 00421 cout<<"full_tf"<<endl<<full_tf<<endl; 00422 00423 Eigen::Affine3d transform_eigen; 00424 tf::TransformTFToEigen(full_tf,transform_eigen ); 00425 Eigen::Matrix4d transform_eigen3(transform_eigen.matrix()); 00426 Eigen::Matrix4f transform_eigen3f = transform_eigen3.cast<float>(); 00427 pcl::transformPointCloud( cloud, cloud_in_virt_cam, transform_eigen3f ); 00428 00429 00430 00431 00432 00433 00434 cloud_in_virt_cam.header.frame_id = "virtual_cam_frame"; 00435 cloud_in_virt_cam.header.stamp = cloud.header.stamp; 00436 00437 // //set ROI 00438 // double distance = tf_gripper_left_in_base.getOrigin().getX(); 00439 // ROS_INFO("distance %d", distance); 00440 // roi_filter.setRoi(distance - _tolerance_x, distance+ _tolerance_x, 00441 // tf_gripper_right_in_base.getOrigin().getY() - _tolerance_y, tf_gripper_left_in_base.getOrigin().getY() + _tolerance_y, 00442 // tf_gripper_left_in_base.getOrigin().getZ() - _max_height_z, tf_gripper_left_in_base.getOrigin().getZ() + 0.03); 00443 // 00444 // pcl::PointCloud<Point> cloud_in_base_roi_filtered; 00445 // roi_filter.apply(cloud_in_base, cloud_in_base_roi_filtered); 00446 // 00447 // //transform cloud into camera_frame for projection 00448 // pcl::PointCloud<Point> cloud_in_cam_roi_filtered; 00449 // pcl_ros::transformPointCloud( _cam_info->header.frame_id, cloud_in_base_roi_filtered, cloud_in_cam_roi_filtered, listener_); 00450 // ROS_INFO("got cloud with %d after roi points",cloud_in_cam_roi_filtered.points.size() ); 00451 00452 00453 00454 00455 // DEBUG 00456 // Eigen::Vector4f min, max; 00457 // 00458 // pcl::getMinMax3D(cloud_in_virt_cam, min, max); 00459 // 00460 // ROS_INFO_STREAM("min max"<<min<<"\n max"<<max); 00461 00462 pass.setInputCloud (cloud_in_virt_cam.makeShared()); 00463 pass.setFilterFieldName ("z"); 00464 std::cerr<<table_height<<std::endl; 00465 pass.setFilterLimits (0.0, virtual_cam_z - this->table_height); //table height - 10cm 00466 //pass.setFilterLimitsNegative (true); 00467 pcl::PointCloud<Point> cloud_temp; 00468 00469 pass.filter (cloud_temp); 00470 cloud_in_virt_cam = cloud_temp; 00471 00472 00473 //estimate table plane 00474 coefficients = boost::shared_ptr<pcl::ModelCoefficients>(new pcl::ModelCoefficients()); 00475 pcl::PointIndices::Ptr inliers (new pcl::PointIndices); 00476 // Create the segmentation object 00477 pcl::SACSegmentation<Point> seg; 00478 // Optional 00479 seg.setOptimizeCoefficients (false); 00480 // Mandatory 00481 seg.setModelType (pcl::SACMODEL_PLANE); 00482 seg.setMethodType (pcl::SAC_RANSAC); 00483 seg.setDistanceThreshold (0.015); 00484 00485 seg.setInputCloud (cloud_in_virt_cam.makeShared ()); 00486 seg.segment (*inliers, *coefficients); 00487 00488 00489 std::cerr << "Model coefficients: " << coefficients->values[0] << " " 00490 << coefficients->values[1] << " " 00491 << coefficients->values[2] << " " 00492 << coefficients->values[3] << std::endl; 00493 00494 00495 00496 00497 00498 // pcl::io::savePCDFile("cloud_in_virt_cam.pcd", cloud_in_virt_cam); 00499 00500 // return 0; 00501 00502 //extract table 00503 pcl::PointCloud<Point> cloud_table_in_virt_cam; 00504 pcl::ExtractIndices<Point> extract; 00505 extract.setInputCloud (cloud_in_virt_cam.makeShared()); 00506 extract.setIndices (inliers); 00507 extract.setNegative (false); 00508 extract.filter (cloud_table_in_virt_cam); 00509 00510 //extract everything else 00511 pcl::PointCloud<Point> cloud_objects_in_virt_cam; 00512 extract.setNegative (true); 00513 extract.filter (cloud_objects_in_virt_cam); 00514 00515 00516 ROS_INFO("size table points %d size object points %d", cloud_table_in_virt_cam.points.size(), cloud_objects_in_virt_cam.points.size()); 00517 // pcl::io::savePCDFile("cloud_objects_in_virt_cam.pcd", cloud_objects_in_virt_cam); 00518 00519 00520 00521 //project 00522 00523 //all 00524 cv::Mat mask = cv::Mat::zeros(cv::Size(_cam_info->width, _cam_info->height), CV_8U); 00525 cv::Mat mask_cont = cv::Mat::zeros(cv::Size(_cam_info->width, _cam_info->height), CV_8U); 00526 00527 cv::Mat maskRGB = cv::Mat::zeros(cv::Size(_cam_info->width, _cam_info->height), CV_8UC3); 00528 ROS_INFO("picel_coords %f %f %f", cloud.points[0].x, cloud.points[0].y,cloud.points[0].z ); 00529 vector<Point, Eigen::aligned_allocator<Point> >::iterator iter; 00530 for (iter = cloud_in_virt_cam.points.begin(); iter != cloud_in_virt_cam.points.end(); ++iter){ 00531 Point& point = *iter; 00532 00533 if (isnan(point.x) || isnan(point.y) || isnan(point.z)) 00534 continue; 00535 cv::Point3d p3d(point.x, point.y, point.z); 00536 cv::Point2d p2d; 00537 _model.project3dToPixel(p3d, p2d); 00538 int x = round(p2d.x); 00539 int y = round(p2d.y); 00540 if((x>mask.cols-1) || (x<0) || (y>mask.rows-1) || (y<0)) 00541 continue; 00542 mask.at<unsigned char>(y, x) = 255; 00543 cv::circle(maskRGB, cv::Point(x,y), 3, cv::Scalar(point.b, point.g, point.r), -1); 00544 //DEBUG 00545 // maskRGB.at<unsigned char>(y, 3 * x) = point.b; 00546 // maskRGB.at<unsigned char>(y, 3 * x + 1) = point.g; 00547 // maskRGB.at<unsigned char>(y, 3 * x + 2) = point.r; 00548 } 00549 00550 //objects 00551 cv::Mat mask_objects = cv::Mat::zeros(cv::Size(_cam_info->width, _cam_info->height), CV_8U); 00552 for (iter = cloud_objects_in_virt_cam.points.begin(); iter != cloud_objects_in_virt_cam.points.end(); ++iter){ 00553 Point& point = *iter; 00554 00555 if (isnan(point.x) || isnan(point.y) || isnan(point.z)) 00556 continue; 00557 cv::Point3d p3d(point.x, point.y, point.z); 00558 cv::Point2d p2d; 00559 _model.project3dToPixel(p3d, p2d); 00560 int x = round(p2d.x); 00561 int y = round(p2d.y); 00562 if((x>mask_objects.cols-1) || (x<0) || (y>mask_objects.rows-1) || (y<0)) 00563 continue; 00564 mask_objects.at<unsigned char>(y, x) = 255; 00565 cv::circle(maskRGB, cv::Point(x,y), 3, cv::Scalar(point.b, point.g, point.r), -1); 00566 //DEBUG 00567 // maskRGB.at<unsigned char>(y, 3 * x) = point.b; 00568 // maskRGB.at<unsigned char>(y, 3 * x + 1) = point.g; 00569 // maskRGB.at<unsigned char>(y, 3 * x + 2) = point.r; 00570 } 00571 00572 //filter object parts with normals aligned with table normal 00573 00574 Eigen::Vector3f table_normal; 00575 table_normal << coefficients->values[0], coefficients->values[1], coefficients->values[2]; 00576 table_normal.normalize(); 00577 00578 cv::Mat mask_object_tops = cv::Mat::zeros(cv::Size(_cam_info->width, _cam_info->height), CV_8U); 00579 00580 pcl::NormalEstimation<Point, pcl::Normal> ne; 00581 ne.setInputCloud (cloud_objects_in_virt_cam.makeShared()); 00582 00583 pcl::KdTreeFLANN<Point>::Ptr tree (new pcl::KdTreeFLANN<Point> ()); 00584 ne.setSearchMethod (tree); 00585 pcl::PointCloud<pcl::Normal> cloud_normals; 00586 ne.setRadiusSearch (0.01); 00587 ne.compute (cloud_normals); 00588 00589 00590 pcl::PointCloud<pcl::Normal>::iterator normal_iter = cloud_normals.points.begin(); 00591 for (iter = cloud_objects_in_virt_cam.points.begin(); iter != cloud_objects_in_virt_cam.points.end(); ++iter, ++normal_iter){ 00592 Point& point = *iter; 00593 pcl::Normal& normal = *normal_iter; 00594 float dot_prod = std::abs(table_normal.dot(normal.getNormalVector3fMap())); 00595 //DEBUG 00596 // std::cout<<" table normal \n"<<table_normal<<"\n object normal \n"<<normal.getNormalVector3fMap(); 00597 // printf("\n dp %f dp_thresh %f \n", dot_prod, dot_threshold); 00598 if (dot_prod < dot_threshold){ 00599 continue; 00600 } 00601 00602 if (isnan(point.x) || isnan(point.y) || isnan(point.z)) 00603 continue; 00604 cv::Point3d p3d(point.x, point.y, point.z); 00605 cv::Point2d p2d; 00606 _model.project3dToPixel(p3d, p2d); 00607 int x = round(p2d.x); 00608 int y = round(p2d.y); 00609 if((x>mask_object_tops.cols-1) || (x<0) || (y>mask_object_tops.rows-1) || (y<0)) 00610 continue; 00611 mask_object_tops.at<unsigned char>(y, x) = 255; 00612 cv::circle(maskRGB, cv::Point(x,y), 3, cv::Scalar(point.b, point.g, point.r), -1); 00613 //DEBUG 00614 // maskRGB.at<unsigned char>(y, 3 * x) = point.b; 00615 // maskRGB.at<unsigned char>(y, 3 * x + 1) = point.g; 00616 // maskRGB.at<unsigned char>(y, 3 * x + 2) = point.r; 00617 } 00618 00619 00620 00621 00622 00623 00624 //table 00625 00626 00627 cv::Mat mask_table = cv::Mat::zeros(cv::Size(_cam_info->width, _cam_info->height), CV_8U); 00628 for (iter = cloud_table_in_virt_cam.points.begin(); iter != cloud_table_in_virt_cam.points.end(); ++iter){ 00629 Point& point = *iter; 00630 00631 if (isnan(point.x) || isnan(point.y) || isnan(point.z)) 00632 continue; 00633 cv::Point3d p3d(point.x, point.y, point.z); 00634 cv::Point2d p2d; 00635 _model.project3dToPixel(p3d, p2d); 00636 int x = round(p2d.x); 00637 int y = round(p2d.y); 00638 if((x>mask_table.cols-1) || (x<0) || (y>mask_table.rows-1) || (y<0)) 00639 continue; 00640 mask_table.at<unsigned char>(y, x) = 127; 00641 cv::circle(maskRGB, cv::Point(x,y), 3, cv::Scalar(point.b, point.g, point.r), -1); 00642 //DEBUG 00643 // maskRGB.at<unsigned char>(y, 3 * x) = point.b; 00644 // maskRGB.at<unsigned char>(y, 3 * x + 1) = point.g; 00645 // maskRGB.at<unsigned char>(y, 3 * x + 2) = point.r; 00646 } 00647 00648 00649 00650 #if X_OUTPUT 00651 00652 cv::namedWindow("test", 1); 00653 cv::waitKey(); 00654 00655 cv::imshow("test", mask); 00656 00657 cv::waitKey(); 00658 00659 cv::imshow("test", mask_table); 00660 00661 std::cerr<<"mask table"<<std::endl; 00662 00663 cv::waitKey(); 00664 00665 cv::imshow("test", mask_objects); 00666 00667 cv::waitKey(); 00668 00669 cv::imshow("test", mask_object_tops); 00670 00671 std::cerr<<"before morphology"<<std::endl; 00672 00673 cv::waitKey(); 00674 00675 00676 //DEBUG 00677 00678 //cv::imshow("test", mask); 00679 00680 // cv::namedWindow("testrgb", 1); 00681 // cv::imshow("testrgb", maskRGB); 00682 #endif 00683 00684 // BUG MAKE PARAM 00685 cv::morphologyEx(mask_object_tops,mask_object_tops,CV_MOP_CLOSE , getStructuringElement(cv::MORPH_RECT, cv::Size(3,3)), cv::Point(-1,-1), this->morphology_param); 00686 // it can be done in other way: 00687 // cv::dilate(mask_object_tops,mask_object_tops,getStructuringElement(cv::MORPH_RECT, cv::Size(5,5)) ); 00688 // cv::erode(mask_object_tops, mask_object_tops, cv::Mat(), cv::Point(-1, -1), 3 ); 00689 00690 00691 mask = cv::max(mask_table, mask_object_tops); 00692 00693 #if X_OUTPUT 00694 00695 00696 cv::imshow("test", mask_object_tops); 00697 cv::waitKey(); 00698 #endif 00699 //DEBUG 00700 // cv::dilate(self_mask,self_mask,getStructuringElement(cv::MORPH_RECT, cv::Size(5,5)) ); 00701 //#if X_OUTPUT 00702 // cv::imshow("test", self_mask); 00703 // cv::waitKey(); 00704 //#endif 00705 // cv::bitwise_and(mask, self_mask, mask); 00706 00707 00708 //search for largest contour 00709 00710 std::vector<std::vector<cv::Point> > contours; 00711 std::vector<cv::Vec4i> hierarchy; 00712 cv::findContours(mask_object_tops, contours, hierarchy, CV_RETR_CCOMP, 00713 CV_CHAIN_APPROX_SIMPLE); 00714 00715 if (hierarchy.empty()){ 00716 ROS_ERROR("no contours found"); 00717 return false; 00718 } 00719 00720 bool found = false; 00721 int max_contour = 0; 00722 double max_contour_area = 0; 00723 00724 const double contour_min_area_ = 100; 00725 for (int i=0; i < hierarchy.size(); i = hierarchy[i][0]) 00726 { 00727 double contour_area = cv::contourArea(cv::Mat(contours[i])); 00728 if (contour_area > contour_min_area_ && contour_area > max_contour_area) 00729 { 00730 found = true; 00731 max_contour_area = contour_area; 00732 max_contour = i; 00733 } 00734 } 00735 00736 if (found) 00737 { 00738 00739 cv::drawContours(mask_cont, contours, max_contour, cv::Scalar(255), CV_FILLED, 00740 8, hierarchy, 0); 00741 00742 00743 00744 } 00745 else 00746 cout<<" not found"<<endl; 00747 00748 #if X_OUTPUT 00749 cv::imshow("test", mask_cont); 00750 cv::waitKey(); 00751 #endif 00752 00753 00754 cv::imwrite("test.png", mask_cont); 00755 00756 00757 IplImage ipl_image = mask_cont; 00758 sensor_msgs::ImagePtr img_msg = sensor_msgs::CvBridge::cvToImgMsg(&ipl_image); 00759 img_msg->header.frame_id = _cam_info->header.frame_id; 00760 img_msg->header.stamp = cloud.header.stamp; 00761 00762 topview = mask_cont; 00763 00764 return true; 00765 00766 00767 00768 } 00769 00770 // function to get the corners from another service 00771 00772 bool getCornersToPush(cv::Mat& topview, pr2_interactive_segmentation::cornerFind::Response& res){ 00773 pr2_interactive_segmentation::cornerFind::Request req; 00774 IplImage temp(topview); 00775 sensor_msgs::ImagePtr imgptr = sensor_msgs::CvBridge::cvToImgMsg(&temp); 00776 req.image = *imgptr; 00777 _corner_finder.call(req, res); 00778 00779 00780 return true; 00781 } 00782 00783 00784 bool get3dPoints(const pr2_interactive_segmentation::cornerFind::Response& res, pcl::PointCloud<pcl::PointNormal>& grasp_points){ 00785 Eigen::Vector3f table_normal(coefficients->values[0], coefficients->values[1], coefficients->values[2]); 00786 00787 //create Points 00788 grasp_points.reserve(res.corner.size()); 00789 grasp_points.width = res.corner.size(); 00790 grasp_points.height = 1; 00791 for (int i = 0; i< res.corner.size() ; ++i){ 00792 cv::Point2d p2d(res.corner[i].x, res.corner[i].y); 00793 cv::Point3d p3d; 00794 00795 // get the ray of the pinhole camera 00796 _model.projectPixelTo3dRay(p2d, p3d); 00797 Eigen::Vector3f ray(p3d.x, p3d.y, p3d.z); 00798 00799 // distance to the corner to push from the virtual camera 00800 float t = -1.0 * coefficients->values[3] / (table_normal.dot(ray)); 00801 00802 // vector to the corner 00803 Eigen::Vector3f intersec = t * ray; 00804 00805 // do the same for the next point that is the point + push 00806 00807 p2d = cv::Point2d(res.corner[i].x + this->push_distance * res.push_direction[i].x, res.corner[i].y + this->push_distance * res.push_direction[i].y); 00808 _model.projectPixelTo3dRay(p2d, p3d); 00809 ray = Eigen::Vector3f(p3d.x, p3d.y, p3d.z); 00810 t = -1.0 * coefficients->values[3] / (table_normal.dot(ray)); 00811 00812 // vector between the corner and the corner + push direction 00813 Eigen::Vector3f normal = t * ray - intersec; 00814 normal.normalize(); 00815 00816 // put the corner with the direction of push into the point cloud 00817 pcl::PointNormal p; 00818 p.getArray3fMap() = intersec; 00819 //DEBUG 00820 //cout<<"intersec"<<endl<<intersec<<endl; 00821 00822 p.getNormalVector3fMap() = normal; 00823 grasp_points.push_back(p); 00824 00825 } 00826 00827 00828 // transform it to the base link frame 00829 Eigen::Affine3d transform_eigen; 00830 tf::Transform tf_full = tf_virtual_cam_transl * tf_virtual_cam; 00831 tf::TransformTFToEigen(tf_full ,transform_eigen ); 00832 Eigen::Matrix4d transform_eigen3(transform_eigen.matrix()); 00833 Eigen::Matrix4f transform_eigen3f = transform_eigen3.cast<float>(); 00834 00835 pcl::PointCloud<pcl::PointNormal> grasp_points_in_base; 00836 pcl::transformPointCloudWithNormals( grasp_points, grasp_points_in_base, transform_eigen3f ); 00837 00838 grasp_points_in_base.header.frame_id = base_frame; 00839 grasp_points_in_base.header.stamp = ros::Time::now(); 00840 00841 grasp_points = grasp_points_in_base; 00842 00843 00844 return true; 00845 } 00846 00847 00848 bool get3dRandomPoint(randomPoint& random, pcl::PointCloud<pcl::PointNormal>& grasp_points){ 00849 Eigen::Vector3f table_normal(coefficients->values[0], coefficients->values[1], coefficients->values[2]); 00850 00851 //create Points 00852 grasp_points.width = 1; 00853 grasp_points.height = 1; 00854 00855 cv::Point2d p2d(random.push_point.x,random.push_point.y); 00856 cv::Point3d p3d; 00857 00858 // get the ray of the pinhole camera 00859 _model.projectPixelTo3dRay(p2d, p3d); 00860 Eigen::Vector3f ray(p3d.x, p3d.y, p3d.z); 00861 00862 // distance to the corner to push from the virtual camera 00863 float t = -1.0 * coefficients->values[3] / (table_normal.dot(ray)); 00864 00865 // vector to the corner 00866 Eigen::Vector3f intersec = t * ray; 00867 00868 // do the same for the next point that is the point + push 00869 int x=random.push_point.x; 00870 float xdirection=random.direction[0]; 00871 int y=random.push_point.y; 00872 float ydirection=random.direction[1]; 00873 00874 p2d = cv::Point2d(x+this->push_distance*xdirection,y+this->push_distance*ydirection); 00875 _model.projectPixelTo3dRay(p2d, p3d); 00876 ray = Eigen::Vector3f(p3d.x, p3d.y, p3d.z); 00877 t = -1.0 * coefficients->values[3] / (table_normal.dot(ray)); 00878 00879 // vector between the corner and the corner + push direction 00880 Eigen::Vector3f normal = t * ray - intersec; 00881 normal.normalize(); 00882 00883 // put the corner with the direction of push into the point cloud 00884 pcl::PointNormal p; 00885 p.getArray3fMap() = intersec; 00886 //DEBUG 00887 //cout<<"intersec"<<endl<<intersec<<endl; 00888 00889 p.getNormalVector3fMap() = normal; 00890 grasp_points.push_back(p); 00891 00892 00893 00894 // transform it to the base link frame 00895 Eigen::Affine3d transform_eigen; 00896 tf::Transform tf_full = tf_virtual_cam_transl * tf_virtual_cam; 00897 tf::TransformTFToEigen(tf_full ,transform_eigen ); 00898 Eigen::Matrix4d transform_eigen3(transform_eigen.matrix()); 00899 Eigen::Matrix4f transform_eigen3f = transform_eigen3.cast<float>(); 00900 00901 pcl::PointCloud<pcl::PointNormal> grasp_points_in_base; 00902 pcl::transformPointCloudWithNormals( grasp_points, grasp_points_in_base, transform_eigen3f ); 00903 00904 grasp_points_in_base.header.frame_id = base_frame; 00905 grasp_points_in_base.header.stamp = ros::Time::now(); 00906 00907 grasp_points = grasp_points_in_base; 00908 00909 00910 return true; 00911 } 00912 00913 00914 00915 // to get the 4 x 4 matrix of the pose 00916 bool convertPointNormalstoGraps(pcl::PointCloud<pcl::PointNormal>& cloud, std::vector<Eigen::Matrix4f>& poses){ 00917 poses.reserve(cloud.points.size()); 00918 BOOST_FOREACH(pcl::PointNormal& p, cloud.points){ 00919 Eigen::Matrix4f pose; 00920 // position 00921 pose.block<3,1>(0,3) = p.getVector3fMap(); 00922 // x rotation 00923 pose.block<3,1>(0,0) = p.getNormalVector3fMap(); 00924 // get y direction if the dot product is 1 then take the other one 00925 Eigen::Vector3f orth(0,1,0); 00926 if ( std::abs(orth.dot(pose.block<3,1>(0,0))) > 0.9 ){ 00927 orth = Eigen::Vector3f(1,0,0); 00928 } 00929 // compute the z direction 00930 pose.block<3,1>(0,2) = orth.cross(pose.block<3,1>(0,0)); 00931 pose.block<3,1>(0,1) = pose.block<3,1>(0,2).cross(pose.block<3,1>(0,0)); 00932 poses.push_back(pose); 00933 } 00934 00935 return true; 00936 00937 } 00938 00939 00940 00941 00942 00943 }; 00944 00945 int main(int argc, char** argv){ 00946 00947 ros::init(argc, argv, "poke_point_finder_node"); 00948 00949 PokePointFinder hcs; 00950 ros::spin(); 00951 00952 return 0; 00953 } 00954 00955 00956