tabletop_detector.cpp
Go to the documentation of this file.
00001 #include "hrl_object_fetching/tabletop_detector.h"
00002 using namespace std;
00003 
00004 namespace hrl_object_fetching {
00005 
00006     TabletopDetector::TabletopDetector() : img_trans(nh) {
00007     }
00008 
00009     
00010     void TabletopDetector::onInit() {
00011         pc_pub = nh.advertise<pcl::PointCloud<pcl::PointXYZRGB> >("/table_detection_vis", 1);
00012         height_pub = img_trans.advertise("/height_image", 1);
00013         pose_arr_pub = nh.advertise<geometry_msgs::PoseArray>("/table_approach_poses", 1);
00014         nh_priv = ros::NodeHandle("~");
00015         bool run_service;
00016         nh_priv.param<bool>("run_service", run_service, false);
00017         if(run_service)
00018             table_detect_service = nh.advertiseService("/table_detect", &TabletopDetector::srvCallback, this);
00019         else
00020             pc_sub = nh.subscribe("/kinect_head/rgb/points", 1, &TabletopDetector::pcCallback, this);
00021         ros::Duration(1.0).sleep();
00022     }
00023 
00024     bool TabletopDetector::srvCallback(hrl_object_fetching::DetectTable::Request& req, 
00025                                        hrl_object_fetching::DetectTable::Response& resp) {
00026         pc_sub = nh.subscribe("/kinect_head/rgb/points", 1, &TabletopDetector::pcCallback, this);
00027         grasp_points_found = false;
00028         while(ros::ok()) {
00029             ros::spinOnce();
00030             if(grasp_points_found) {
00031                 resp.grasp_points = grasp_points;
00032                 pc_sub.shutdown();
00033                 return true;
00034             }
00035             ros::Duration(0.1).sleep();
00036         }
00037         return false;
00038     }
00039 
00040     bool compind(int a, int b, vector<float> v) { return std::fabs(v[a]-CV_PI/2) < std::fabs(v[b]-CV_PI/2); }
00041 
00042     void TabletopDetector::pcCallback(sensor_msgs::PointCloud2::ConstPtr pc_msg) {
00043 
00044         pcl::PointCloud<pcl::PointXYZRGB> pc_full, pc_full_frame;
00045         pcl::fromROSMsg(*pc_msg, pc_full);
00046         string head_frame("/head_pan_link");
00047         string base_frame("/base_link");
00048         ros::Time now = ros::Time::now();
00049         tf_listener.waitForTransform(pc_msg->header.frame_id, head_frame, now, ros::Duration(3.0));
00050         pcl_ros::transformPointCloud(head_frame, pc_full, pc_full_frame, tf_listener);
00051         // pc_full_frame is in torso lift frame
00052 
00053         tf_listener.waitForTransform(base_frame, head_frame, now, ros::Duration(3.0));
00054         tf::StampedTransform base_head_trans;
00055         tf_listener.lookupTransform(base_frame, head_frame, now, base_head_trans);
00056         float z_diff = base_head_trans.getOrigin().z();
00057 
00058         float minx = 0.3, maxx = 3.0, miny = -1.5, maxy = 1.5;
00059         float minz = 0.6 - z_diff, maxz = 1.0 - z_diff;
00060         float resolution = 200; 
00061         uint32_t imgx = (maxx-minx)*resolution;
00062         uint32_t imgy = (maxy-miny)*resolution;
00063         cv::Mat height_img(imgx, imgy, CV_8U, cv::Scalar(0));
00064         cv_bridge::CvImage cvb_height_img;
00065         
00066         BOOST_FOREACH(const pcl::PointXYZRGB& pt, pc_full_frame.points) {
00067             if(pt.x != pt.x || pt.y != pt.y || pt.z != pt.z)
00068                 continue;
00069             int32_t x, y, z;
00070             x = (pt.x - minx)/(maxx-minx) * imgx;
00071             y = (pt.y - miny)/(maxy-miny) * imgy;
00072             z = (pt.z - minz)/(maxz-minz) * 256;
00073             if(x < 0 || y < 0) continue; 
00074             if(x >= imgx || y >= imgy) continue;
00075             if(z < 0 || z >= 256) continue;
00076             if(height_img.at<uint8_t>(x, y) == 0 || height_img.at<uint8_t>(x, y) < (uint8_t) z)
00077                 height_img.at<uint8_t>(x, y) = (uint8_t) z;
00078         }
00079 
00080         cv::Mat height_hist(256, 1, CV_32F, cv::Scalar(0));
00081         for(uint32_t x=0;x<imgx;x++)
00082             for(uint32_t y=0;y<imgy;y++) {
00083                 if(height_img.at<uint8_t>(x,y) == 255)
00084                     height_img.at<uint8_t>(x,y) = 0;
00085                 if(height_img.at<uint8_t>(x,y) != 0) {
00086                     height_hist.at<float>(height_img.at<uint8_t>(x,y), 0)++;
00087                 }
00088             }
00089         uint32_t gfiltlen = 25;
00090         float stddev = 6;
00091         cv::Mat gauss_filt(gfiltlen, 1, CV_32F, cv::Scalar(0));
00092         for(uint32_t i=0;i<gfiltlen;i++)
00093             gauss_filt.at<float>(i,0) = 0.39894 / stddev * std::exp(-(i-((float)gfiltlen)/2)*(i-((float)gfiltlen)/2)/(2*stddev*stddev));
00094         //cout << gauss_filt;
00095         uint32_t maxval = 0, maxidx = 0;
00096         for(uint32_t i=0;i<256-gfiltlen;i++) {
00097             uint32_t sum = 0;
00098             for(uint32_t j=0;j<gfiltlen;j++) 
00099                 sum += height_hist.at<float>(i+j,0) * gauss_filt.at<float>(j,0);
00100             if(sum > maxval) {
00101                 maxval = sum;
00102                 maxidx = i+gfiltlen/2;
00103             }
00104         }
00105         int32_t table_height = ((int32_t)maxidx);
00106         //printf("%d %d, ", maxval, maxidx);
00107         cv::Mat height_img_thresh = height_img.clone();
00108         for(uint32_t x=0;x<imgx;x++)
00109             for(uint32_t y=0;y<imgy;y++) {
00110                 if(std::fabs(table_height - ((int32_t)height_img_thresh.at<uint8_t>(x,y))) < stddev*2)
00111                     height_img_thresh.at<uint8_t>(x,y) = 255;
00112                 else
00113                     height_img_thresh.at<uint8_t>(x,y) = 0;
00114             }
00115 
00116         cv::Mat height_morph(imgx, imgy, CV_8U, cv::Scalar(0));
00117         cv::Mat tmp_img(imgx, imgy, CV_8U, cv::Scalar(0));
00118         IplImage t1 = height_img_thresh; IplImage t2 = height_morph;
00119         IplConvKernel* element = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT);
00120         cvMorphologyEx(&t1, &t2, NULL, element, CV_MOP_CLOSE);
00121         cvMorphologyEx(&t2, &t2, NULL, element, CV_MOP_OPEN, 2);
00122         cv::Mat table_edge = height_morph.clone();
00123         //cvMorphologyEx(&height_img, &height_morph, NULL, element, CV_MOP_CLOSE);
00124 
00125         double sumx = 0, sumy = 0, suma = 0;
00126         for(uint32_t y=0;y<imgy;y++) {
00127             bool first_found = false;
00128             for(uint32_t x=0;x<imgx;x++) {
00129                 if(height_morph.at<uint8_t>(x,y) == 255) {
00130                     sumx += x;
00131                     sumy += y;
00132                     suma ++;
00133                 }
00134                 if(first_found) {
00135                     table_edge.at<uint8_t>(x,y) = 0;
00136                     continue;
00137                 }
00138                 if(table_edge.at<uint8_t>(x,y) == 255)
00139                     first_found = true;
00140             }
00141         }
00142         double centerx = sumx/suma, centery = sumy/suma;
00143         double moment11 = 0, moment12 = 0, moment21 = 0, moment22 = 0;
00144         for(uint32_t y=0;y<imgx;y++) {
00145             for(uint32_t x=0;x<imgx;x++) {
00146                 if(height_morph.at<uint8_t>(x,y) == 255) {
00147                     moment11 += (x - centerx) * (x - centerx); 
00148                     moment12 += (y - centery) * (x - centerx); 
00149                     moment21 += (x - centerx) * (y - centery); 
00150                     moment22 += (y - centery) * (y - centery); 
00151                 }
00152             }
00153         }
00154         double teig1 = (moment11 + moment22) / 2;
00155         double teig2 = sqrt((moment11 + moment22) * (moment11 + moment22) - 
00156                             4*(moment11*moment22 - moment12*moment12))/2;
00157         double eig1 = teig1 + teig2, eig2 = teig1 - teig2;
00158         double sign1 = 1, sign2 = 1;
00159         if((moment11 - eig1) * (moment12) < 0)
00160             sign1 = -1;
00161         if((moment11 - eig2) * (moment12) < 0)
00162             sign2 = -1;
00163         double evec1 = sign1 * sqrt((moment22 - eig1) / (moment11 - eig1));
00164         double evec2 = sign2 * sqrt((moment22 - eig2) / (moment11 - eig2));
00165         double m1 = sqrt(1+evec1*evec1), m2 = sqrt(1+evec2*evec2);
00166         double mag = 200 * sqrt(eig1) / suma;
00167         double comp1x = mag * sqrt(eig2/eig1) * evec1/m1, comp1y = sqrt(eig2/eig1) * mag /m1;
00168         double comp2x = mag * evec2/m2, comp2y = mag /m2;
00169         CvPoint** rpts = new CvPoint*[1]; rpts[0] = new CvPoint[4];
00170         rpts[0][0].y = centerx+comp1y+comp2y; rpts[0][0].x = centery+comp1x+comp2x;
00171         rpts[0][1].y = centerx+comp1y-comp2y; rpts[0][1].x = centery+comp1x-comp2x;
00172         rpts[0][2].y = centerx-comp1y-comp2y; rpts[0][2].x = centery-comp1x-comp2x;
00173         rpts[0][3].y = centerx-comp1y+comp2y; rpts[0][3].x = centery-comp1x+comp2x;
00174         rpts[0][4].y = centerx+comp1y+comp2y; rpts[0][4].x = centery+comp1x+comp2x;
00175         int npts[1] = {5};
00176         cvPolyLine(&t2, rpts, npts, 1, 1, cv::Scalar(180), 2);
00177         //delete[] rpts[0]; delete[] rpts;
00178         //printf("(%f, %f) [%f, %f] %f, %f, %f, %f;", (evec1/m1)*(evec1/m1) + (1/(m1*m1)), (evec2/m2)*(evec2/m2) + (1/(m2*m2)), sqrt(eig1), sqrt(eig2), comp1x, comp1y, comp2x, comp2y);
00179         cv::Mat table_hull(imgx, imgy, CV_8U, cv::Scalar(0));
00180         IplImage ipl_hull = table_hull;
00181         cvFillPoly(&ipl_hull, rpts, npts, 1, cv::Scalar(255));
00182 
00183         cv::Mat obj_img(imgx, imgy, CV_8U, cv::Scalar(0));
00184         std::vector<int32_t> xfeats, yfeats, zfeats;
00185         double sumobjx = 0, sumobjy = 0, sumobja = 0;
00186         for(uint32_t y=0;y<imgx;y++) 
00187             for(uint32_t x=0;x<imgx;x++) 
00188                 if(table_hull.at<uint8_t>(x,y) == 255 && height_morph.at<uint8_t>(x,y) == 0
00189                         && height_img.at<uint8_t>(x,y) > table_height + stddev*2) {
00190                     obj_img.at<uint8_t>(x,y) = height_img.at<uint8_t>(x,y);
00191                     sumobjx += x; sumobjy += y; sumobja ++;
00192                     //xfeats.push_back(x); yfeats.push_back(y); 
00193                     //zfeats.push_back(height_img.at<uint8_t>(x,y));
00194                 }
00195         double objcentx = sumobjx/sumobja, objcenty = sumobjy/sumobja;
00196 
00197         CvMemStorage* storage = cvCreateMemStorage(0);
00198         CvSeq* lines = 0;
00199         cv::Mat lines_img = height_morph.clone();
00200         IplImage lines_img_ipl = lines_img;
00201         IplImage table_edge_ipl = table_edge;
00202         cvMorphologyEx(&table_edge_ipl, &table_edge_ipl, NULL, element, CV_MOP_DILATE, 1);
00203         lines = cvHoughLines2(&table_edge_ipl, storage, CV_HOUGH_STANDARD, 1, 3*CV_PI/180, 60, 0, 0);
00204         vector<float> theta_bins, rho_bins;
00205         vector<uint32_t> ind_bins;
00206         for(uint32_t i=0; i < lines->total; i++) {
00207             float* line = (float*)cvGetSeqElem(lines, i);
00208             float rho = line[0];
00209             float theta = line[1];
00210             theta_bins.push_back(theta);
00211             rho_bins.push_back(rho);
00212             ind_bins.push_back(i);
00213 
00214             double a = cos(theta), b = sin(theta);
00215             double x0 = a*rho, y0 = b*rho;
00216             CvPoint pt1, pt2;
00217             a = cos(theta+CV_PI/2); b = sin(theta+CV_PI/2);
00218             x0 = objcenty; y0 = objcentx;
00219             pt1.x = cvRound(x0 + 1000*(-b));
00220             pt1.y = cvRound(y0 + 1000*(a));
00221             pt2.x = cvRound(x0 - 1000*(-b));
00222             pt2.y = cvRound(y0 - 1000*(a));
00223             cvLine(&lines_img_ipl, pt1, pt2, cv::Scalar(100), 2, 8 );
00224         }
00225         //delete[] lines;
00226       //boost::function<bool (int,int)> attr_comp = boost::bind(&RandomTree::attrCompare, *this, _1, _2, attrs[a]);
00227         boost::function<bool(int, int)> sortind = boost::bind(&compind, _1, _2, theta_bins);
00228         sort(ind_bins.begin(), ind_bins.end(), sortind);
00229         vector<float> posesx, posesy, poses_theta;
00230         for(uint32_t i=0;i<ind_bins.size();i++) {
00231             double theta = theta_bins[ind_bins[i]];
00232             double rho = rho_bins[ind_bins[i]];
00233             double a1 = cos(theta-CV_PI/2), b1 = sin(theta-CV_PI/2);
00234             double a2 = cos(theta-CV_PI), b2 = sin(theta-CV_PI);
00235             double vvcl = a2*b1-b2*a1, deltpx = cos(theta)*rho-objcenty, deltpy = sin(theta)*rho-objcentx;
00236             double pvcr = deltpx*b1 - deltpy*a1;
00237             double t = pvcr/vvcl;
00238             double posey = objcenty + t*a2, posex = objcentx + t*b2;
00239             printf("\naPose %d: (t: %f, %f, %f)[%f, %f](%f, %f)[%f, %f](1 %f, %f)(2 %f, %f)[theta %f, %f]\n", i, t, posex, posey, t*a2, t*b2, a1*rho, b1*rho, objcentx, objcenty, a1, b1, a2, b2, theta, rho);
00240             if(posex == posex && posey == posey &&
00241                 posex >= 0 && posey >= 0 &&
00242                 posex < imgx && posey < imgy) {
00243                 posesx.push_back(posex); posesy.push_back(posey); poses_theta.push_back(theta);
00244             }
00245             //lines_img.at<uint8_t>(posex, posey)
00246         }
00247         vector<float> retposesx, retposesy;
00248         float xgrand = 0.1 * resolution, ygrand = 0.1 * resolution;
00249         grasp_points.poses.clear();
00250         for(uint32_t i=0;i<posesx.size();i++) {
00251             bool same_found = false;
00252             for(int32_t j=((int)retposesx.size())-1;j>=0;j--) {
00253                 if(fabs(posesx[i] - retposesx[j]) < xgrand && 
00254                    fabs(posesy[i] - retposesy[j]) < ygrand) {
00255                     //retposesx[j] = (retposesx[j] + posesx[i])/2;
00256                     //retposesy[j] = (retposesy[j] + posesy[i])/2;
00257                     same_found = true;
00258                 } 
00259             }
00260             if(!same_found) {
00261                 retposesx.push_back(posesx[i]);
00262                 retposesy.push_back(posesy[i]);
00263                 geometry_msgs::Pose cpose;
00264                 cpose.position.x = posesx[i]/imgx*(maxx-minx) + minx;
00265                 cpose.position.y = posesy[i]/imgy*(maxy-miny) + miny;
00266                 cpose.position.z = table_height/256.0*(maxz-minz) + minz;
00267                 btMatrix3x3 quatmat; btQuaternion quat;
00268                 quatmat.setEulerZYX(-poses_theta[i] - CV_PI/2, 0 , 0);
00269                 quatmat.getRotation(quat);
00270                 btQuaternion head_quat(base_head_trans.getRotation().x(),
00271                                        base_head_trans.getRotation().y(),
00272                                        base_head_trans.getRotation().z(),
00273                                        base_head_trans.getRotation().w());
00274                 //quat *= head_quat;
00275                 //quat = quat*head_quat;
00276                 //quat = head_quat;
00277                 cpose.orientation.x = quat.x(); cpose.orientation.y = quat.y();
00278                 cpose.orientation.z = quat.z(); cpose.orientation.w = quat.w();
00279                 grasp_points.poses.push_back(cpose);
00280             }
00281         }
00282         grasp_points.header.stamp = ros::Time::now();
00283         grasp_points.header.frame_id = head_frame;
00284         pose_arr_pub.publish(grasp_points);
00285         
00286 
00287         printf("\nCenter (%f, %f)\n", objcentx, objcenty);
00288         for(uint32_t i=0;i<retposesx.size();i++) {
00289         //for(uint32_t i=0;i<1;i++) {
00290             printf("\nPose %d: (%f, %f)\n", i, retposesx[i], retposesy[i]);
00291             //CvPoint centerpt; centerpt.x = objcenty; centerpt.y = objcentx;
00292             CvPoint centerpt; centerpt.x = retposesy[i]; centerpt.y = retposesx[i];
00293             cvCircle(&lines_img_ipl, centerpt, 3, cv::Scalar(200), 2);
00294         }
00295 
00296 
00297         /*
00298         cv::Mat obj_feats(xfeats.size(), 1, CV_32S, cv::Scalar(0));
00299         for(uint32_t i=0;i<xfeats.size();i++) {
00300             obj_feats.at<uint32_t>(i,0) = xfeats[i]; obj_feats.at<uint32_t>(i,1) = yfeats[i]; obj_feats.at<uint32_t>(i,2) = zfeats[i]; 
00301         }
00302         cvflann::KMeansIndexParams kmips;
00303         kmips.branching = 32;
00304         kmips.iterations = 11;
00305         kmips.centers_init = cvflann::CENTERS_RANDOM;
00306         kmips.cb_index = 0.2;
00307         cv::Mat obj_centers;
00308         CvMat obj_feats_mat = obj_feats;
00309         //cvflann::Matrix<uint32_t> obj_feats_mat;
00310         //cvflann::Matrix<cvflann::EUCLIDEAN> obj_centers_mat;
00311         int num_clust = cvflann::hierarchicalClustering<CV_32S,CV_32S>(obj_feats_mat, obj_centers, kmips);
00312         printf("\nNum clust: %d \n", num_clust);
00313         */
00314 
00315 
00316         cv::Mat table_edge2 = table_edge.clone();
00317         IplImage table_edge_ipl2 = table_edge2;
00318         cvMorphologyEx(&table_edge_ipl2, &table_edge_ipl2, NULL, element, CV_MOP_DILATE, 3);
00319 
00320         BOOST_FOREACH(const pcl::PointXYZRGB& pt, pc_full_frame.points) {
00321             if(pt.x != pt.x || pt.y != pt.y || pt.z != pt.z)
00322                 continue;
00323             int32_t x, y, z;
00324             x = (pt.x - minx)/(maxx-minx) * imgx;
00325             y = (pt.y - miny)/(maxy-miny) * imgy;
00326             z = (pt.z - minz)/(maxz-minz) * 256;
00327             if(x < 0 || y < 0) continue; 
00328             if(x >= imgx || y >= imgy) continue;
00329             if(z < 0 || z >= 256) continue;
00330             if(height_morph.at<uint8_t>(x,y) == 255 && 
00331                     std::fabs(table_height - z) < stddev*2) {
00332                 uint32_t red = 0xFFFF0000;
00333                 ((uint32_t*) &pt.rgb)[0] = red;
00334             }
00335             if(table_edge.at<uint8_t>(x,y) == 255 && 
00336                     std::fabs(table_height - z) < stddev*4) {
00337                 uint32_t blue = 0xFF0000FF;
00338                 ((uint32_t*) &pt.rgb)[0] = blue;
00339             }
00340         }
00341 
00342         //cvb_height_img.image = height_img;
00343         //cvb_height_img.image = height_morph;
00344         //cvb_height_img.image = obj_img;
00345         cvb_height_img.image = lines_img;
00346         //cvb_height_img.image = table_edge;
00347         cvb_height_img.header.stamp = ros::Time::now();
00348         cvb_height_img.header.frame_id = head_frame;
00349         cvb_height_img.encoding = enc::MONO8;
00350         height_pub.publish(cvb_height_img.toImageMsg());
00351         pc_full_frame.header.stamp = ros::Time::now();
00352         pc_full_frame.header.frame_id = head_frame;
00353         pc_pub.publish(pc_full_frame);
00354 
00355         if(grasp_points.poses.size() > 0)
00356             grasp_points_found = true;
00357 
00358         //delete element;
00359     }
00360 
00361 };
00362 
00363 using namespace hrl_object_fetching;
00364 
00365 int main(int argc, char **argv)
00366 {
00367     ros::init(argc, argv, "tabletop_approach");
00368     TabletopDetector ta;
00369     ta.onInit();
00370     ros::spin();
00371     return 0;
00372 }


hrl_object_fetching
Author(s): Kelsey Hawkins. Advisor: Prof. Charlie Kemp. Healthcare Robotics Lab, Georgia Tech
autogenerated on Wed Nov 27 2013 11:33:13