00001
00002 #include <tabletop_pushing/extern/graphcut/graph.h>
00003 #include <tabletop_pushing/extern/graphcut/energy.h>
00004 #include <tabletop_pushing/extern/graphcut/GCoptimization.h>
00005
00006
00007 typedef Graph<float, float, float> GraphType;
00008
00009 inline float max(const float a, const double b)
00010 {
00011 return std::max(static_cast<double>(a), b);
00012 }
00013
00014 inline float min(const float a, const double b)
00015 {
00016 return std::min(static_cast<double>(a), b);
00017 }
00018
00019 class ArmModel
00020 {
00021 public:
00022 ArmModel() : l_hand_on(false), r_hand_on(false), l_arm_on(false),
00023 r_arm_on(false)
00024 {
00025 hands.clear();
00026 arms.clear();
00027 }
00028 unsigned int size()
00029 {
00030 return 2;
00031 }
00032
00033 std::vector<cv::Point> operator[](unsigned int i)
00034 {
00035 if (i == 0)
00036 return hands;
00037 if (i > 1)
00038 {
00039 std::stringstream err_msg;
00040 err_msg << "Index argument: " << i << " is out of range in class ArmModel";
00041 throw std::out_of_range(err_msg.str());
00042 }
00043 return arms;
00044 }
00045
00053 float distanceToArm(cv::Point2f p, cv::Mat& depth_frame)
00054 {
00055 float l_dist = distanceToArm(p, l_chain, depth_frame);
00056 float r_dist = distanceToArm(p, r_chain, depth_frame);
00057 if (l_dist < 0 && r_dist < 0) return -1.0f;
00058 if (l_dist < 0)
00059 {
00060 return r_dist;
00061 }
00062 if (r_dist < 0)
00063 {
00064 return l_dist;
00065 }
00066 return min(l_dist, r_dist);
00067 }
00068
00069 float distanceToArm(cv::Point2f p, std::vector<cv::Point>& chain,
00070 cv::Mat& depth_frame)
00071 {
00072 if (chain.size() == 0)
00073 {
00074 return -1.0f;
00075 }
00076 float min_dist = 640.0f*480.0f;
00077 for (unsigned int i = 1; i < chain.size(); ++i)
00078 {
00079 float d_i = pointLineDistance(p, chain[i-1] , chain[i], depth_frame);
00080 if (d_i < min_dist)
00081 min_dist = d_i;
00082 }
00083 return min_dist;
00084 }
00085
00086 float pointLineDistance(cv::Point2f p, cv::Point2f l0, cv::Point2f l1,
00087 cv::Mat& depth_frame)
00088 {
00089 if (l0.x == l1.x)
00090 {
00091 cv::Point2f q(l0.x, p.y);
00092 float l_max_x = max(l0.x, l1.x);
00093 float l_min_x = min(l0.x, l1.x);
00094 if (p.y > l_max_x)
00095 {
00096 q.y = l_max_x;
00097 }
00098 else if (p.y < l_min_x)
00099 {
00100 q.y = l_min_x;
00101 }
00102 return pointPointDistance(p,q,depth_frame);
00103 }
00104 cv::Point2f x0;
00105 cv::Point2f x1;
00106
00107 if (l0.x < l1.x)
00108 {
00109 x0 = l0;
00110 x1 = l1;
00111 }
00112 else
00113 {
00114 x0 = l1;
00115 x1 = l0;
00116 }
00117 cv::Point2f v = x1 - x0;
00118 cv::Point2f w = p - x0;
00119
00120 float c0 = w.x*v.x+w.y*v.y;
00121 float c1 = v.x*v.x+v.y*v.y;
00122 float b = c0/c1;
00123
00124 cv::Point2f q = x0 + b*v;
00125
00126 float d = pointPointDistance(p,q,depth_frame);
00127 if (c0 <= 0 || q.x < x0.x)
00128 {
00129 d = pointPointDistance(p,x0,depth_frame);
00130 }
00131 if (c1 <= 0 || q.x > x1.x)
00132 {
00133 d = pointPointDistance(p,x1,depth_frame);
00134 }
00135 return d;
00136 }
00137
00138 float pointPointDistance(cv::Point2f& p, cv::Point2f& q, cv::Mat& depth_frame)
00139 {
00140
00141
00142 const float d_x = p.x-q.x;
00143 const float d_y = p.y-q.y;
00144
00145
00146
00147 return sqrt(d_x*d_x + d_y*d_y);
00148 }
00149
00150 std::vector<cv::Point> hands;
00151 std::vector<cv::Point> arms;
00152 std::vector<cv::Point> l_chain;
00153 std::vector<cv::Point> r_chain;
00154 bool l_hand_on;
00155 bool r_hand_on;
00156 bool l_arm_on;
00157 bool r_arm_on;
00158 };
00159
00160 class MotionGraphcut
00161 {
00162 public:
00163 MotionGraphcut(double workspace_background_weight = 1.0f,
00164 double min_weight = 0.01, double magnitude_thresh=0.1,
00165 double flow_gain = 0.3, int arm_grow_radius=2) :
00166 workspace_background_weight_(workspace_background_weight),
00167 min_weight_(min_weight), magnitude_thresh_(magnitude_thresh),
00168 flow_gain_(flow_gain), arm_grow_radius_(arm_grow_radius)
00169 {
00170 }
00171
00172 virtual ~MotionGraphcut()
00173 {
00174 }
00175
00191 cv::Mat operator()(cv::Mat& color_frame, cv::Mat& depth_frame,
00192 cv::Mat& u, cv::Mat& v, cv::Mat& workspace_mask,
00193 cv::Mat& table_heights, ArmModel arm_locs)
00194 {
00195 const int R = color_frame.rows;
00196 const int C = color_frame.cols;
00197 int num_nodes = R*C;
00198 int num_edges = ((C-1)*3+1)*(R-1)+(C-1);
00199 GraphType *g;
00200 g = new GraphType(num_nodes, num_edges);
00201
00202 #ifdef VISUALIZE_GRAPH_WEIGHTS
00203 cv::Mat fg_weights(color_frame.size(), CV_32FC1);
00204 cv::Mat bg_weights(color_frame.size(), CV_32FC1);
00205 cv::Mat table_weights(color_frame.size(), CV_32FC1);
00206 #endif // VISUALIZE_GRAPH_WEIGHTS
00207 #ifdef VISUALIZE_GRAPH_EDGE_WEIGHTS
00208 cv::Mat left_weights(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00209 cv::Mat up_weights(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00210 cv::Mat up_left_weights(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00211 #endif // VISUALIZE_GRAPH_EDGE_WEIGHTS
00212
00213 for (int r = 0; r < R; ++r)
00214 {
00215 for (int c = 0; c < C; ++c)
00216 {
00217 g->add_node();
00218 float magnitude = std::sqrt(u.at<float>(r,c)*u.at<float>(r,c) +
00219 v.at<float>(r,c)*v.at<float>(r,c));
00220
00221 if (workspace_mask.at<uchar>(r,c) == 0)
00222 {
00223 g->add_tweights(r*C+c, min_weight_, workspace_background_weight_);
00224
00225 #ifdef VISUALIZE_GRAPH_WEIGHTS
00226 fg_weights.at<float>(r,c) = min_weight_;
00227 bg_weights.at<float>(r,c) = workspace_background_weight_;
00228 table_weights.at<float>(r,c) = min_weight_;
00229 #endif // VISUALIZE_GRAPH_WEIGHTS
00230 continue;
00231 }
00232 const float mag_score = max(getFlowFGScore(magnitude), min_weight_);
00233 const float table_score = max(getTableScore(color_frame.at<cv::Vec3f>(r,c),
00234 fabs(table_heights.at<float>(r,c))), min_weight_);
00235 const float not_mag_score = max(1.0 - mag_score, min_weight_);
00236 const float bg_score = not_mag_score + table_score;
00237 g->add_tweights(r*C+c, mag_score, bg_score);
00238 #ifdef VISUALIZE_GRAPH_WEIGHTS
00239 fg_weights.at<float>(r,c) = mag_score;
00240 bg_weights.at<float>(r,c) = bg_score;
00241 table_weights.at<float>(r,c) = table_score;
00242 #endif // VISUALIZE_GRAPH_WEIGHTS
00243 }
00244 }
00245 for (int r = 0; r < R; ++r)
00246 {
00247 for (int c = 0; c < C; ++c)
00248 {
00249
00250 if (c > 0)
00251 {
00252
00253 float w_l = getEdgeWeight(color_frame.at<cv::Vec3f>(r,c),
00254 depth_frame.at<float>(r,c),
00255 color_frame.at<cv::Vec3f>(r,c-1),
00256 depth_frame.at<float>(r,c-1));
00257 g->add_edge(r*C+c, r*C+c-1, w_l, w_l);
00258 #ifdef VISUALIZE_GRAPH_EDGE_WEIGHTS
00259 left_weights.at<float>(r,c) = w_l;
00260 #endif // VISUALIZE_EDGE_GRAPH_WEIGHTS
00261 }
00262 if (r > 0)
00263 {
00264
00265 float w_u = getEdgeWeight(color_frame.at<cv::Vec3f>(r,c),
00266 depth_frame.at<float>(r,c),
00267 color_frame.at<cv::Vec3f>(r-1,c),
00268 depth_frame.at<float>(r-1,c));
00269 g->add_edge(r*C+c, (r-1)*C+c, w_u, w_u);
00270 #ifdef VISUALIZE_GRAPH_EDGE_WEIGHTS
00271 up_weights.at<float>(r,c) = w_u;
00272 #endif // VISUALIZE_GRAPH_EDGE_WEIGHTS
00273
00274 if (c > 0)
00275 {
00276 float w_ul = getEdgeWeight(color_frame.at<cv::Vec3f>(r,c),
00277 depth_frame.at<float>(r,c),
00278 color_frame.at<cv::Vec3f>(r-1,c-1),
00279 depth_frame.at<float>(r-1,c-1));
00280 g->add_edge(r*C+c, (r-1)*C+c-1, w_ul, w_ul);
00281 #ifdef VISUALIZE_GRAPH_EDGE_WEIGHTS
00282 up_left_weights.at<float>(r,c) = w_ul;
00283 #endif // VISUALIZE_GRAPH_EDGE_WEIGHTS
00284 }
00285 }
00286 }
00287 }
00288
00289 #ifdef VISUALIZE_GRAPH_WEIGHTS
00290 cv::imshow("fg_weights", fg_weights);
00291 cv::imshow("bg_weights", bg_weights);
00292
00293
00294
00295 cv::imshow("table_weights", table_weights);
00296 #endif // VISUALIZE_GRAPH_WEIGHTS
00297 #ifdef VISUALIZE_GRAPH_EDGE_WEIGHTS
00298 double up_max = 1.0;
00299 cv::minMaxLoc(up_weights, NULL, &up_max);
00300 up_weights /= up_max;
00301
00302 cv::imshow("up_weights", up_weights);
00303 double left_max = 1.0;
00304 cv::minMaxLoc(left_weights, NULL, &left_max);
00305 left_weights /= left_max;
00306 cv::imshow("left_weights", left_weights);
00307 double up_left_max = 1.0;
00308 cv::minMaxLoc(up_left_weights, NULL, &up_left_max);
00309 up_left_weights /= up_max;
00310 cv::imshow("up_left_weights", up_left_weights);
00311 #endif // VISUALIZE_GRAPH_EDGE_WEIGHTS
00312
00313
00314 g->maxflow(false);
00315
00316
00317 cv::Mat segs = convertFlowResultsToCvMat(g, R, C);
00318 delete g;
00319 return segs;
00320 }
00321
00334 cv::Mat segmentRobotArm(cv::Mat& color_frame_in, cv::Mat& depth_frame_in,
00335 cv::Mat& workspace_mask_in, ArmModel& arms,
00336 int min_arm_x, int max_arm_x, int min_arm_y,
00337 int max_arm_y)
00338 {
00339
00340
00341 const int crop_min_x = max(0, min_arm_x - arm_search_radius_);
00342 const int crop_max_x = min(color_frame_in.cols,
00343 max_arm_x + arm_search_radius_);
00344 const int crop_min_y = max(0, min_arm_y - arm_search_radius_);
00345 const int crop_max_y = min(color_frame_in.rows,
00346 max_arm_y + arm_search_radius_);
00347 cv::Rect roi(crop_min_x, crop_min_y, crop_max_x-crop_min_x,
00348 crop_max_y-crop_min_y);
00349 cv::Mat color_frame = color_frame_in(roi);
00350 cv::Mat depth_frame = depth_frame_in(roi);
00351 cv::Mat workspace_mask = workspace_mask_in(roi);
00352
00353 const int R = color_frame.rows;
00354 const int C = color_frame.cols;
00355
00356 int num_nodes = R*C;
00357 int num_edges = ((C-1)*3+1)*(R-1)+(C-1);
00358 GraphType *g;
00359 g = new GraphType(num_nodes, num_edges);
00360
00361 #ifdef VISUALIZE_ARM_GRAPH_WEIGHTS
00362 cv::Mat fg_weights(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00363 cv::Mat bg_weights(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00364 cv::Mat dist_img(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00365 #endif // VISUALIZE_GRAPH_WEIGHTS
00366 #ifdef VISUALIZE_ARM_GRAPH_EDGE_WEIGHTS
00367 cv::Mat left_weights(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00368 cv::Mat up_weights(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00369 cv::Mat up_left_weights(color_frame.size(), CV_32FC1, cv::Scalar(0.0));
00370 #endif // VISUALIZE_ARM_GRAPH_WEIGHTS
00371
00372
00373
00374 if (arms[0].size() == 0)
00375 {
00376 ROS_WARN_STREAM("No hands!");
00377 }
00378 if (arms[1].size() == 0)
00379 {
00380 ROS_WARN_STREAM("No arms!");
00381 }
00382 std::vector<cv::Vec3f> hand_stats = getImagePointGaussian(color_frame,
00383 arms[0],
00384 crop_min_x,
00385 crop_min_y);
00386 std::vector<cv::Vec3f> arm_stats = getImagePointGaussian(color_frame,
00387 arms[1],
00388 crop_min_x,
00389 crop_min_y);
00390
00391 for (int r = 0; r < R; ++r)
00392 {
00393 for (int c = 0; c < C; ++c)
00394 {
00395 g->add_node();
00396 #ifdef USE_WORKSPACE_MASK_FOR_ARM
00397 if (workspace_mask.at<uchar>(r,c) == 0)
00398 {
00399 g->add_tweights(r*C+c, min_weight_, workspace_background_weight_);
00400 #ifdef VISUALIZE_ARM_GRAPH_WEIGHTS
00401 fg_weights.at<float>(r,c) = min_weight_;
00402 bg_weights.at<float>(r,c) = workspace_background_weight_;
00403 dist_img.at<float>(r,c) = min_weight_;
00404 #endif // VISUALIZE_GRAPH_WEIGHTS
00405 continue;
00406 }
00407 #endif // USE_WORKSPACE_MASK_FOR_ARM
00408 #ifdef VISUALIZE_ARM_GRAPH_WEIGHTS
00409 const float me_score = max(getArmFGScore(color_frame, depth_frame, r, c,
00410 arm_stats, hand_stats, arms,
00411 roi, dist_img), min_weight_);
00412 #else // VISUALIZE_ARM_GRAPH_WEIGHTS
00413 const float me_score = max(getArmFGScore(color_frame, depth_frame, r, c,
00414 arm_stats, hand_stats, arms,
00415 roi), min_weight_);
00416 #endif // VISUALIZE_ARM_GRAPH_WEIGHTS
00417 const float not_me_score = max(1.0 - me_score, min_weight_);
00418 g->add_tweights(r*C+c, me_score, not_me_score);
00419 #ifdef VISUALIZE_ARM_GRAPH_WEIGHTS
00420 fg_weights.at<float>(r,c) = me_score;
00421 bg_weights.at<float>(r,c) = not_me_score;
00422 #endif // VISUALIZE_ARM_GRAPH_WEIGHTS
00423 }
00424 }
00425
00426 for (int r = 0; r < R; ++r)
00427 {
00428 for (int c = 0; c < C; ++c)
00429 {
00430
00431 if (c > 0)
00432 {
00433
00434 float w_l = getEdgeWeight(color_frame.at<cv::Vec3f>(r,c),
00435 depth_frame.at<float>(r,c),
00436 color_frame.at<cv::Vec3f>(r,c-1),
00437 depth_frame.at<float>(r,c-1));
00438 g->add_edge(r*C+c, r*C+c-1, w_l, w_l);
00439 #ifdef VISUALIZE_ARM_GRAPH_EDGE_WEIGHTS
00440 left_weights.at<float>(r,c) = w_l;
00441 #endif // VISUALIZE_ARM_GRAPH_EDGE_WEIGHTS
00442 }
00443 if (r > 0)
00444 {
00445
00446 float w_u = getEdgeWeight(color_frame.at<cv::Vec3f>(r,c),
00447 depth_frame.at<float>(r,c),
00448 color_frame.at<cv::Vec3f>(r-1,c),
00449 depth_frame.at<float>(r-1,c));
00450 g->add_edge(r*C+c, (r-1)*C+c, w_u, w_u);
00451 #ifdef VISUALIZE_ARM_GRAPH_EDGE_WEIGHTS
00452 up_weights.at<float>(r,c) = w_u;
00453 #endif // VISUALIZE_ARM_GRAPH_WEIGHTS
00454
00455
00456 if (c > 0)
00457 {
00458 float w_ul = getEdgeWeight(color_frame.at<cv::Vec3f>(r,c),
00459 depth_frame.at<float>(r,c),
00460 color_frame.at<cv::Vec3f>(r-1,c-1),
00461 depth_frame.at<float>(r-1,c-1));
00462 g->add_edge(r*C+c, (r-1)*C+c-1, w_ul, w_ul);
00463 #ifdef VISUALIZE_ARM_GRAPH_EDGE_WEIGHTS
00464 up_left_weights.at<float>(r,c) = w_ul;
00465 #endif // VISUALIZE_ARM_GRAPH_EDGE_WEIGHTS
00466
00467 }
00468 }
00469 }
00470 }
00471 #ifdef VISUALIZE_ARM_GRAPH_WEIGHTS
00472 cv::imshow("fg_weights_arm", fg_weights);
00473 cv::imshow("bg_weights_arm", bg_weights);
00474 cv::imshow("arm_dist_scores", dist_img);
00475 #endif // VISUALIZE_ARM_GRAPH_WEIGHTS
00476 #ifdef VISUALIZE_ARM_GRAPH_EDGE_WEIGHTS
00477 double up_max = 1.0;
00478 cv::minMaxLoc(up_weights, NULL, &up_max);
00479 up_weights /= up_max;
00480 double left_max = 1.0;
00481 cv::minMaxLoc(left_weights, NULL, &left_max);
00482 left_weights /= left_max;
00483 double up_left_max = 1.0;
00484 cv::minMaxLoc(up_left_weights, NULL, &up_left_max);
00485 up_left_weights /= up_max;
00486 cv::imshow("up_weights_arm", up_weights);
00487 cv::imshow("left_weights_arm", left_weights);
00488 cv::imshow("up_left_weights_arm", up_left_weights);
00489 #endif // VISUALIZE_ARM_GRAPH_EDGE_WEIGHTS
00490
00491
00492 g->maxflow(false);
00493
00494
00495 cv::Mat segs = convertFlowResultsToCvMat(g, R, C, roi,
00496 color_frame_in.size());
00497 delete g;
00498 return segs;
00499 }
00500
00501 float getFlowFGScore(float magnitude)
00502 {
00503 return min(1.0, max(flow_gain_*exp(magnitude), 0.0));
00504 }
00505
00506 float getTableScore(cv::Vec3f cur_c, float height_from_table)
00507 {
00508 const float dist_score = exp(-height_from_table/table_height_var_);
00509 #ifndef USE_TABLE_COLOR_ESTIMATE
00510 return min(1.0, max(dist_score, 0.0));
00511 #else // USE_TABLE_COLOR_ESTIMATE
00512 const float h_score = 1.0-fabs(cur_c[0] - table_stats_[0][0])/(
00513 table_stats_[1][0] + arm_color_var_add_);
00514 const float s_score = 1.0-fabs(cur_c[1] - table_stats_[0][1])/(
00515 table_stats_[1][1] + arm_color_var_add_);
00516 const float table_score = (h_score + s_score)/2.0+0.5*dist_score;
00517 return table_score;
00518 #endif // USE_TABLE_COLOR_ESTIMATE
00519 }
00520 #ifdef VISUALIZE_ARM_GRAPH_WEIGHTS
00521 float getArmFGScore(cv::Mat& color_frame, cv::Mat& depth_frame, int r, int c,
00522 std::vector<cv::Vec3f>& arm_stats,
00523 std::vector<cv::Vec3f>& hand_stats, ArmModel& arms,
00524 cv::Rect& roi, cv::Mat& dist_img)
00525 #else // VISUALIZE_ARM_GRAPH_WEIGHTS
00526 float getArmFGScore(cv::Mat& color_frame, cv::Mat& depth_frame, int r, int c,
00527 std::vector<cv::Vec3f>& arm_stats,
00528 std::vector<cv::Vec3f>& hand_stats, ArmModel& arms,
00529 cv::Rect& roi)
00530 #endif // VISUALIZE_ARM_GRAPH_WEIGHTS
00531 {
00532 const float dist_score = exp(-arms.distanceToArm(
00533 cv::Point2f(c+roi.x,r+roi.y), depth_frame)/arm_dist_var_);
00534 #ifdef VISUALIZE_ARM_GRAPH_WEIGHTS
00535 dist_img.at<float>(r,c) = dist_score;
00536 #endif // VISUALIZE_ARM_GRAPH_WEIGHTS
00537 cv::Vec3f cur_c = color_frame.at<cv::Vec3f>(r,c);
00538 const float arm_h_score = 1.0-fabs(cur_c[0] - arm_stats[0][0])/(
00539 arm_stats[1][0] + arm_color_var_add_);
00540 const float arm_s_score = 1.0-fabs(cur_c[1] - arm_stats[0][1])/(
00541 arm_stats[1][1] + arm_color_var_add_);
00542 const float arm_v_score = 1.0-fabs(cur_c[2] - arm_stats[0][2])/(
00543 arm_stats[1][2] + arm_color_var_add_);
00544 const float arm_score = (arm_alpha_*(arm_h_score + arm_s_score +
00545 arm_v_score)/3.0 +
00546 arm_beta_*dist_score);
00547 const float hand_h_score = 1.0-fabs(cur_c[0] - hand_stats[0][0])/(
00548 hand_stats[1][0] + arm_color_var_add_);
00549 const float hand_s_score = 1.0-fabs(cur_c[1] - hand_stats[0][1])/(
00550 hand_stats[1][1] + arm_color_var_add_);
00551 const float hand_v_score = 1.0-fabs(cur_c[2] - hand_stats[0][2])/(
00552 hand_stats[1][2] + arm_color_var_add_);
00553 const float hand_score = (arm_alpha_*(hand_h_score + hand_s_score +
00554 hand_v_score) / 3.0 +
00555 arm_beta_*dist_score);
00556 return max(hand_score, arm_score);
00557 }
00558
00559 std::vector<cv::Vec3f> getImagePointGaussian(cv::Mat& color_frame,
00560 std::vector<cv::Point> points,
00561 int min_x=0, int min_y=0)
00562 {
00563
00564 const int C = color_frame.cols;
00565 const int R = color_frame.rows;
00566 int pixel_count = 0;
00567 cv::Vec3f means;
00568 means[0] = 0.0;
00569 means[1] = 0.0;
00570 means[2] = 0.0;
00571 for (unsigned int i = 0; i < points.size(); ++i)
00572 {
00573 for (int r = max(0, points[i].y - min_y - arm_grow_radius_);
00574 r < min(points[i].y - min_y + arm_grow_radius_, R); ++r)
00575 {
00576 for (int c = max(0, points[i].x - min_x - arm_grow_radius_);
00577 c < min(points[i].x - min_x + arm_grow_radius_, C); ++c)
00578 {
00579 cv::Vec3f cur_color = color_frame.at<cv::Vec3f>(r,c);
00580 means += cur_color;
00581 ++pixel_count;
00582 }
00583 }
00584 }
00585 if (pixel_count > 0)
00586 {
00587 means[0] /= pixel_count;
00588 means[1] /= pixel_count;
00589 means[2] /= pixel_count;
00590 }
00591 else
00592 {
00593 ROS_WARN_STREAM("Calculating stats for 0 pixels");
00594 }
00595 cv::Vec3f vars;
00596 vars[0] = 0.0;
00597 vars[1] = 0.0;
00598 vars[2] = 0.0;
00599 for (unsigned int i = 0; i < points.size(); ++i)
00600 {
00601 for (int r = max(0, points[i].y - min_y -arm_grow_radius_);
00602 r < min(points[i].y - min_y + arm_grow_radius_, R); ++r)
00603 {
00604 for (int c = max(0, points[i].x - min_x - arm_grow_radius_);
00605 c < min(points[i].x - min_x + arm_grow_radius_, C); ++c)
00606 {
00607 cv::Vec3f diff = color_frame.at<cv::Vec3f>(r,c);
00608 diff = diff.mul(diff);
00609 vars += diff;
00610 }
00611 }
00612 }
00613 vars[0] /= (pixel_count+1.0);
00614 vars[1] /= (pixel_count+1.0);
00615 vars[2] /= (pixel_count+1.0);
00616 std::vector<cv::Vec3f> stats;
00617 stats.push_back(means);
00618 stats.push_back(vars);
00619 return stats;
00620 }
00621
00622 void setTableColorStats(cv::Mat& color_frame, std::vector<cv::Point>& pts)
00623 {
00624 cv::Mat color_frame_hsv(color_frame.size(), color_frame.type());
00625 cv::cvtColor(color_frame, color_frame_hsv, CV_BGR2HSV);
00626 cv::Mat color_frame_f(color_frame_hsv.size(), CV_32FC3);
00627 color_frame_hsv.convertTo(color_frame_f, CV_32FC3, 1.0/255, 0);
00628 table_stats_ = getImagePointGaussian(color_frame_f, pts);
00629 }
00630
00631 cv::Mat convertFlowResultsToCvMat(GraphType *g, int R, int C)
00632 {
00633 cv::Mat segs(R, C, CV_8UC1, cv::Scalar(0));
00634 for (int r = 0; r < R; ++r)
00635 {
00636 uchar* seg_row = segs.ptr<uchar>(r);
00637 for (int c = 0; c < C; ++c)
00638 {
00639 int label = (g->what_segment(r*C+c) == GraphType::SOURCE);
00640 seg_row[c] = label*255;
00641 }
00642 }
00643 return segs;
00644 }
00645
00646 cv::Mat convertFlowResultsToCvMat(GraphType *g, int R, int C,
00647 cv::Rect roi, cv::Size out_size)
00648 {
00649 cv::Mat segs(out_size, CV_8UC1, cv::Scalar(0));
00650 for (int r = 0; r < R; ++r)
00651 {
00652 for (int c = 0; c < C; ++c)
00653 {
00654 int label = (g->what_segment(r*C+c) == GraphType::SOURCE);
00655 segs.at<uchar>(r+roi.y, c+roi.x) = label*255;
00656 }
00657 }
00658 return segs;
00659 }
00660
00661 float getEdgeWeight(cv::Vec3f c0, float d0, cv::Vec3f c1, float d1)
00662 {
00663 cv::Vec3f c_d = c0-c1;
00664 float w_d = d0-d1;
00665 float w_c = w_c_alpha_*exp(fabs(c_d[0])) + w_c_beta_*exp(fabs(c_d[1])) +
00666 w_c_gamma_*exp(fabs(w_d));
00667 return w_c;
00668 }
00669
00670 enum SegLabels
00671 {
00672 MOVING,
00673 ARM,
00674 TABLE,
00675 BG
00676 };
00677
00678 double workspace_background_weight_;
00679 double min_weight_;
00680 double w_c_alpha_;
00681 double w_c_beta_;
00682 double w_c_gamma_;
00683 double magnitude_thresh_;
00684 double flow_gain_;
00685 double table_height_var_;
00686 double arm_dist_var_;
00687 double arm_color_var_add_;
00688 double arm_alpha_;
00689 double arm_beta_;
00690 int arm_grow_radius_;
00691 int arm_search_radius_;
00692 std::vector<cv::Vec3f> table_stats_;
00693 };
00694
00695 class MGCNode
00696 {
00697 public:
00698 MGCNode(ros::NodeHandle &n) :
00699 n_(n), n_private_("~"),
00700 image_sub_(n, "color_image_topic", 1),
00701 depth_sub_(n, "depth_image_topic", 1),
00702 cloud_sub_(n, "point_cloud_topic", 1),
00703 sync_(MySyncPolicy(15), image_sub_, depth_sub_, cloud_sub_),
00704 it_(n),
00705 singulation_server_(n, "singulation_action",
00706 boost::bind(&TabletopPushingPerceptionNode::trackerGoalCallback,
00707 this, _1),
00708 false),
00709 tf_(), os_(&ft_), pcl_segmenter_(&ft_),
00710 have_depth_data_(false), tracking_(false),
00711 tracker_initialized_(false), tracker_count_(0)
00712 {
00713
00714 n_private_.param("crop_min_x", crop_min_x_, 0);
00715 n_private_.param("crop_max_x", crop_max_x_, 640);
00716 n_private_.param("crop_min_y", crop_min_y_, 0);
00717 n_private_.param("crop_max_y", crop_max_y_, 480);
00718 n_private_.param("display_wait_ms", display_wait_ms_, 3);
00719 n_private_.param("min_workspace_x", min_workspace_x_, 0.0);
00720 n_private_.param("min_workspace_y", min_workspace_y_, 0.0);
00721 n_private_.param("min_workspace_z", min_workspace_z_, 0.0);
00722 n_private_.param("below_table_z", below_table_z_, 0.1);
00723 n_private_.param("max_workspace_x", max_workspace_x_, 0.0);
00724 n_private_.param("max_workspace_y", max_workspace_y_, 0.0);
00725 n_private_.param("max_workspace_z", max_workspace_z_, 0.0);
00726 n_private_.param("min_pushing_x", min_pushing_x_, 0.0);
00727 n_private_.param("min_pushing_y", min_pushing_y_, 0.0);
00728 n_private_.param("max_pushing_x", max_pushing_x_, 0.0);
00729 n_private_.param("max_pushing_y", max_pushing_y_, 0.0);
00730 std::string default_workspace_frame = "/torso_lift_link";
00731 n_private_.param("workspace_frame", workspace_frame_,
00732 default_workspace_frame);
00733
00734 n_private_.param("min_table_z", pcl_segmenter_.min_table_z_, -0.5);
00735 n_private_.param("max_table_z", pcl_segmenter_.max_table_z_, 1.5);
00736 pcl_segmenter_.min_workspace_x_ = min_workspace_x_;
00737 pcl_segmenter_.max_workspace_x_ = max_workspace_x_;
00738
00739 n_private_.param("segmenting_moving_stuff", segmenting_moving_stuff_,
00740 false);
00741 n_private_.param("autostart_tracking", tracking_, false);
00742 n_private_.param("auto_flow_cluster", auto_flow_cluster_, false);
00743 n_private_.param("autostart_pcl_segmentation", autorun_pcl_segmentation_,
00744 false);
00745
00746 n_private_.param("num_downsamples", num_downsamples_, 2);
00747 std::string cam_info_topic_def = "/kinect_head/rgb/camera_info";
00748 n_private_.param("cam_info_topic", cam_info_topic_,
00749 cam_info_topic_def);
00750 n_private_.param("table_ransac_thresh", pcl_segmenter_.table_ransac_thresh_,
00751 0.01);
00752
00753 base_output_path_ = "/home/thermans/sandbox/cut_out/";
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771 int win_size = 5;
00772 n_private_.param("lk_win_size", win_size, 5);
00773 lkflow_.setWinSize(win_size);
00774 int num_levels = 4;
00775 n_private_.param("lk_num_levels", num_levels, 4);
00776 lkflow_.setNumLevels(num_levels);
00777 n_private_.param("lk_ratio_thresh", lkflow_.r_thresh_, 30.0);
00778 n_private_.param("max_flow_clusters", os_.max_k_, 2);
00779 n_private_.param("flow_cluster_max_iter", os_.kmeans_max_iter_, 200);
00780 n_private_.param("flow_cluster_epsilon", os_.kmeans_epsilon_, 0.05);
00781 n_private_.param("flow_cluster_attempts", os_.kmeans_tries_, 5);
00782 n_private_.param("affine_estimate_radius", os_.affine_estimate_radius_, 5);
00783 n_private_.param("min_affine_point_set_size", os_.min_affine_point_set_size_,
00784 100);
00785 n_private_.param("max_ransac_iters", os_.max_ransac_iters_,
00786 150);
00787 n_private_.param("affine_RANSAC_epsilon", os_.ransac_epsilon_, 1.0);
00788 n_private_.param("affine_RANSAC_inlier_percent",
00789 os_.ransac_inlier_percent_est_, 0.05);
00790 n_private_.param("minimum_new_cluster_separation",
00791 os_.minimum_new_cluster_separation_, 5.0);
00792 n_private_.param("surf_hessian_thresh", ft_.surf_.hessianThreshold,
00793 150.0);
00794 bool use_fast;
00795 n_private_.param("use_fast_corners", use_fast, false);
00796 ft_.setUseFast(use_fast);
00797 n_private_.param("image_hist_size", image_hist_size_, 5);
00798 n_private_.param("pcl_cluster_tolerance", pcl_segmenter_.cluster_tolerance_,
00799 0.25);
00800 n_private_.param("pcl_difference_thresh", pcl_segmenter_.cloud_diff_thresh_,
00801 0.01);
00802 n_private_.param("pcl_min_cluster_size", pcl_segmenter_.min_cluster_size_,
00803 100);
00804 n_private_.param("pcl_max_cluster_size", pcl_segmenter_.max_cluster_size_,
00805 2500);
00806 n_private_.param("normal_estimate_search_radius", norm_est_radius_, 0.03);
00807 n_private_.param("pcl_voxel_downsample_res", pcl_segmenter_.voxel_down_res_,
00808 0.005);
00809 n_private_.param("use_pcl_voxel_downsample", pcl_segmenter_.use_voxel_down_,
00810 true);
00811
00812
00813 sync_.registerCallback(&TabletopPushingPerceptionNode::sensorCallback,
00814 this);
00815 push_pose_server_ = n_.advertiseService(
00816 "get_push_pose", &TabletopPushingPerceptionNode::getPushPose, this);
00817 table_location_server_ = n_.advertiseService(
00818 "get_table_location", &TabletopPushingPerceptionNode::getTableLocation,
00819 this);
00820 motion_mask_pub_ = it_.advertise("motion_mask", 15);
00821 motion_img_pub_ = it_.advertise("motion_img", 15);
00822 arm_mask_pub_ = it_.advertise("arm_mask", 15);
00823 arm_img_pub_ = it_.advertise("arm_img", 15);
00824 pcl_segmenter_.pcl_obj_seg_pub_ = n_.advertise<sensor_msgs::PointCloud2>(
00825 "separate_table_objs", 1000);
00826 singulation_server_.start();
00827 }
00828
00829 void sensorCallback(const sensor_msgs::ImageConstPtr& img_msg,
00830 const sensor_msgs::ImageConstPtr& depth_msg,
00831 const sensor_msgs::PointCloud2ConstPtr& cloud_msg)
00832 {
00833
00834 cv::Mat color_frame(bridge_.imgMsgToCv(img_msg));
00835 cv::Mat depth_frame(bridge_.imgMsgToCv(depth_msg));
00836
00837
00838 cv::cvtColor(color_frame, color_frame, CV_RGB2BGR);
00839
00840
00841 XYZPointCloud cloud;
00842 pcl::fromROSMsg(*cloud_msg, cloud);
00843 tf_.waitForTransform(workspace_frame_, cloud.header.frame_id,
00844 cloud.header.stamp, ros::Duration(0.5));
00845 pcl_ros::transformPointCloud(workspace_frame_, cloud, cloud, tf_);
00846
00847
00848 for (int r = 0; r < depth_frame.rows; ++r)
00849 {
00850 float* depth_row = depth_frame.ptr<float>(r);
00851 for (int c = 0; c < depth_frame.cols; ++c)
00852 {
00853 float cur_d = depth_row[c];
00854 if (isnan(cur_d))
00855 {
00856 depth_row[c] = 0.0;
00857 }
00858 }
00859 }
00860
00861 cv::Mat workspace_mask(color_frame.rows, color_frame.cols, CV_8UC1,
00862 cv::Scalar(255));
00863
00864
00865 for (int r = 0; r < color_frame.rows; ++r)
00866 {
00867 uchar* workspace_row = workspace_mask.ptr<uchar>(r);
00868 for (int c = 0; c < color_frame.cols; ++c)
00869 {
00870
00871 pcl::PointXYZ cur_pt = cloud.at(c, r);
00872 if (cur_pt.x < min_workspace_x_ || cur_pt.x > max_workspace_x_ ||
00873 cur_pt.y < min_workspace_y_ || cur_pt.y > max_workspace_y_ ||
00874 cur_pt.z < min_workspace_z_ || cur_pt.z > max_workspace_z_ ||
00875 r < crop_min_y_ || c < crop_min_x_ || r > crop_max_y_ ||
00876 c > crop_max_x_ )
00877 {
00878 workspace_row[c] = 0;
00879 }
00880 }
00881 }
00882
00883
00884 cv::Mat color_frame_down = downSample(color_frame, num_downsamples_);
00885 cv::Mat depth_frame_down = downSample(depth_frame, num_downsamples_);
00886 cv::Mat workspace_mask_down = downSample(workspace_mask, num_downsamples_);
00887
00888
00889 prev_color_frame_ = cur_color_frame_.clone();
00890 prev_depth_frame_ = cur_depth_frame_.clone();
00891 prev_workspace_mask_ = cur_workspace_mask_.clone();
00892 prev_camera_header_ = cur_camera_header_;
00893
00894
00895 cur_color_frame_ = color_frame_down.clone();
00896 cur_depth_frame_ = depth_frame_down.clone();
00897 cur_workspace_mask_ = workspace_mask_down.clone();
00898 cur_point_cloud_ = cloud;
00899 have_depth_data_ = true;
00900 cur_camera_header_ = img_msg->header;
00901
00902
00903 if (autorun_pcl_segmentation_) getPushVector();
00904
00905
00906 updateTracks(cur_color_frame_, cur_depth_frame_, prev_color_frame_,
00907 prev_depth_frame_, cur_point_cloud_);
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918 #ifdef DISPLAY_INPUT_COLOR
00919 cv::imshow("color", cur_color_frame_);
00920 #endif // DISPLAY_INPUT_COLOR
00921 #ifdef DISPLAY_INPUT_DEPTH
00922 double depth_max = 1.0;
00923 cv::minMaxLoc(cur_depth_frame_, NULL, &depth_max);
00924 cv::Mat depth_display = cur_depth_frame_.clone();
00925 depth_display /= depth_max;
00926 cv::imshow("input_depth", depth_display);
00927 #endif // DISPLAY_INPUT_DEPTH
00928 #ifdef DISPLAY_WORKSPACE_MASK
00929 cv::imshow("workspace_mask", cur_workspace_mask_);
00930 #endif // DISPLAY_WORKSPACE_MASK
00931 #if defined DISPLAY_INPUT_COLOR || defined DISPLAY_INPUT_DEPTH || defined DISPLAY_OPTICAL_FLOW || defined DISPLAY_GRAPHCUT || defined DISPLAY_WORKSPACE_MASK || defined DISPLAY_OPT_FLOW_INTERNALS || defined DISPLAY_GRAPHCUT || defined VISUALIZE_GRAPH_WEIGHTS || defined VISUALIZE_ARM_GRAPH_WEIGHTS || defined DISPLAY_ARM_CIRCLES || defined DISPLAY_FLOW_FIELD_CLUSTERING
00932 cv::waitKey(display_wait_ms_);
00933 #endif // Any display defined
00934 }
00935
00936 bool getTableLocation(LocateTable::Request& req, LocateTable::Response& res)
00937 {
00938 if ( have_depth_data_ )
00939 {
00940 res.table_centroid = getTablePlane(cur_point_cloud_);
00941 if ((res.table_centroid.pose.position.x == 0.0 &&
00942 res.table_centroid.pose.position.y == 0.0 &&
00943 res.table_centroid.pose.position.z == 0.0) ||
00944 res.table_centroid.pose.position.x < 0.0)
00945 {
00946 ROS_ERROR_STREAM("No plane found, leaving");
00947 res.found_table = false;
00948 return false;
00949 }
00950 res.found_table = true;
00951 }
00952 else
00953 {
00954 ROS_ERROR_STREAM("Calling getTableLocation prior to receiving sensor data.");
00955 res.found_table = false;
00956 return false;
00957 }
00958 return true;
00959 }
00960
00961 bool getPushPose(PushPose::Request& req, PushPose::Response& res)
00962 {
00963 if ( have_depth_data_ )
00964 {
00965 res = findPushPose(cur_color_frame_, cur_depth_frame_, cur_point_cloud_,
00966 req.use_guided);
00967 }
00968 else
00969 {
00970 ROS_ERROR_STREAM("Calling getPushPose prior to receiving sensor data.");
00971 return false;
00972 }
00973 return true;
00974 }
00975
00976 PoseStamped getPushVector()
00977 {
00978 if (tracker_count_ == 1)
00979 {
00980 ROS_INFO_STREAM("Finding tabletop objects. tracker_count_ == 1");
00981 ProtoObjects objs;
00982 pcl_segmenter_.findTabletopObjects(objs, cur_point_cloud_);
00983 }
00984 else if (tracker_count_ > 1)
00985 {
00986 ROS_INFO_STREAM("Updating tabletop objects. tracker_count_ > 1");
00987
00988
00989 ProtoObjects objs = pcl_segmenter_.updateObjects(cur_point_cloud_);
00990
00991 return os_.getPushVector(motion_mask_hist_.back(),
00992 arm_mask_hist_.back(),
00993 workspace_mask_hist_.back(),
00994 color_frame_hist_.back(),
00995 depth_frame_hist_.back(),
00996 flow_u_hist_.back(),
00997 flow_v_hist_.back(), objs);
00998 }
00999 PoseStamped empty;
01000 return empty;
01001 }
01002
01003 PushPose::Response findPushPose(cv::Mat visual_frame,
01004 cv::Mat depth_frame,
01005 XYZPointCloud& cloud, bool use_guided)
01006 {
01007 PushPose::Response res;
01008 if (use_guided)
01009 {
01010 res.push_pose = getPushVector();
01011 }
01012 else
01013 {
01014 res.push_pose = findRandomPushPose(cloud);
01015 }
01016 res.invalid_push_pose = false;
01017 return res;
01018 }
01019
01020
01021
01022
01023
01024 void trackerGoalCallback(
01025 const tabletop_pushing::ObjectSingulationGoalConstPtr &goal)
01026 {
01027 if (goal->init)
01028 {
01029 ROS_INFO_STREAM("Initializing tracker.");
01030 initTracker();
01031 tabletop_pushing::ObjectSingulationResult result;
01032 singulation_server_.setSucceeded(result);
01033 }
01034
01035 if (goal->start)
01036 {
01037 ROS_INFO_STREAM("Starting tracker.");
01038 startTracker();
01039 tabletop_pushing::ObjectSingulationResult result;
01040 singulation_server_.setSucceeded(result);
01041 }
01042 else
01043 {
01044 ROS_INFO_STREAM("Stopping tracker.");
01045 stopTracker();
01046 tabletop_pushing::ObjectSingulationResult result;
01047 if (goal->get_singulation_vector)
01048 {
01049 result.singulation_vector = getPushVector();
01050 }
01051 singulation_server_.setSucceeded(result);
01052
01053 }
01054 }
01055
01056 void initTracker()
01057 {
01058 tracker_initialized_ = false;
01059 tracking_ = false;
01060 }
01061
01062 void startTracker()
01063 {
01064
01065 tracking_ = true;
01066 }
01067
01068 void stopTracker()
01069 {
01070
01071 tracking_ = false;
01072 }
01073
01074 void updateTracks(cv::Mat color_frame, cv::Mat& depth_frame,
01075 cv::Mat& prev_color_frame, cv::Mat& prev_depth_frame,
01076 XYZPointCloud& cloud)
01077 {
01078
01079 cv::Mat gray_frame;
01080 cv::cvtColor(color_frame, gray_frame, CV_BGR2GRAY);
01081
01082 if (!tracker_initialized_)
01083 {
01084 cam_info_ = *ros::topic::waitForMessage<sensor_msgs::CameraInfo>(
01085 cam_info_topic_, n_, ros::Duration(5.0));
01086
01087 table_centroid_ = getTablePlane(cloud);
01088 if (table_centroid_.pose.position.x == 0.0 &&
01089 table_centroid_.pose.position.y == 0.0 &&
01090 table_centroid_.pose.position.z == 0.0)
01091 {
01092 ROS_DEBUG_STREAM("No plane found!");
01093 }
01094 else
01095 {
01096 min_workspace_z_ = table_centroid_.pose.position.z - below_table_z_;
01097 n_private_.setParam("min_workspace_z", min_workspace_z_);
01098 ROS_DEBUG_STREAM("Found plane");
01099 }
01100
01101 ft_.initTracks(gray_frame);
01102
01103 tracker_initialized_ = true;
01104 tracker_count_ = 0;
01105 return;
01106 }
01107 if (!tracking_)
01108 {
01109 return;
01110 }
01111
01112 AffineFlowMeasures sparse_flow = ft_.updateTracks(gray_frame,
01113 cur_workspace_mask_);
01114 ++tracker_count_;
01115 }
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318 cv::Point projectPointIntoImage(PointStamped cur_point,
01319 std::string target_frame)
01320 {
01321 cv::Point img_loc;
01322 try
01323 {
01324
01325 PointStamped image_frame_loc_m;
01326 tf_.transformPoint(target_frame, cur_point, image_frame_loc_m);
01327
01328 img_loc.x = static_cast<int>((cam_info_.K[0]*image_frame_loc_m.point.x +
01329 cam_info_.K[2]*image_frame_loc_m.point.z) /
01330 image_frame_loc_m.point.z);
01331 img_loc.y = static_cast<int>((cam_info_.K[4]*image_frame_loc_m.point.y +
01332 cam_info_.K[5]*image_frame_loc_m.point.z) /
01333 image_frame_loc_m.point.z);
01334
01335
01336 for (int i = 0; i < num_downsamples_; ++i)
01337 {
01338 img_loc.x /= 2;
01339 img_loc.y /= 2;
01340 }
01341 }
01342 catch (tf::TransformException e)
01343 {
01344
01345 }
01346 return img_loc;
01347 }
01348
01349 cv::Point projectPointIntoImage(PoseStamped cur_pose,
01350 std::string target_frame)
01351 {
01352 PointStamped cur_point;
01353 cur_point.header = cur_pose.header;
01354 cur_point.point = cur_pose.pose.position;
01355 return projectPointIntoImage(cur_point, target_frame);
01356 }
01357
01358 bool getLineValues(cv::Point p1, cv::Point p2, std::vector<cv::Point>& line,
01359 cv::Size frame_size,
01360 int &min_x, int &max_x, int &min_y, int &max_y)
01361 {
01362 int num_points_added = 0;
01363 bool steep = (abs(p1.y - p2.y) > abs(p1.x - p2.x));
01364 if (steep)
01365 {
01366
01367 cv::Point tmp(p1.y, p1.x);
01368 p1.x = tmp.x;
01369 p1.y = tmp.y;
01370 tmp.y = p2.x;
01371 tmp.x = p2.y;
01372 p2.x = tmp.x;
01373 p2.y = tmp.y;
01374 }
01375 if (p1.x > p2.x)
01376 {
01377
01378 cv::Point tmp(p1.x, p1.y);
01379 p1.x = p2.x;
01380 p1.y = p2.y;
01381 p2.x = tmp.x;
01382 p2.y = tmp.y;
01383 }
01384 int dx = p2.x - p1.x;
01385 int dy = abs(p2.y - p1.y);
01386 int error = dx / 2;
01387 int ystep = 0;
01388 if (p1.y < p2.y)
01389 {
01390 ystep = 1;
01391 }
01392 else if (p1.y > p2.y)
01393 {
01394 ystep = -1;
01395 }
01396 for(int x = p1.x, y = p1.y; x <= p2.x; ++x)
01397 {
01398 if (steep)
01399 {
01400 cv::Point p_new(y,x);
01401
01402 if (x < 0 || y < 0 || x >= frame_size.height || y >= frame_size.width ||
01403 (x == 0 && y == 0))
01404 {
01405 }
01406 else
01407 {
01408 if (p_new.x < min_x)
01409 min_x = p_new.x;
01410 if (p_new.x > max_x)
01411 max_x = p_new.x;
01412 if (p_new.y < min_y)
01413 min_y = p_new.y;
01414 if (p_new.y > max_y)
01415 max_y = p_new.y;
01416 line.push_back(p_new);
01417 ++num_points_added;
01418 }
01419 }
01420 else
01421 {
01422 cv::Point p_new(x,y);
01423
01424 if (x < 0 || y < 0 || x >= frame_size.width || y >= frame_size.height ||
01425 (x == 0 && y == 0))
01426 {
01427 }
01428 else
01429 {
01430 if (p_new.x < min_x)
01431 min_x = p_new.x;
01432 if (p_new.x > max_x)
01433 max_x = p_new.x;
01434 if (p_new.y < min_y)
01435 min_y = p_new.y;
01436 if (p_new.y > max_y)
01437 max_y = p_new.y;
01438 line.push_back(p_new);
01439 ++num_points_added;
01440 }
01441 }
01442 error -= dy;
01443 if (error < 0)
01444 {
01445 y += ystep;
01446 error += dx;
01447 }
01448 }
01449 return (num_points_added > 0);
01450 }
01451
01452 ArmModel projectArmPoses(std_msgs::Header img_header, cv::Size frame_size,
01453 int &min_x, int &max_x, int &min_y, int &max_y)
01454 {
01455
01456 ArmModel arm_locs;
01457
01458
01459 cv::Point ll0 = projectJointOriginIntoImage(img_header,
01460 "l_gripper_l_finger_tip_link");
01461 cv::Point ll1 = projectJointOriginIntoImage(img_header,
01462 "l_gripper_l_finger_link");
01463 cv::Point lr0 = projectJointOriginIntoImage(img_header,
01464 "l_gripper_r_finger_tip_link");
01465 cv::Point lr1 = projectJointOriginIntoImage(img_header,
01466 "l_gripper_r_finger_link");
01467 cv::Point lp = projectJointOriginIntoImage(img_header,
01468 "l_gripper_palm_link");
01469
01470
01471 cv::Point l1 = projectJointOriginIntoImage(img_header, "l_wrist_flex_link");
01472 cv::Point l2 = projectJointOriginIntoImage(img_header, "l_forearm_link");
01473 cv::Point l3 = projectJointOriginIntoImage(img_header, "l_upper_arm_link");
01474 arm_locs.l_chain.push_back(lp);
01475 arm_locs.l_chain.push_back(ll1);
01476 arm_locs.l_chain.push_back(ll0);
01477 arm_locs.l_chain.push_back(lr0);
01478 arm_locs.l_chain.push_back(lr1);
01479 arm_locs.l_chain.push_back(lp);
01480 arm_locs.l_chain.push_back(l1);
01481 arm_locs.l_chain.push_back(l2);
01482 arm_locs.l_chain.push_back(l3);
01483
01484
01485 cv::Point rl0 = projectJointOriginIntoImage(img_header,
01486 "r_gripper_l_finger_tip_link");
01487 cv::Point rl1 = projectJointOriginIntoImage(img_header,
01488 "r_gripper_l_finger_link");
01489 cv::Point rr0 = projectJointOriginIntoImage(img_header,
01490 "r_gripper_r_finger_tip_link");
01491 cv::Point rr1 = projectJointOriginIntoImage(img_header,
01492 "r_gripper_r_finger_link");
01493 cv::Point rp = projectJointOriginIntoImage(img_header,
01494 "r_gripper_palm_link");
01495
01496
01497
01498 cv::Point r1 = projectJointOriginIntoImage(img_header, "r_wrist_flex_link");
01499 cv::Point r2 = projectJointOriginIntoImage(img_header, "r_forearm_link");
01500 cv::Point r3 = projectJointOriginIntoImage(img_header, "r_upper_arm_link");
01501 arm_locs.r_chain.push_back(rp);
01502 arm_locs.r_chain.push_back(rl1);
01503 arm_locs.r_chain.push_back(rl0);
01504 arm_locs.r_chain.push_back(rr0);
01505 arm_locs.r_chain.push_back(rr1);
01506 arm_locs.r_chain.push_back(rp);
01507 arm_locs.r_chain.push_back(r1);
01508 arm_locs.r_chain.push_back(r2);
01509 arm_locs.r_chain.push_back(r3);
01510
01511
01512 min_x = 10000;
01513 max_x = 0;
01514 min_y = 10000;
01515 max_y = 0;
01516
01517
01518 arm_locs.l_hand_on = getLineValues(ll0, ll1, arm_locs.hands, frame_size,
01519 min_x, max_x, min_y, max_y);
01520 arm_locs.l_hand_on = (getLineValues(ll1, lp, arm_locs.hands, frame_size,
01521 min_x, max_x, min_y, max_y) ||
01522 arm_locs.l_hand_on);
01523 arm_locs.l_hand_on = (getLineValues(lr0, lr1, arm_locs.hands, frame_size,
01524 min_x, max_x, min_y, max_y) ||
01525 arm_locs.l_hand_on);
01526 arm_locs.l_hand_on = (getLineValues(lr1, lp, arm_locs.hands, frame_size,
01527 min_x, max_x, min_y, max_y) ||
01528 arm_locs.l_hand_on);
01529
01530 arm_locs.l_arm_on = getLineValues(lp, l1, arm_locs.arms, frame_size,
01531 min_x, max_x, min_y, max_y);
01532 arm_locs.l_arm_on = (getLineValues(l1, l2, arm_locs.arms, frame_size,
01533 min_x, max_x, min_y, max_y) ||
01534 arm_locs.l_arm_on);
01535 arm_locs.l_arm_on = (getLineValues(l2, l3, arm_locs.arms, frame_size,
01536 min_x, max_x, min_y, max_y) ||
01537 arm_locs.l_arm_on);
01538
01539 arm_locs.r_hand_on = (getLineValues(rl0, rl1, arm_locs.hands, frame_size,
01540 min_x, max_x, min_y, max_y) ||
01541 arm_locs.r_hand_on);
01542 arm_locs.r_hand_on = (getLineValues(rl1, rp, arm_locs.hands, frame_size,
01543 min_x, max_x, min_y, max_y) ||
01544 arm_locs.r_hand_on);
01545 arm_locs.r_hand_on = (getLineValues(rr0, rr1, arm_locs.hands, frame_size,
01546 min_x, max_x, min_y, max_y) ||
01547 arm_locs.r_hand_on);
01548 arm_locs.r_hand_on = (getLineValues(rr1, rp, arm_locs.hands, frame_size,
01549 min_x, max_x, min_y, max_y) ||
01550 arm_locs.r_hand_on);
01551
01552 arm_locs.r_arm_on = getLineValues(rp, r1, arm_locs.arms, frame_size,
01553 min_x, max_x, min_y, max_y);
01554 arm_locs.r_arm_on = (getLineValues(r1, r2, arm_locs.arms, frame_size,
01555 min_x, max_x, min_y, max_y) ||
01556 arm_locs.r_arm_on);
01557 arm_locs.r_arm_on = (getLineValues(r2, r3, arm_locs.arms, frame_size,
01558 min_x, max_x, min_y, max_y) ||
01559 arm_locs.r_arm_on);
01560 return arm_locs;
01561 }
01562
01563 cv::Point projectJointOriginIntoImage(std_msgs::Header img_header,
01564 std::string joint_name)
01565 {
01566 PointStamped joint_origin;
01567 joint_origin.header.frame_id = joint_name;
01568 joint_origin.header.stamp = img_header.stamp;
01569 joint_origin.point.x = 0.0;
01570 joint_origin.point.y = 0.0;
01571 joint_origin.point.z = 0.0;
01572
01573 if (joint_name == "r_gripper_tool_frame" ||
01574 joint_name == "l_gripper_tool_frame" ||
01575 joint_name == "l_gripper_l_finger_tip_link" ||
01576 joint_name == "l_gripper_l_finger_link" ||
01577 joint_name == "l_gripper_r_finger_tip_link" ||
01578 joint_name == "l_gripper_r_finger_link" ||
01579 joint_name == "r_gripper_l_finger_tip_link" ||
01580 joint_name == "r_gripper_l_finger_link" ||
01581 joint_name == "r_gripper_r_finger_tip_link" ||
01582 joint_name == "r_gripper_r_finger_link" ||
01583 joint_name == "r_gripper_tool_frame")
01584 {
01585 joint_origin.point.z = 0.01;
01586 if (joint_name == "r_gripper_l_finger_link" ||
01587 joint_name == "l_gripper_l_finger_link")
01588 {
01589 joint_origin.point.y = 0.02;
01590 }
01591 else if (joint_name == "r_gripper_r_finger_link" ||
01592 joint_name == "l_gripper_r_finger_link")
01593 {
01594 joint_origin.point.y = -0.02;
01595 }
01596 }
01597
01598 if (joint_name == "r_upper_arm_link")
01599 {
01600 joint_origin.point.y = -0.05;
01601 }
01602
01603 if (joint_name == "l_upper_arm_link")
01604 {
01605 joint_origin.point.y = 0.05;
01606 }
01607 if (joint_name == "r_gripper_palm_link")
01608 {
01609 joint_origin.point.x = 0.05;
01610 }
01611 if (joint_name == "l_gripper_palm_link")
01612 {
01613 joint_origin.point.x = 0.05;
01614 }
01615 return projectPointIntoImage(joint_origin, img_header.frame_id);
01616 }
01617
01618 void drawTablePlaneOnImage(XYZPointCloud& plane, PoseStamped cent)
01619 {
01620 cv::Mat plane_display = cur_color_frame_.clone();
01621 std::vector<cv::Point> table_points;
01622 for (unsigned int i = 0; i < plane.points.size(); ++i)
01623 {
01624 PointStamped h;
01625 h.header = plane.header;
01626 h.point.x = plane.points[i].x;
01627 h.point.y = plane.points[i].y;
01628 h.point.z = plane.points[i].z;
01629 cv::Point p = projectPointIntoImage(h, cur_camera_header_.frame_id);
01630 table_points.push_back(p);
01631 #ifdef DISPLAY_PLANE_ESTIMATE
01632 cv::circle(plane_display, p, 2, cv::Scalar(0,255,0));
01633 #endif // DISPLAY_PLANE_ESTIMATE
01634 }
01635
01636 #ifdef USE_TABLE_COLOR_ESTIMATE
01637 ROS_INFO_STREAM("Calculating table color stats.");
01638 mgc_.setTableColorStats(cur_color_frame_, table_points);
01639 #endif // USE_TABLE_COLOR_ESTIMATE
01640
01641 #ifdef DISPLAY_PLANE_ESTIMATE
01642 cv::Point cent_img = projectPointIntoImage(cent,
01643 cur_camera_header_.frame_id);
01644 cv::circle(plane_display, cent_img, 5, cv::Scalar(0,0,255));
01645 cv::imshow("table_image", plane_display);
01646 #endif // DISPLAY_PLANE_ESTIMATE
01647 }
01648
01649
01650
01651
01652 cv::Mat downSample(cv::Mat data_in, int scales)
01653 {
01654 cv::Mat out = data_in.clone();
01655 for (int i = 0; i < scales; ++i)
01656 {
01657 cv::pyrDown(data_in, out);
01658 data_in = out;
01659 }
01660 return out;
01661 }
01662
01663 cv::Mat upSample(cv::Mat data_in, int scales)
01664 {
01665 cv::Mat out = data_in.clone();
01666 for (int i = 0; i < scales; ++i)
01667 {
01668
01669 cv::Size out_size(data_in.cols*2, data_in.rows*2);
01670 cv::pyrUp(data_in, out, out_size);
01671 data_in = out;
01672 }
01673 return out;
01674 }
01675
01676 cv::Mat getTableHeightDistances()
01677 {
01678 cv::Mat table_distances(cur_depth_frame_.size(), CV_32FC1, cv::Scalar(0.0));
01679 const float table_height = table_centroid_.pose.position.z;
01680 for (int r = 0; r < table_distances.rows; ++r)
01681 {
01682 for (int c = 0; c < table_distances.cols; ++c)
01683 {
01684 pcl::PointXYZ cur_pt = cur_point_cloud_.at(2*c, 2*r);
01685 if (isnan(cur_pt.x) || isnan(cur_pt.y) || isnan(cur_pt.z))
01686 {
01687
01688 table_distances.at<float>(r,c) = 3.0;
01689 }
01690 else
01691 {
01692 table_distances.at<float>(r,c) = cur_pt.z - table_height;
01693 }
01694 }
01695 }
01696 #ifdef DISPLAY_TABLE_DISTANCES
01697 cv::imshow("table_distances_raw", table_distances);
01698 #endif // DISPLAY_TABLE_DISTANCES
01699 return table_distances;
01700 }
01701
01702 PoseStamped getTablePlane(XYZPointCloud& cloud)
01703 {
01704 Eigen::Vector4f table_centroid = pcl_segmenter_.getTablePlane(cloud);
01705 PoseStamped p;
01706 p.pose.position.x = table_centroid[0];
01707 p.pose.position.y = table_centroid[1];
01708 p.pose.position.z = table_centroid[2];
01709 p.header = cloud.header;
01710 ROS_INFO_STREAM("Table centroid is: ("
01711 << p.pose.position.x << ", "
01712 << p.pose.position.y << ", "
01713 << p.pose.position.z << ")");
01714
01715
01716 return p;
01717 }
01718
01719 PoseStamped findRandomPushPose(XYZPointCloud& input_cloud)
01720 {
01721 ProtoObjects objs;
01722 pcl_segmenter_.findTabletopObjects(input_cloud, objs);
01723 prev_proto_objs_ = cur_proto_objs_;
01724 cur_proto_objs_ = objs;
01725
01726 ROS_INFO_STREAM("Found " << objs.size() << " objects.");
01727
01728
01729
01730
01731 std::vector<Eigen::Vector4f> cluster_centroids;
01732 for (unsigned int i = 0; i < objs.size(); ++i)
01733 {
01734 if (objs[i].centroid[0] > min_pushing_x_ &&
01735 objs[i].centroid[0] < max_pushing_x_ &&
01736 objs[i].centroid[1] > min_pushing_y_ &&
01737 objs[i].centroid[1] < max_pushing_y_)
01738 {
01739 cluster_centroids.push_back(objs[i].centroid);
01740 }
01741 }
01742 geometry_msgs::PoseStamped p;
01743
01744 if (cluster_centroids.size() < 1)
01745 {
01746 ROS_WARN_STREAM("No object clusters found! Returning empty push_pose");
01747 p.header.frame_id = "/torso_lift_link";
01748 return p;
01749 }
01750 ROS_INFO_STREAM("Found " << cluster_centroids.size() << " proto objects");
01751 int rand_idx = rand() % cluster_centroids.size();
01752 Eigen::Vector4f obj_xyz_centroid = cluster_centroids[rand_idx];
01753 p.pose.position.x = obj_xyz_centroid[0];
01754 p.pose.position.y = obj_xyz_centroid[1];
01755
01756 p.pose.position.z = objs[0].table_centroid[2];
01757 ROS_INFO_STREAM("Chosen push pose is at: (" << obj_xyz_centroid[0] << ", "
01758 << obj_xyz_centroid[1] << ", " << objs[0].table_centroid[2]
01759 << ")");
01760
01761 p.pose.orientation.x = 0;
01762 p.pose.orientation.y = 0;
01763 p.pose.orientation.z = 0;
01764 p.pose.orientation.w = 0;
01765
01766 p.header.frame_id = "/torso_lift_link";
01767 return p;
01768 }
01769
01770 XYZPointCloud getMaskedPointCloud(XYZPointCloud& input_cloud, cv::Mat& mask_in)
01771 {
01772
01773 cv::Mat mask = upSample(mask_in, num_downsamples_);
01774
01775
01776 pcl::PointIndices mask_indices;
01777 mask_indices.header = input_cloud.header;
01778 for (int y = 0; y < mask.rows; ++y)
01779 {
01780 uchar* mask_row = mask.ptr<uchar>(y);
01781 for (int x = 0; x < mask.cols; ++x)
01782 {
01783 if (mask_row[x] != 0)
01784 {
01785 mask_indices.indices.push_back(y*input_cloud.width + x);
01786 }
01787 }
01788 }
01789
01790 XYZPointCloud masked_cloud;
01791 pcl::copyPointCloud(input_cloud, mask_indices, masked_cloud);
01792 return masked_cloud;
01793 }
01794
01798 void spin()
01799 {
01800 while(n_.ok())
01801 {
01802 ros::spinOnce();
01803 }
01804 }
01805
01806 protected:
01807 ros::NodeHandle n_;
01808 ros::NodeHandle n_private_;
01809 message_filters::Subscriber<sensor_msgs::Image> image_sub_;
01810 message_filters::Subscriber<sensor_msgs::Image> depth_sub_;
01811 message_filters::Subscriber<sensor_msgs::PointCloud2> cloud_sub_;
01812 message_filters::Synchronizer<MySyncPolicy> sync_;
01813 image_transport::ImageTransport it_;
01814 sensor_msgs::CameraInfo cam_info_;
01815 image_transport::Publisher motion_img_pub_;
01816 image_transport::Publisher motion_mask_pub_;
01817 image_transport::Publisher arm_img_pub_;
01818 image_transport::Publisher arm_mask_pub_;
01819 actionlib::SimpleActionServer<tabletop_pushing::
01820 ObjectSingulationAction> singulation_server_;
01821 sensor_msgs::CvBridge bridge_;
01822 tf::TransformListener tf_;
01823 ros::ServiceServer push_pose_server_;
01824 ros::ServiceServer table_location_server_;
01825 cv::Mat cur_color_frame_;
01826 cv::Mat cur_depth_frame_;
01827 cv::Mat cur_workspace_mask_;
01828 cv::Mat prev_color_frame_;
01829 cv::Mat prev_depth_frame_;
01830 cv::Mat prev_workspace_mask_;
01831 cv::Mat prev_seg_mask_;
01832 std::deque<cv::Mat> motion_mask_hist_;
01833 std::deque<cv::Mat> arm_mask_hist_;
01834 std::deque<cv::Mat> workspace_mask_hist_;
01835 std::deque<cv::Mat> color_frame_hist_;
01836 std::deque<cv::Mat> depth_frame_hist_;
01837 std::deque<cv::Mat> flow_u_hist_;
01838 std::deque<cv::Mat> flow_v_hist_;
01839 std_msgs::Header cur_camera_header_;
01840 std_msgs::Header prev_camera_header_;
01841 XYZPointCloud cur_point_cloud_;
01842 PointCloudSegmentation pcl_segmenter_;
01843 ObjectSingulation os_;
01844 bool have_depth_data_;
01845 int crop_min_x_;
01846 int crop_max_x_;
01847 int crop_min_y_;
01848 int crop_max_y_;
01849 int display_wait_ms_;
01850 double min_workspace_x_;
01851 double max_workspace_x_;
01852 double min_workspace_y_;
01853 double max_workspace_y_;
01854 double min_workspace_z_;
01855 double max_workspace_z_;
01856 double min_pushing_x_;
01857 double max_pushing_x_;
01858 double min_pushing_y_;
01859 double max_pushing_y_;
01860 double below_table_z_;
01861 int num_downsamples_;
01862 std::string workspace_frame_;
01863 PoseStamped table_centroid_;
01864 bool tracking_;
01865 bool tracker_initialized_;
01866 std::string cam_info_topic_;
01867 int tracker_count_;
01868 std::string base_output_path_;
01869 int image_hist_size_;
01870 double norm_est_radius_;
01871 bool autorun_pcl_segmentation_;
01872 bool auto_flow_cluster_;
01873 bool segmenting_moving_stuff_;
01874 ProtoObjects prev_proto_objs_;
01875 ProtoObjects cur_proto_objs_;
01876 };
01877
01878 int main(int argc, char ** argv)
01879 {
01880 srand(time(NULL));
01881 ros::init(argc, argv, "tabletop_perception_node");
01882 ros::NodeHandle n;
01883 MGCNode perception_node(n);
01884 perception_node.spin();
01885
01886 return 0;
01887 }