tabletop_segmentor.cpp
Go to the documentation of this file.
00001 #include "hrl_table_detect/tabletop_segmentor.h"
00002 using namespace std;
00003 
00004 namespace hrl_table_detect {
00005 
00006     TabletopSegmentor::TabletopSegmentor() : img_trans(nh) {
00007     }
00008 
00009     
00010     void TabletopSegmentor::onInit() {
00012         nh_priv = ros::NodeHandle("~");
00013         bool run_service;
00014         nh_priv.param<bool>("run_service", run_service, false);
00015         nh_priv.param<double>("scan_width", maxy, 1.5); miny = -maxy;
00016         nh_priv.param<double>("min_scan_depth", minx, 0.3);
00017         nh_priv.param<double>("max_scan_depth", maxx, 3.0);
00018         nh_priv.param<double>("min_table_height", minz, 0.5);
00019         nh_priv.param<double>("max_table_height", maxz, 1.0);
00020         nh_priv.param<double>("height_image_res", resolution, 200);
00021         nh_priv.param<double>("inlier_magnitude", inlier_magnitude, 200);
00022         nh_priv.param<int32_t>("num_edge_dilate", num_edge_dilate, 1);
00023         nh_priv.param<int32_t>("num_closes", num_closes, 1);
00024         nh_priv.param<double>("degree_bins", degree_bins, 0.3);
00025         nh_priv.param<double>("hough_thresh", hough_thresh, 30); hough_thresh *= resolution;
00026         nh_priv.param<double>("theta_gran", theta_gran, 1); theta_gran *= CV_PI/180;
00027         nh_priv.param<double>("rho_gran", rho_gran, 0.1); rho_gran *= resolution;
00028         nh_priv.param<double>("xgran", xgran, 0.1); xgran *= resolution;
00029         nh_priv.param<double>("ygran", ygran, 0.1); ygran *= resolution;
00030         nh_priv.param<double>("obj_min_area", obj_min_area, 0.02); obj_min_area *= resolution;
00031         imgx = (maxx-minx)*resolution;
00032         imgy = (maxy-miny)*resolution;
00034 
00035         obj_poses_found = false;
00036         height_img_sum = cv::Mat::zeros(imgx, imgy, CV_32F);
00037         height_img_count = cv::Mat::zeros(imgx, imgy, CV_32F);
00038         height_img_max = cv::Mat::zeros(imgx, imgy, CV_8U);
00039 
00040         //pc_pub = nh.advertise<pcl::PointCloud<pcl::PointXYZRGB> >("/table_detection_vis", 1);
00041         height_pub = img_trans.advertise("/obj_height_image", 1);
00042         obj_arr_pub = nh.advertise<geometry_msgs::PoseArray>("/table_object_poses", 1);
00043         nh_priv = ros::NodeHandle("~");
00044         if(run_service) {
00045             table_detect_start = nh.advertiseService("/obj_segment_start", &TabletopSegmentor::startCallback, this);
00046             table_detect_stop = nh.advertiseService("/obj_segment_stop", &TabletopSegmentor::stopCallback, this);
00047             table_detect_inst = nh.advertiseService("/obj_segment_inst", &TabletopSegmentor::instCallback, this);
00048         }
00049         else
00050             pc_sub = nh.subscribe("/kinect_head/rgb/points", 1, &TabletopSegmentor::pcCallback, this);
00051         ros::Duration(1.0).sleep();
00052     }
00053 
00054     bool TabletopSegmentor::startCallback(hrl_table_detect::DetectTableStart::Request& req, 
00055                                        hrl_table_detect::DetectTableStart::Response& resp) {
00056         obj_poses_found = false;
00057         height_img_sum = cv::Mat::zeros(imgx, imgy, CV_32F);
00058         height_img_count = cv::Mat::zeros(imgx, imgy, CV_32F);
00059         height_img_max = cv::Mat::zeros(imgx, imgy, CV_8U);
00060         pc_sub = nh.subscribe("/kinect_head/rgb/points", 1, &TabletopSegmentor::pcCallback, this);
00061         return true;
00062     }
00063 
00064     bool TabletopSegmentor::stopCallback(hrl_table_detect::DetectTableStop::Request& req, 
00065                                        hrl_table_detect::DetectTableStop::Response& resp) {
00066         pc_sub.shutdown();
00067         resp.grasp_points = obj_poses;
00068         return true;
00069     }
00070 
00071     bool TabletopSegmentor::instCallback(hrl_table_detect::DetectTableInst::Request& req, 
00072                                        hrl_table_detect::DetectTableInst::Response& resp) {
00073         obj_poses_found = false;
00074         height_img_sum = cv::Mat::zeros(imgx, imgy, CV_32F);
00075         height_img_count = cv::Mat::zeros(imgx, imgy, CV_32F);
00076         height_img_max = cv::Mat::zeros(imgx, imgy, CV_8U);
00077         pc_sub = nh.subscribe("/kinect_head/rgb/points", 1, &TabletopSegmentor::pcCallback, this);
00078         double begin_time = ros::Time::now().toSec();
00079         double now = begin_time;
00080         ros::Rate r(100);
00081         while(ros::ok() && now - begin_time < req.block_time) {
00082             ros::spinOnce();
00083             now = ros::Time::now().toSec();
00084             r.sleep();
00085         }
00086         pc_sub.shutdown();
00087         resp.grasp_points = obj_poses;
00088         return true;
00089     }
00090 
00091     bool compind(uint32_t a, uint32_t b, vector<float> v) { return v[a] < v[b]; }
00092 
00093     void convCvBox2DPoly(CvBox2D& box, CvPoint**& pts, int*& npts) {
00094         pts = new CvPoint*[1]; pts[0] = new CvPoint[4];
00095         float x = box.center.x, y = box.center.y;
00096         float x1 = box.size.height*cos(box.angle-CV_PI/2), y1 = -box.size.height*sin(box.angle-CV_PI/2);
00097         float x2 = box.size.width*cos(box.angle), y2 = -box.size.width*sin(box.angle);
00098         pts[0][0].x = x+x1+x2; pts[0][0].y = y+y1+y2;
00099         pts[0][1].x = x-x1+x2; pts[0][1].y = y-y1+y2;
00100         pts[0][2].x = x-x1-x2; pts[0][2].y = y-y1-y2;
00101         pts[0][3].x = x+x1-x2; pts[0][3].y = y+y1-y2;
00102         pts[0][4].x = x+x1+x2; pts[0][4].y = y+y1+y2;
00103         npts = new int[1]; npts[0] = 5;
00104     }
00105 
00106     void drawCvBox2D(IplImage& img, CvBox2D& box, cv::Scalar color, int width=1) {
00107         CvPoint** rpts; int* npts;
00108         convCvBox2DPoly(box, rpts, npts);
00109         cvPolyLine(&img, rpts, npts, 1, 1, color, width);
00110         delete[] rpts[0]; delete[] rpts; delete[] npts;
00111     }
00112 
00113     void fillCvBox2D(IplImage& img, CvBox2D& box, cv::Scalar color) {
00114         CvPoint** rpts; int* npts;
00115         convCvBox2DPoly(box, rpts, npts);
00116         cvFillPoly(&img, rpts, npts, 1, color);
00117         delete[] rpts[0]; delete[] rpts; delete[] npts;
00118     }
00119 
00120     void TabletopSegmentor::pcCallback(sensor_msgs::PointCloud2::ConstPtr pc_msg) {
00121         if(!pc_lock.try_lock())
00122             return;
00123 
00124         pcl::PointCloud<pcl::PointXYZRGB> pc_full, pc_full_frame;
00125         pcl::fromROSMsg(*pc_msg, pc_full);
00126         string base_frame("/base_link");
00127         ros::Time now = ros::Time::now();
00128         tf_listener.waitForTransform(pc_msg->header.frame_id, base_frame, now, ros::Duration(3.0));
00129         pcl_ros::transformPointCloud(base_frame, pc_full, pc_full_frame, tf_listener);
00130         // pc_full_frame is in torso lift frame
00131 
00132         cv::Mat cur_height_img = cv::Mat::zeros(imgx, imgy, CV_8U);
00133         
00134         BOOST_FOREACH(const pcl::PointXYZRGB& pt, pc_full_frame.points) {
00135             if(pt.x != pt.x || pt.y != pt.y || pt.z != pt.z)
00136                 continue;
00137             int32_t x, y, z;
00138             x = (pt.x - minx)/(maxx-minx) * imgx;
00139             y = (pt.y - miny)/(maxy-miny) * imgy;
00140             z = (pt.z - minz)/(maxz-minz) * 256;
00141             if(x < 0 || y < 0) continue; 
00142             if(x >= imgx || y >= imgy) continue;
00143             if(z < 0 || z >= 256) continue;
00144             if(cur_height_img.at<uint8_t>(x, y) == 0 || cur_height_img.at<uint8_t>(x, y) < (uint8_t) z)
00145                 cur_height_img.at<uint8_t>(x, y) = (uint8_t) z;
00146         }
00147         cv::max(height_img_max, cur_height_img, height_img_max);
00148         cv::Mat cur_height_img_flt;
00149         cur_height_img.convertTo(cur_height_img_flt, CV_32F);
00150         height_img_sum += cur_height_img_flt;
00151         cv::Mat cur_count(imgx, imgy, CV_8U);
00152         cur_count = (cur_height_img > 0) / 255;
00153         cv::Mat cur_count_flt(imgx, imgy, CV_32F);
00154         cur_count.convertTo(cur_count_flt, CV_32F);
00155         height_img_count += cur_count_flt;
00156         cv::Mat height_img_avg_flt = height_img_sum / height_img_count;
00157         cv::Mat height_img_avg(imgx, imgy, CV_8U);
00158         height_img_avg_flt.convertTo(height_img_avg, CV_8U);
00159         height_img_avg = height_img_max;
00160 
00161         cv::Mat height_hist(256, 1, CV_32F, cv::Scalar(0));
00162         for(uint32_t x=0;x<imgx;x++)
00163             for(uint32_t y=0;y<imgy;y++) {
00164                 if(height_img_avg.at<uint8_t>(x,y) == 255)
00165                     height_img_avg.at<uint8_t>(x,y) = 0;
00166                 if(height_img_avg.at<uint8_t>(x,y) != 0) {
00167                     height_hist.at<float>(height_img_avg.at<uint8_t>(x,y), 0)++;
00168                 }
00169             }
00171         uint32_t gfiltlen = 25;
00172         float stddev = 256/(maxz-minz) * 0.015;
00173         cv::Mat gauss_filt(gfiltlen, 1, CV_32F, cv::Scalar(0));
00174         for(uint32_t i=0;i<gfiltlen;i++)
00175             gauss_filt.at<float>(i,0) = 0.39894 / stddev * std::exp(-(i-((float)gfiltlen)/2)*(i-((float)gfiltlen)/2)/(2*stddev*stddev));
00176         //cout << gauss_filt;
00177         uint32_t maxval = 0, maxidx = 0;
00178         for(uint32_t i=0;i<256-gfiltlen;i++) {
00179             uint32_t sum = 0;
00180             for(uint32_t j=0;j<gfiltlen;j++) 
00181                 sum += height_hist.at<float>(i+j,0) * gauss_filt.at<float>(j,0);
00182             if(sum > maxval && i != 0) {
00183                 maxval = sum;
00184                 maxidx = i+gfiltlen/2;
00185             }
00186         }
00187         int32_t table_height = ((int32_t)maxidx);
00188         //printf("%d %d, ", maxval, maxidx);
00190         cv::Mat height_img_thresh(imgx, imgy, CV_8U);
00191         height_img_thresh = height_img_avg.clone();
00192         for(uint32_t x=0;x<imgx;x++)
00193             for(uint32_t y=0;y<imgy;y++) {
00194                 if(std::fabs(table_height - ((int32_t)height_img_thresh.at<uint8_t>(x,y))) < stddev*2)
00195                     height_img_thresh.at<uint8_t>(x,y) = 255;
00196                 else
00197                     height_img_thresh.at<uint8_t>(x,y) = 0;
00198             }
00200         IplImage height_img_thresh_ipl = height_img_thresh;
00201         IplConvKernel* element = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT);
00202         cvMorphologyEx(&height_img_thresh_ipl, &height_img_thresh_ipl, NULL, element, CV_MOP_CLOSE, num_closes);
00203         //cvMorphologyEx(&height_img_thresh, &height_img_thresh, NULL, element, CV_MOP_OPEN, 2);
00204 
00205         cv::Mat height_img_thresh_blob = height_img_thresh.clone();
00206         IplImage blob_img = height_img_thresh_blob;
00207         CBlobResult blobs = CBlobResult(&blob_img, NULL, 0);
00208         //blobs.Filter(blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, 10);
00209         CBlob biggestblob;
00210         blobs.GetNthBlob(CBlobGetArea(), 0, biggestblob);
00211         cv::Mat table_blob(imgx, imgy, CV_8U, cv::Scalar(0)); IplImage table_blob_img = table_blob;
00212         biggestblob.FillBlob(&table_blob_img, cv::Scalar(150));
00213         //drawCvBox2D(blob_img, table_roi, cv::Scalar(50), 1);
00214         CvBox2D table_roi = biggestblob.GetEllipse(); table_roi.angle *= CV_PI/180;
00215         cv::Mat table_hull(imgx, imgy, CV_8U, cv::Scalar(0));
00216         IplImage hull_img = table_hull;
00217         fillCvBox2D(hull_img, table_roi, cv::Scalar(255));
00218         //printf("Cvbox: %f, %f, %f, %f, %f\n", table_roi.center.x, table_roi.center.y, table_roi.size.width, table_roi.size.height, table_roi.angle);
00219 
00220         //cv::Mat height_morph(imgx, imgy, CV_8U, cv::Scalar(0));
00221         //cv::Mat tmp_img(imgx, imgy, CV_8U, cv::Scalar(0));
00222         //IplImage t1 = height_img_thresh; IplImage  = height_morph;
00223 
00224         cv::Mat above_table(imgx, imgy, CV_8U);
00225         bitwise_and(height_img_max > table_height + stddev*2, table_hull, above_table);
00226         IplImage above_table_img = above_table;
00227 
00228         CBlobResult obj_blobs = CBlobResult(&above_table_img, NULL, 0);
00229         obj_blobs.Filter(obj_blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, obj_min_area);
00230         CBlob cur_obj_blob;
00231         vector<float> obj_cents_x, obj_cents_y, obj_cents_r, obj_areas, obj_dists;
00232         vector<uint32_t> obj_inds;
00233         for(int i=0;i<obj_blobs.GetNumBlobs();i++) {
00234             obj_blobs.GetNthBlob(CBlobGetArea(), i, cur_obj_blob);
00235             CvBox2D obj_box = cur_obj_blob.GetEllipse();
00236             obj_cents_x.push_back(obj_box.center.x);
00237             obj_cents_y.push_back(obj_box.center.y);
00238             obj_cents_r.push_back(obj_box.angle * CV_PI/180);
00239             obj_areas.push_back(cur_obj_blob.Area());
00240             obj_dists.push_back((obj_box.center.x-imgx/2)*(obj_box.center.x-imgx/2)+obj_box.center.y*obj_box.center.y);
00241             obj_inds.push_back(i);
00242         }
00243         boost::function<bool(uint32_t, uint32_t)> sortind = boost::bind(&compind, _1, _2, obj_dists);
00244         sort(obj_inds.begin(), obj_inds.end(), sortind);
00245 
00246         obj_poses.poses.clear();
00247         for(uint32_t i=0;i<obj_inds.size();i++) {
00248             float posey = obj_cents_x[obj_inds[i]], posex = obj_cents_y[obj_inds[i]];
00249             float poser = -obj_cents_r[obj_inds[i]] + 3*CV_PI/2;
00250             geometry_msgs::Pose cpose;
00251             cpose.position.x = posex/imgx*(maxx-minx) + minx;
00252             cpose.position.y = posey/imgy*(maxy-miny) + miny;
00253             cpose.position.z = table_height/256.0*(maxz-minz) + minz;
00254             btMatrix3x3 quatmat; btQuaternion quat;
00255             quatmat.setEulerZYX(poser, 0 , 0);
00256             quatmat.getRotation(quat);
00257             cpose.orientation.x = quat.x(); cpose.orientation.y = quat.y();
00258             cpose.orientation.z = quat.z(); cpose.orientation.w = quat.w();
00259             CvPoint centerpt; centerpt.y = posex; centerpt.x = posey;
00260             printf("[%d](%f, %f, area: %f)\n", i, posex, posey, obj_areas[obj_inds[i]]);
00261             IplImage height_img_max_ipl = height_img_max;
00262             cvCircle(&height_img_max_ipl, centerpt, 3, cv::Scalar(200), 2);
00263             obj_poses.poses.push_back(cpose);
00264         }
00265         obj_poses.header.stamp = ros::Time::now();
00266         obj_poses.header.frame_id = base_frame;
00267         obj_arr_pub.publish(obj_poses);
00268 
00269         cv_bridge::CvImage cvb_height_img;
00270         //cvb_height_img.image = height_img_avg;
00271         //cvb_height_img.image = height_img_max;
00272         //cvb_height_img.image = height_morph;
00273         //cvb_height_img.image = obj_img;
00274         //cvb_height_img.image = height_img_thresh_blob;
00275         //cvb_height_img.image = table_blob;
00276         //cvb_height_img.image = height_img_thresh;
00277         cvb_height_img.image = above_table;
00278         //cvb_height_img.image = table_edge;
00279         cvb_height_img.header.stamp = ros::Time::now();
00280         cvb_height_img.header.frame_id = base_frame;
00281         cvb_height_img.encoding = enc::MONO8;
00282         height_pub.publish(cvb_height_img.toImageMsg());
00283         pc_full_frame.header.stamp = ros::Time::now();
00284         pc_full_frame.header.frame_id = base_frame;
00285         //pc_pub.publish(pc_full_frame);
00286 
00287         if(obj_poses.poses.size() > 0)
00288             obj_poses_found = true;
00289 
00290         //delete element;
00291         pc_lock.unlock();
00292     }
00293 
00294 };
00295 
00296 using namespace hrl_table_detect;
00297 
00298 int main(int argc, char **argv)
00299 {
00300     ros::init(argc, argv, "tabletop_segmentation");
00301     TabletopSegmentor ta;
00302     ta.onInit();
00303     ros::spin();
00304     return 0;
00305 }


hrl_table_detect
Author(s): kelsey
autogenerated on Wed Nov 27 2013 12:15:26