00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 #include "jsk_pcl_ros/edgebased_cube_finder.h"
00037 #include <pcl/kdtree/kdtree_flann.h>
00038 #include <pcl/common/centroid.h>
00039 #include "jsk_recognition_utils/pcl_conversion_util.h"
00040 #include <jsk_recognition_msgs/BoundingBoxArray.h>
00041 #include <geometry_msgs/PoseArray.h>
00042 #include <pcl/filters/extract_indices.h>
00043 #include <visualization_msgs/Marker.h>
00044 #include <eigen_conversions/eigen_msg.h>
00045 #include <pcl/sample_consensus/method_types.h>
00046 #include <pcl/sample_consensus/model_types.h>
00047 #include <pcl/segmentation/sac_segmentation.h>
00048 #include <pcl/common/angles.h>
00049 #include <jsk_recognition_msgs/PolygonArray.h>
00050 #include <jsk_recognition_msgs/ClusterPointIndices.h>
00051 #include <pcl/filters/project_inliers.h>
00052 #include <pcl/surface/convex_hull.h>
00053 #include <pcl_conversions/pcl_conversions.h>
00054 
00055 namespace jsk_pcl_ros
00056 {
00057   CubeHypothesis::CubeHypothesis(const IndicesPair& pair,
00058                                  const CoefficientsPair& coefficients_pair,
00059                                  const double outlier_threshold):
00060     value_(0.0), indices_pair_(pair), coefficients_pair_(coefficients_pair),
00061     outlier_threshold_(outlier_threshold_)
00062   {
00063 
00064   }
00065   
00066   CubeHypothesis::~CubeHypothesis()
00067   {
00068   }
00069 
00070   void CubeHypothesis::computeCentroid(
00071     const pcl::PointCloud<pcl::PointXYZRGB>::Ptr& cloud,
00072     const pcl::PointIndices::Ptr& indices,
00073     Eigen::Vector3f& output)
00074   {
00075     Eigen::Vector4f centroid;
00076     
00077     pcl::PointCloud<pcl::PointXYZRGB>::Ptr target_cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
00078     pcl::ExtractIndices<pcl::PointXYZRGB> ex;
00079     ex.setInputCloud(cloud);
00080     ex.setIndices(indices);
00081     ex.filter(*target_cloud);
00082     pcl::compute3DCentroid(*target_cloud, centroid);
00083     jsk_recognition_utils::pointFromVectorToVector<Eigen::Vector4f, Eigen::Vector3f>(centroid, output);
00084   }
00085 
00086   void CubeHypothesis::getLinePoints(
00087     const jsk_recognition_utils::Line& line,
00088     const pcl::PointCloud<pcl::PointXYZRGB>& cloud,
00089     const pcl::PointIndices::Ptr indices,
00090     jsk_recognition_utils::Vertices& output)
00091   {
00092     pcl::PointCloud<pcl::PointXYZRGB>::Ptr points
00093       (new pcl::PointCloud<pcl::PointXYZRGB>);
00094     pcl::ExtractIndices<pcl::PointXYZRGB> extract;
00095     extract.setInputCloud(cloud.makeShared());
00096     extract.setIndices(indices);
00097     extract.filter(*points);
00098     for (size_t i = 0; i < points->points.size(); i++) {
00099       pcl::PointXYZRGB p = points->points[i];
00100       Eigen::Vector3f p_eigen = p.getVector3fMap();
00101       Eigen::Vector3f foot_point;
00102       line.foot(p_eigen, foot_point);
00103       output.push_back(foot_point);
00104     }
00105   }
00106 
00107   jsk_recognition_utils::ConvexPolygon::Ptr CubeHypothesis::buildConvexPolygon(
00108     const jsk_recognition_utils::PointPair& a_edge_pair, const jsk_recognition_utils::PointPair& b_edge_pair)
00109   {
00110     jsk_recognition_utils::Vertices vertices;
00111     vertices.push_back(a_edge_pair.get<0>());
00112     vertices.push_back(a_edge_pair.get<1>());
00113     vertices.push_back(b_edge_pair.get<1>());
00114     vertices.push_back(b_edge_pair.get<0>());
00115     jsk_recognition_utils::ConvexPolygon::Ptr convex (new jsk_recognition_utils::ConvexPolygon(vertices));
00116     return convex;
00117   }
00118   
00119   double CubeHypothesis::evaluatePointOnPlanes(
00120     const pcl::PointCloud<pcl::PointXYZRGB>& cloud,
00121     jsk_recognition_utils::ConvexPolygon& polygon_a,
00122     jsk_recognition_utils::ConvexPolygon& polygon_b)
00123   {
00124     std::vector<int> a_indices, b_indices;
00125     for (size_t i = 0; i < cloud.points.size(); i++) {
00126       pcl::PointXYZRGB pcl_point = cloud.points[i];
00127       if (pcl_isfinite(pcl_point.x) &&
00128           pcl_isfinite(pcl_point.y) &&
00129           pcl_isfinite(pcl_point.z)) { 
00130         Eigen::Vector3f eigen_point = pcl_point.getVector3fMap();
00131         if (polygon_a.distanceSmallerThan(eigen_point, outlier_threshold_)) {
00132           a_indices.push_back(i);
00133         }
00134         if (polygon_b.distanceSmallerThan(eigen_point, outlier_threshold_)) {
00135           b_indices.push_back(i);
00136         }
00137       }
00138     }
00139     
00140     return a_indices.size() + b_indices.size();
00141   }
00142   
00143   jsk_recognition_utils::PointPair CubeHypothesis::computeAxisEndPoints(
00144     const jsk_recognition_utils::Line& axis,
00145     const jsk_recognition_utils::PointPair& a_candidates,
00146     const jsk_recognition_utils::PointPair& b_candidates)
00147   {
00148     jsk_recognition_utils::Vertices original_points;
00149     original_points.push_back(a_candidates.get<0>());
00150     original_points.push_back(a_candidates.get<1>());
00151     original_points.push_back(b_candidates.get<0>());
00152     original_points.push_back(b_candidates.get<1>());
00153     for (size_t i = 0; i < original_points.size(); i++) {
00154       Eigen::Vector3f p = original_points[i];
00155       ROS_INFO("[foot_point] [%f, %f, %f]", p[0], p[1], p[2]);
00156     }
00157     
00158     jsk_recognition_utils::Vertices foot_points;
00159     for (size_t i = 0; i < original_points.size(); i++) {
00160       Eigen::Vector3f foot_point;
00161       axis.foot(original_points[i], foot_point);
00162       foot_points.push_back(foot_point);
00163     }
00164     double max_alpha = -DBL_MAX;
00165     double min_alpha = DBL_MAX;
00166     Eigen::Vector3f max_alpha_point, min_alpha_point;
00167     
00168     for (size_t i = 0; i < foot_points.size(); i++) {
00169       double alpha = axis.computeAlpha(foot_points[i]);
00170       if (alpha > max_alpha) {
00171         max_alpha = alpha;
00172         max_alpha_point = foot_points[i];
00173       }
00174       if (alpha < min_alpha) {
00175         min_alpha = alpha;
00176         min_alpha_point = foot_points[i];
00177       }
00178     }
00179     ROS_INFO("min_alpha_point: [%f, %f, %f]", min_alpha_point[0], min_alpha_point[1], min_alpha_point[2]);
00180     ROS_INFO("max_alpha_point: [%f, %f, %f]", max_alpha_point[0], max_alpha_point[1], max_alpha_point[2]);
00181     return boost::make_tuple(min_alpha_point, max_alpha_point);
00182   }
00183 
00184   
00185   PlanarCubeHypothesis::PlanarCubeHypothesis(
00186     const IndicesPair& pair, const CoefficientsPair& coefficients_pair, const double outlier_threshold):
00187     CubeHypothesis(pair, coefficients_pair, outlier_threshold)
00188   {
00189 
00190   }
00191   
00192   DiagnoalCubeHypothesis::DiagnoalCubeHypothesis(
00193     const IndicesPair& pair, const CoefficientsPair& coefficients_pair,
00194     const double outlier_threshold):
00195     CubeHypothesis(pair, coefficients_pair, outlier_threshold), resolution_(10)
00196   {
00197 
00198   }
00199 
00200   void DiagnoalCubeHypothesis::estimate(
00201     const pcl::PointCloud<pcl::PointXYZRGB>& cloud)
00202   {
00203     const double dt = (M_PI - 2.0 * min_angle_) / resolution_;
00204     jsk_recognition_utils::Line::Ptr line_a
00205       = jsk_recognition_utils::Line::fromCoefficients(coefficients_pair_.get<0>()->values);
00206     jsk_recognition_utils::Line::Ptr line_b
00207       = jsk_recognition_utils::Line::fromCoefficients(coefficients_pair_.get<1>()->values);
00208     if (!line_a->isSameDirection(*line_b)) {
00209       line_b = line_b->flip();
00210     }
00211     
00212     const double r2 = line_a->distance(*line_b);
00213     const double r = r2 / 2;
00214     jsk_recognition_utils::Line::Ptr axis = line_a->midLine(*line_b);
00215     Eigen::Vector3f center;
00216     axis->getOrigin(center);
00217     ROS_INFO("line_a:");
00218     line_a->print();
00219     ROS_INFO("line_b:");
00220     line_b->print();
00221     ROS_INFO("axis:");
00222     axis->print();
00223     ROS_INFO("r: %f", r);
00224     
00225     
00226     
00227     
00228     
00229     Eigen::Vector3f centroid_a, centroid_b;
00230     pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_ptr = cloud.makeShared();
00231     computeCentroid(cloud_ptr, indices_pair_.get<0>(), centroid_a);
00232     computeCentroid(cloud_ptr, indices_pair_.get<1>(), centroid_b);
00233     ROS_INFO("centroid_a: [%f, %f, %f]", centroid_a[0], centroid_a[1], centroid_a[2]);
00234     ROS_INFO("centroid_b: [%f, %f, %f]", centroid_b[0], centroid_b[1], centroid_b[2]);
00235     jsk_recognition_utils::Line::Ptr line_a_aligned = axis->parallelLineOnAPoint(centroid_a);
00236     jsk_recognition_utils::Line::Ptr line_b_aligned = axis->parallelLineOnAPoint(centroid_b);
00237     ROS_INFO("line_a_aligned:");
00238     line_a_aligned->print();
00239     ROS_INFO("line_b_aligned:");
00240     line_b_aligned->print();
00241     
00242     jsk_recognition_utils::Vertices line_a_points, line_b_points;
00243     getLinePoints(*line_a_aligned, cloud, indices_pair_.get<0>(),
00244                   line_a_points);
00245     getLinePoints(*line_b_aligned, cloud, indices_pair_.get<1>(),
00246                   line_b_points);
00247     jsk_recognition_utils::PointPair line_a_end_points = line_a->findEndPoints(line_a_points);
00248     jsk_recognition_utils::PointPair line_b_end_points = line_b->findEndPoints(line_b_points);
00249     double max_v = - DBL_MAX;
00250     double max_theta;
00251     jsk_recognition_utils::Line::Ptr max_line_c;
00252     jsk_recognition_utils::PointPair max_line_c_a_points, max_line_c_b_points;
00253     for (size_t i = 0; i < resolution_; i++) {
00254       ROS_INFO("estimate i: %lu", i);
00255       double theta = dt * i + min_angle_;
00256       Eigen::Vector3f point_on_x;
00257       line_a->foot(center, point_on_x);
00258       
00259       
00260       
00261       
00262       Eigen::Vector3f ex = (point_on_x - center).normalized();
00263       Eigen::Vector3f ez;
00264       axis->getDirection(ez);
00265       Eigen::Vector3f ey = ez.cross(ex).normalized();
00266       
00267       if (center.dot(ey) > 0) {
00268         ex = -ex;
00269         ey = ez.cross(ex).normalized();
00270       }
00271       Eigen::Vector3f point_on_y = center + r * ey;
00272       jsk_recognition_utils::Line::Ptr line_c = axis->parallelLineOnAPoint(point_on_y);
00273       
00274       
00275       
00276       
00277       
00278       
00279 
00280       
00281       
00282       
00283       
00284       
00285       
00286       Eigen::Vector3f line_c_a_min_point, line_c_a_max_point;
00287       Eigen::Vector3f line_c_b_min_point, line_c_b_max_point;
00288       line_c->foot(line_a_end_points.get<0>(), line_c_a_min_point);
00289       line_c->foot(line_a_end_points.get<1>(), line_c_a_max_point);
00290       line_c->foot(line_b_end_points.get<0>(), line_c_b_min_point);
00291       line_c->foot(line_b_end_points.get<1>(), line_c_b_max_point);
00292       jsk_recognition_utils::PointPair line_c_a_end_points = boost::make_tuple(line_c_a_min_point,
00293                                                         line_c_a_max_point);
00294       jsk_recognition_utils::PointPair line_c_b_end_points = boost::make_tuple(line_c_b_min_point,
00295                                                         line_c_b_max_point);
00296       jsk_recognition_utils::ConvexPolygon::Ptr plane_a = buildConvexPolygon(line_a_end_points,
00297                                                       line_c_a_end_points);
00298       jsk_recognition_utils::ConvexPolygon::Ptr plane_b = buildConvexPolygon(line_b_end_points,
00299                                                       line_c_b_end_points);
00300       double v = evaluatePointOnPlanes(cloud, *plane_a, *plane_b);
00301       if (max_v < v) {
00302         max_v = v;
00303         max_theta = theta;
00304         max_line_c = line_c;
00305         max_line_c_a_points = line_c_a_end_points;
00306         max_line_c_b_points = line_c_b_end_points;
00307       } 
00308    }
00309     value_ = max_v;
00310     
00311     jsk_recognition_utils::PointPair axis_end_points = computeAxisEndPoints(
00312       *axis,
00313       max_line_c_a_points,
00314       max_line_c_b_points);
00315     ROS_INFO("end_point: [%f, %f, %f]", axis_end_points.get<0>()[0], axis_end_points.get<0>()[1], axis_end_points.get<0>()[2]);
00316     ROS_INFO("end_point: [%f, %f, %f]", axis_end_points.get<1>()[0], axis_end_points.get<1>()[1], axis_end_points.get<1>()[2]);
00317     Eigen::Vector3f midpoint
00318       = (axis_end_points.get<0>() + axis_end_points.get<1>()) / 2.0;
00319     double z_dimension = (axis_end_points.get<0>() - midpoint).norm() * 2;
00320     
00321     ROS_INFO("midpoint: [%f, %f, %f]", midpoint[0], midpoint[1], midpoint[2]);
00322     cube_.reset(new jsk_recognition_utils::Cube(midpoint, *line_a_aligned, *line_b_aligned, *max_line_c));
00323     std::vector<double> dimensions = cube_->getDimensions();
00324     dimensions[2] = z_dimension;
00325     cube_->setDimensions(dimensions);
00326   }
00327 
00328   int EdgebasedCubeFinder::countInliers(
00329     const pcl::PointCloud<PointT>::Ptr cloud,
00330     const jsk_recognition_utils::ConvexPolygon::Ptr convex)
00331   {
00332     int num = 0;
00333     for (size_t i = 0; i < cloud->points.size(); i++) {
00334       PointT p = cloud->points[i];
00335       if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
00336         Eigen::Vector3f ep = p.getVector3fMap();
00337         if (convex->distanceSmallerThan(ep, outlier_threshold_)) {
00338           num++;
00339         }
00340       }
00341     }
00342     return num;
00343   }
00344   
00345   void EdgebasedCubeFinder::filterBasedOnConvex(
00346     const pcl::PointCloud<PointT>::Ptr cloud,
00347     const std::vector<jsk_recognition_utils::ConvexPolygon::Ptr>& convexes,
00348     std::vector<int>& output_indices)
00349   {
00350     
00351     for (size_t i = 0; i < convexes.size(); i++) {
00352       jsk_recognition_utils::ConvexPolygon::Ptr convex = convexes[i];
00353       if (true) {
00354         
00355         
00356         
00357         
00358         
00359         if (true) {
00360           output_indices.push_back(i);
00361         }
00362       }
00363     }
00364   }
00365 
00366   void EdgebasedCubeFinder::configCallback (Config &config, uint32_t level)
00367   {
00368     boost::mutex::scoped_lock lock(mutex_);
00369     outlier_threshold_ = config.outlier_threshold;
00370     min_inliers_ = config.min_inliers;
00371     convex_area_threshold_ = config.convex_area_threshold;
00372     convex_edge_threshold_ = config.convex_edge_threshold;
00373     parallel_edge_distance_min_threshold_ = config.parallel_edge_distance_min_threshold;
00374     parallel_edge_distance_max_threshold_ = config.parallel_edge_distance_max_threshold;
00375   }
00376   
00377   void EdgebasedCubeFinder::onInit()
00378   {
00379     ConnectionBasedNodelet::onInit();
00380     
00381 
00382     srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00383     dynamic_reconfigure::Server<Config>::CallbackType f =
00384       boost::bind (&EdgebasedCubeFinder::configCallback, this, _1, _2);
00385     srv_->setCallback (f);
00386 
00387     
00389     
00391     pub_ = advertise<jsk_recognition_msgs::BoundingBoxArray>(*pnh_, "output", 1);
00392     pub_pose_array_
00393       = advertise<geometry_msgs::PoseArray>(*pnh_, "output_pose_array", 1);
00394     pub_debug_marker_
00395       = advertise<visualization_msgs::Marker>(*pnh_, "debug_marker", 1);
00396     pub_debug_filtered_cloud_ = advertise<sensor_msgs::PointCloud2>(
00397       *pnh_, "debug_filtered_cloud", 1);
00398     pub_debug_polygons_
00399       = advertise<jsk_recognition_msgs::PolygonArray>(*pnh_, "debug_polygons", 1);
00400     pub_debug_clusers_
00401       = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_, "debug_clusters", 1);
00402 
00403     onInitPostProcess();
00404   }
00405 
00406   void EdgebasedCubeFinder::subscribe()
00407   {
00409     
00411     sub_input_.subscribe(*pnh_, "input", 1);
00412     sub_edges_.subscribe(*pnh_, "input_edges", 1);
00413     sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00414     sync_->connectInput(sub_input_, sub_edges_);
00415     sync_->registerCallback(boost::bind(
00416                               &EdgebasedCubeFinder::estimate, this, _1, _2));
00417   }
00418 
00419   void EdgebasedCubeFinder::unsubscribe()
00420   {
00421     sub_input_.unsubscribe();
00422     sub_edges_.unsubscribe();
00423   }
00424 
00425   jsk_recognition_utils::Line::Ptr EdgebasedCubeFinder::midLineFromCoefficientsPair(
00426     const CoefficientsPair& pair)
00427   {
00428     pcl::ModelCoefficients::Ptr coefficients_a = pair.get<0>();
00429     pcl::ModelCoefficients::Ptr coefficients_b = pair.get<1>();
00430     jsk_recognition_utils::Line::Ptr line_a = jsk_recognition_utils::Line::fromCoefficients(coefficients_a->values);
00431     jsk_recognition_utils::Line::Ptr line_b = jsk_recognition_utils::Line::fromCoefficients(coefficients_b->values);
00432     return line_a->midLine(*line_b);
00433   }
00434 
00435   pcl::PointCloud<EdgebasedCubeFinder::PointT>::Ptr EdgebasedCubeFinder::extractPointCloud(
00436     const pcl::PointCloud<PointT>::Ptr cloud,
00437     const pcl::PointIndices::Ptr indices)
00438   {
00439     pcl::PointCloud<PointT>::Ptr ret (new pcl::PointCloud<PointT>);
00440     pcl::ExtractIndices<PointT> ex;
00441     ex.setInputCloud(cloud);
00442     ex.setIndices(indices);
00443     ex.filter(*ret);
00444     return ret;
00445   }
00446 
00447   jsk_recognition_utils::PointPair EdgebasedCubeFinder::minMaxPointOnLine(
00448     const jsk_recognition_utils::Line& line,
00449     const pcl::PointCloud<PointT>::Ptr cloud)
00450   {
00451     jsk_recognition_utils::Vertices points;
00452     for (size_t i = 0; i < cloud->points.size(); i++) {
00453       PointT p = cloud->points[i];
00454       Eigen::Vector3f eigen_p = p.getVector3fMap();
00455       Eigen::Vector3f foot;
00456       line.foot(eigen_p, foot);
00457       points.push_back(foot);
00458     }
00459     return line.findEndPoints(points);
00460   }
00461   
00462   jsk_recognition_utils::ConvexPolygon::Ptr EdgebasedCubeFinder::convexFromPairs(
00463     const pcl::PointCloud<PointT>::Ptr cloud,
00464     const CoefficientsPair& coefficients_pair,
00465     const IndicesPair& indices_pair)
00466   {
00467     pcl::ModelCoefficients::Ptr coefficients_a = coefficients_pair.get<0>();
00468     pcl::ModelCoefficients::Ptr coefficients_b = coefficients_pair.get<1>();
00469     pcl::PointIndices::Ptr indices_a = indices_pair.get<0>();
00470     pcl::PointIndices::Ptr indices_b = indices_pair.get<1>();
00471     
00472     pcl::PointCloud<PointT>::Ptr cloud_a = extractPointCloud(cloud, indices_a);
00473     pcl::PointCloud<PointT>::Ptr cloud_b = extractPointCloud(cloud, indices_b);
00474 
00475     jsk_recognition_utils::Line::Ptr line_a = jsk_recognition_utils::Line::fromCoefficients(coefficients_a->values);
00476     jsk_recognition_utils::Line::Ptr line_b = jsk_recognition_utils::Line::fromCoefficients(coefficients_b->values);
00477     jsk_recognition_utils::PointPair a_min_max = minMaxPointOnLine(*line_a, cloud_a);
00478     jsk_recognition_utils::PointPair b_min_max = minMaxPointOnLine(*line_b, cloud_b);
00479     jsk_recognition_utils::Vertices vertices;
00480     vertices.push_back(a_min_max.get<0>());
00481     vertices.push_back(a_min_max.get<1>());
00482     vertices.push_back(b_min_max.get<1>());
00483     vertices.push_back(b_min_max.get<0>());
00484     jsk_recognition_utils::ConvexPolygon::Ptr ret (new jsk_recognition_utils::ConvexPolygon(vertices));
00485     return ret;
00486   }
00487   
00488   void EdgebasedCubeFinder::filterPairsBasedOnParallelEdgeDistances(
00489     const std::vector<IndicesPair>& pairs,
00490     const std::vector<CoefficientsPair>& coefficients_pair,
00491     std::vector<IndicesPair>& filtered_indices_pairs,
00492     std::vector<CoefficientsPair>& filtered_coefficients_pairs)
00493   {
00494     for (size_t i = 0; i < coefficients_pair.size(); i++) {
00495       CoefficientsPair coefficients = coefficients_pair[i];
00496       pcl::ModelCoefficients::Ptr coefficients_a = coefficients_pair[i].get<0>();
00497       pcl::ModelCoefficients::Ptr coefficients_b = coefficients_pair[i].get<1>();
00498       jsk_recognition_utils::Line::Ptr line_a = jsk_recognition_utils::Line::fromCoefficients(coefficients_a->values);
00499       jsk_recognition_utils::Line::Ptr line_b = jsk_recognition_utils::Line::fromCoefficients(coefficients_b->values);
00500 
00501       
00502       jsk_recognition_utils::Line::Ptr axis = line_a->midLine(*line_b);
00503       Eigen::Vector3f origin_a, origin_b;
00504       line_a->getOrigin(origin_a);
00505       line_b->getOrigin(origin_b);
00506       jsk_recognition_utils::Line::Ptr line_a_aligned = axis->parallelLineOnAPoint(origin_a);
00507       jsk_recognition_utils::Line::Ptr line_b_aligned = axis->parallelLineOnAPoint(origin_b);
00508       Eigen::Vector3f distance_vector;
00509       line_a_aligned->parallelLineNormal(*line_b_aligned, distance_vector);
00510       double distance = distance_vector.norm();
00511       
00512       ROS_INFO("d: %f", distance);
00513       if (distance < parallel_edge_distance_max_threshold_ &&
00514           distance > parallel_edge_distance_min_threshold_) {
00515         filtered_indices_pairs.push_back(pairs[i]);
00516         filtered_coefficients_pairs.push_back(coefficients);
00517       }
00518     }
00519   }
00520 
00521   
00522   pcl::PointIndices::Ptr
00523   EdgebasedCubeFinder::preparePointCloudForRANSAC(
00524     const jsk_recognition_utils::ConvexPolygon::Ptr convex,
00525     const CoefficientsPair& edge_coefficients_pair,
00526     const pcl::PointCloud<PointT>::Ptr cloud)
00527   {
00528     
00529     pcl::PointIndices::Ptr indices(new pcl::PointIndices);
00530     jsk_recognition_utils::ConvexPolygon::Ptr magnified_convex = convex->magnify(1.1);
00531     pcl::PointCloud<PointT>::Ptr ret (new pcl::PointCloud<PointT>);
00532     for (size_t i = 0; i < cloud->points.size(); i++) {
00533       PointT p = cloud->points[i];
00534       if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
00535         Eigen::Vector3f ep = p.getVector3fMap();
00536         Eigen::Vector3f foot;
00537         magnified_convex->projectOnPlane(ep, foot);
00538         if (magnified_convex->isInside(foot) && convex->distanceSmallerThan(ep, outlier_threshold_)) {
00539         
00540           
00541           indices->indices.push_back(i);
00542         }
00543       }
00544     }
00545     return indices;
00546    }
00547 
00548    void EdgebasedCubeFinder::estimateParallelPlane(
00549      const jsk_recognition_utils::ConvexPolygon::Ptr convex,
00550      const pcl::PointCloud<PointT>::Ptr filtered_cloud,
00551      pcl::PointIndices::Ptr output_inliers,
00552      pcl::ModelCoefficients::Ptr output_coefficients)
00553    {
00554      Eigen::Vector3f normal = convex->getNormal();
00555      pcl::SACSegmentation<PointT> seg;
00556      seg.setOptimizeCoefficients (true);
00557      seg.setModelType (pcl::SACMODEL_PERPENDICULAR_PLANE);
00558      seg.setMethodType (pcl::SAC_RANSAC);
00559      seg.setDistanceThreshold (outlier_threshold_);
00560      seg.setInputCloud(filtered_cloud);
00561      seg.setMaxIterations (10000);
00562      seg.setAxis(normal);
00563      seg.setEpsAngle(pcl::deg2rad(10.0));
00564      seg.segment (*output_inliers, *output_coefficients);
00565    }
00566 
00567    void EdgebasedCubeFinder::estimatePerpendicularPlane(
00568      const jsk_recognition_utils::ConvexPolygon::Ptr convex,
00569      const CoefficientsPair& edge_coefficients,
00570      const pcl::PointCloud<PointT>::Ptr filtered_cloud,
00571      pcl::PointIndices::Ptr output_inliers,
00572      pcl::ModelCoefficients::Ptr output_coefficients)
00573    {
00574      Eigen::Vector3f normal_a = convex->getNormal();
00575      jsk_recognition_utils::Line::Ptr mid_line = midLineFromCoefficientsPair(edge_coefficients);
00576      Eigen::Vector3f normal_b;
00577      mid_line->getDirection(normal_b);
00578      Eigen::Vector3f normal = normal_a.cross(normal_b);
00579      pcl::SACSegmentation<PointT> seg;
00580      seg.setOptimizeCoefficients (true);
00581      seg.setModelType (pcl::SACMODEL_PERPENDICULAR_PLANE);
00582      seg.setMethodType (pcl::SAC_RANSAC);
00583      seg.setDistanceThreshold (outlier_threshold_);
00584      seg.setInputCloud(filtered_cloud);
00585      seg.setMaxIterations (10000);
00586      seg.setAxis(normal);
00587      seg.setEpsAngle(pcl::deg2rad(5.0));
00588      seg.segment (*output_inliers, *output_coefficients);
00589    }
00590 
00591   jsk_recognition_utils::Cube::Ptr EdgebasedCubeFinder::cubeFromIndicesAndCoefficients(
00592     const pcl::PointCloud<EdgebasedCubeFinder::PointT>::Ptr cloud,
00593     const IndicesCoefficientsTriple& indices_coefficients_triple,
00594     pcl::PointCloud<EdgebasedCubeFinder::PointT>::Ptr points_on_edge)
00595   {
00596     Eigen::Vector3f ex, ey, ez;
00597     CoefficientsTriple coefficients_triple
00598       = indices_coefficients_triple.get<1>();
00599     IndicesTriple indices_triple
00600       = indices_coefficients_triple.get<0>();
00601     
00602     jsk_recognition_utils::Line::Ptr mid_line
00603       = jsk_recognition_utils::Line::fromCoefficients(coefficients_triple.get<0>()->values);
00604     jsk_recognition_utils::Line::Ptr line_a
00605       = jsk_recognition_utils::Line::fromCoefficients(coefficients_triple.get<1>()->values);
00606     jsk_recognition_utils::Line::Ptr line_b
00607       = jsk_recognition_utils::Line::fromCoefficients(coefficients_triple.get<2>()->values);
00608     
00609     if (!mid_line->isSameDirection(*line_a)) {
00610       line_a = line_a->flip();
00611     }
00612     if (!mid_line->isSameDirection(*line_b)) {
00613       line_b = line_b->flip();
00614     }
00615     jsk_recognition_utils::Line::Ptr axis = line_a->midLine(*line_b);
00616     
00617     pcl::PointCloud<PointT>::Ptr point_on_a
00618       = extractPointCloud(cloud,
00619                           indices_triple.get<1>());
00620     pcl::PointCloud<PointT>::Ptr point_on_b
00621       = extractPointCloud(cloud,
00622                           indices_triple.get<2>());
00623     pcl::PointCloud<PointT>::Ptr point_on_c
00624       = extractPointCloud(cloud,
00625                           indices_triple.get<0>());
00626     Eigen::Vector4f a_centroid4, b_centroid4, c_centroid4;
00627     Eigen::Vector3f a_centroid, b_centroid, c_centroid;
00628     pcl::compute3DCentroid(*point_on_a, a_centroid4);
00629     pcl::compute3DCentroid(*point_on_b, b_centroid4);
00630     pcl::compute3DCentroid(*point_on_c, c_centroid4);
00631     jsk_recognition_utils::pointFromVectorToVector<Eigen::Vector4f, Eigen::Vector3f>(
00632       a_centroid4, a_centroid);
00633     jsk_recognition_utils::pointFromVectorToVector<Eigen::Vector4f, Eigen::Vector3f>(
00634       b_centroid4, b_centroid);
00635     jsk_recognition_utils::pointFromVectorToVector<Eigen::Vector4f, Eigen::Vector3f>(
00636       c_centroid4, c_centroid);
00637     
00638     jsk_recognition_utils::Line::Ptr line_a_aligned = axis->parallelLineOnAPoint(a_centroid);
00639     jsk_recognition_utils::Line::Ptr line_b_aligned = axis->parallelLineOnAPoint(b_centroid);
00640     jsk_recognition_utils::Line::Ptr mid_line_aligned = axis->parallelLineOnAPoint(c_centroid);
00641     
00642     pcl::PointCloud<PointT>::Ptr all_points(new pcl::PointCloud<PointT>);
00643     *all_points = *point_on_a + *point_on_b;
00644     *all_points = *all_points + *point_on_c;
00645     *points_on_edge = *all_points;
00646     
00647     
00648     
00649     
00650     
00651     
00652     
00653     
00654     
00655     
00656     
00657     
00658     
00659     
00660       
00661     jsk_recognition_utils::PointPair min_max_points = minMaxPointOnLine(*axis, all_points);
00662     PointT min_point, max_point;
00663     
00664     
00665     
00666     
00667     
00668     
00669     
00670     
00671     Eigen::Vector3f center_point
00672       = (min_max_points.get<0>() + min_max_points.get<1>()) / 2.0;
00673     double z_width = (min_max_points.get<0>() - min_max_points.get<1>()).norm();
00674     mid_line_aligned->getDirection(ez);
00675     mid_line_aligned->parallelLineNormal(*line_a_aligned, ex);
00676     mid_line_aligned->parallelLineNormal(*line_b_aligned, ey);
00677     
00678     double x_width = ex.norm();
00679     double y_width = ey.norm();
00680     
00681     ex.normalize();
00682     ey.normalize();
00683     ez.normalize();
00684 
00685     ROS_INFO("ex: [%f, %f, %f]", ex[0], ex[1], ex[2]);
00686     ROS_INFO("ey: [%f, %f, %f]", ey[0], ey[1], ey[2]);
00687     ROS_INFO("ez: [%f, %f, %f]", ez[0], ez[1], ez[2]);
00688     
00689     if (ex.cross(ey).dot(ez) < 0) {
00690       ez = -ez;
00691     }
00692     
00693     Eigen::Quaternionf rot = jsk_recognition_utils::rotFrom3Axis(ex, ey, ez);
00694     std::vector<double> dimensions;
00695     dimensions.push_back(x_width);
00696     dimensions.push_back(y_width);
00697     dimensions.push_back(z_width);
00698     jsk_recognition_utils::Cube::Ptr ret (new jsk_recognition_utils::Cube(center_point, rot, dimensions));
00699     return ret;
00700   }
00701   
00702   void EdgebasedCubeFinder::estimate(
00703     const sensor_msgs::PointCloud2::ConstPtr& input_cloud,
00704     const jsk_recognition_msgs::ParallelEdgeArray::ConstPtr& input_edges)
00705   {
00706      boost::mutex::scoped_lock lock(mutex_);
00707      pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
00708      pcl::PointCloud<PointT>::Ptr all_filtered_cloud (new pcl::PointCloud<PointT>);
00709      pcl::fromROSMsg(*input_cloud, *cloud);
00710      visualization_msgs::Marker marker;
00711      jsk_recognition_msgs::PolygonArray polygon_array;
00712      geometry_msgs::PoseArray pose_array;
00713      jsk_recognition_msgs::BoundingBoxArray box_array;
00714      box_array.header = input_cloud->header;
00715      pose_array.header = input_cloud->header;
00716      std::vector<jsk_recognition_utils::Cube::Ptr> cubes;
00717      std::vector<pcl::PointIndices::Ptr> candidate_cluster_indices;
00718      for (size_t i = 0; i < input_edges->edge_groups.size(); i++) {
00719        jsk_recognition_msgs::ParallelEdge parallel_edge = input_edges->edge_groups[i];
00720        std::vector<pcl::PointIndices::Ptr> edges
00721          = pcl_conversions::convertToPCLPointIndices(
00722            parallel_edge.cluster_indices);
00723        std::vector<pcl::ModelCoefficients::Ptr> coefficients
00724          = pcl_conversions::convertToPCLModelCoefficients(
00725            parallel_edge.coefficients);
00726        std::vector<IndicesCoefficientsTriple> triples
00727          = tripleIndicesAndCoefficients(edges, coefficients);
00728        std::vector<IndicesCoefficientsTriple> perpendicular_triples
00729          = filterPerpendicularEdgeTriples(triples);
00730        if (perpendicular_triples.size() > 0) {
00731          
00732          pcl::PointCloud<PointT>::Ptr points_on_edges(new pcl::PointCloud<PointT>);
00733          pcl_conversions::toPCL(input_cloud->header, points_on_edges->header);
00734          for (size_t j = 0; j < perpendicular_triples.size(); j++) {
00735            pcl::PointCloud<PointT>::Ptr points_on_edge(new pcl::PointCloud<PointT>);
00736            jsk_recognition_utils::Cube::Ptr cube = cubeFromIndicesAndCoefficients(
00737              cloud,
00738              perpendicular_triples[j],
00739              points_on_edge);
00740            *points_on_edges = *points_on_edges + *points_on_edge;
00741            cubes.push_back(cube);
00742          }
00743          pub_debug_filtered_cloud_.publish(points_on_edges);
00744        }
00745      }
00746 
00747      if (cubes.size() > 0) {
00748        for (size_t i = 0; i < cubes.size(); i++) {
00749          
00750          jsk_recognition_msgs::BoundingBox ros_box = cubes[i]->toROSMsg();
00751          ros_box.header = input_cloud->header;
00752          box_array.boxes.push_back(ros_box);
00753          pose_array.poses.push_back(ros_box.pose);
00754        }
00755        pub_.publish(box_array);
00756        pub_pose_array_.publish(pose_array);
00757      }
00758   }
00759 
00760   bool EdgebasedCubeFinder::isPerpendicularVector(
00761     const Eigen::Vector3f& a,
00762     const Eigen::Vector3f& b)
00763   {
00764     double dot = a.normalized().dot(b.normalized());
00765     if (fabs(dot) >= 1.0) {
00766       return false;
00767     }
00768     else {
00769       double theta = fabs(acos(dot));
00770       NODELET_INFO("theta: %f", pcl::rad2deg(theta));
00771       if (fabs(theta - M_PI / 2.0) < pcl::deg2rad(20.0)) {
00772         return true;
00773       }
00774       else {
00775         return false;
00776       }
00777     }
00778   }
00779   
00780   EdgebasedCubeFinder::EdgeRelation EdgebasedCubeFinder::perpendicularEdgeTriple(
00781     const jsk_recognition_utils::Line& edge_a,
00782     const jsk_recognition_utils::Line& edge_b,
00783     const jsk_recognition_utils::Line& edge_c)
00784   {
00785     Eigen::Vector3f a_b_normal, a_c_normal;
00786     edge_a.parallelLineNormal(edge_b, a_b_normal);
00787     edge_a.parallelLineNormal(edge_c, a_c_normal);
00788     if (isPerpendicularVector(a_b_normal, a_c_normal)) {
00789       return A_PERPENDICULAR;
00790     }
00791     else {
00792       Eigen::Vector3f b_a_normal, b_c_normal;
00793       edge_b.parallelLineNormal(edge_a, b_a_normal);
00794       edge_b.parallelLineNormal(edge_c, b_c_normal);
00795       if (isPerpendicularVector(b_a_normal, b_c_normal)) {
00796         return B_PERPENDICULAR;
00797       }
00798       else {
00799         Eigen::Vector3f c_a_normal, c_b_normal;
00800         edge_c.parallelLineNormal(edge_a, c_a_normal);
00801         edge_c.parallelLineNormal(edge_b, c_b_normal);
00802         if (isPerpendicularVector(c_a_normal, c_b_normal)) {
00803           return C_PERPENDICULAR;
00804         }
00805         else {
00806           return NOT_PERPENDICULAR;
00807         }
00808       }
00809     }
00810   }
00811   
00812   std::vector<IndicesCoefficientsTriple>
00813   EdgebasedCubeFinder::filterPerpendicularEdgeTriples(
00814     const std::vector<IndicesCoefficientsTriple>& triples)
00815   {
00816     std::vector<IndicesCoefficientsTriple> ret;
00817     for (size_t i = 0; i < triples.size(); i++) {
00818       pcl::ModelCoefficients::Ptr a_coefficients
00819         = triples[i].get<1>().get<0>();
00820       pcl::ModelCoefficients::Ptr b_coefficients
00821         = triples[i].get<1>().get<1>();
00822       pcl::ModelCoefficients::Ptr c_coefficients
00823         = triples[i].get<1>().get<2>();
00824       jsk_recognition_utils::Line::Ptr edge_a
00825         = jsk_recognition_utils::Line::fromCoefficients(a_coefficients->values);
00826       jsk_recognition_utils::Line::Ptr edge_b
00827         = jsk_recognition_utils::Line::fromCoefficients(b_coefficients->values);
00828       jsk_recognition_utils::Line::Ptr edge_c
00829         = jsk_recognition_utils::Line::fromCoefficients(c_coefficients->values);
00830       
00831       EdgeRelation relation = perpendicularEdgeTriple(*edge_a,
00832                                                       *edge_b,
00833                                                       *edge_c);
00834       if (relation != NOT_PERPENDICULAR) {
00835         
00836         if (relation == A_PERPENDICULAR) {
00837           ret.push_back(triples[i]);
00838         }
00839         else if (relation == B_PERPENDICULAR) {
00840           IndicesCoefficientsTriple new_triple
00841             = boost::make_tuple(
00842               boost::make_tuple(triples[i].get<0>().get<1>(),
00843                                 triples[i].get<0>().get<0>(),
00844                                 triples[i].get<0>().get<2>()),
00845               boost::make_tuple(
00846                           triples[i].get<1>().get<1>(),
00847                           triples[i].get<1>().get<0>(),
00848                           triples[i].get<1>().get<2>()));
00849           ret.push_back(new_triple);
00850         }
00851         else if (relation == C_PERPENDICULAR) {
00852           IndicesCoefficientsTriple new_triple
00853             = boost::make_tuple(
00854               boost::make_tuple(triples[i].get<0>().get<2>(),
00855                                 triples[i].get<0>().get<0>(),
00856                                 triples[i].get<0>().get<1>()),
00857               boost::make_tuple(
00858                           triples[i].get<1>().get<2>(),
00859                           triples[i].get<1>().get<0>(),
00860                           triples[i].get<1>().get<1>()));
00861           ret.push_back(new_triple);
00862         }
00863       }
00864     }
00865     return ret;
00866   }
00867   
00868   void EdgebasedCubeFinder::estimate2(
00869     const sensor_msgs::PointCloud2::ConstPtr& input_cloud,
00870     const jsk_recognition_msgs::ParallelEdgeArray::ConstPtr& input_edges)
00871   {
00872      boost::mutex::scoped_lock lock(mutex_);
00873      pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
00874      pcl::PointCloud<PointT>::Ptr all_filtered_cloud (new pcl::PointCloud<PointT>);
00875      pcl::fromROSMsg(*input_cloud, *cloud);
00876      visualization_msgs::Marker marker;
00877      jsk_recognition_msgs::PolygonArray polygon_array;
00878      std::vector<pcl::PointIndices::Ptr> candidate_cluster_indices;
00879      
00880      polygon_array.header = input_cloud->header;
00881      marker.pose.orientation.w = 1.0;
00882      marker.color.a = 1.0;
00883      marker.color.r = 1.0;
00884      marker.header = input_cloud->header;
00885      marker.scale.x = 0.01;
00886      marker.type = visualization_msgs::Marker::LINE_LIST;
00887      NODELET_INFO("%lu parallel edge groups", input_edges->edge_groups.size());
00888      geometry_msgs::PoseArray pose_array;
00889      pose_array.header = input_cloud->header;
00890      jsk_recognition_msgs::BoundingBoxArray ros_output;
00891      ros_output.header = input_cloud->header;
00892 
00893      for (size_t i = 0; i < input_edges->edge_groups.size(); i++) {
00894        jsk_recognition_msgs::ParallelEdge parallel_edge = input_edges->edge_groups[i];
00895 
00896        if (parallel_edge.cluster_indices.size() <= 1) {
00897          NODELET_ERROR("parallel edge group has only %lu edges",
00898                        parallel_edge.cluster_indices.size());
00899          continue;
00900        }
00901        NODELET_INFO("%lu parallel edge groups has %lu edges",
00902                     i, parallel_edge.cluster_indices.size());
00904        
00906        std::vector<pcl::PointIndices::Ptr> edges
00907          = pcl_conversions::convertToPCLPointIndices(
00908            parallel_edge.cluster_indices);
00909        std::vector<pcl::ModelCoefficients::Ptr> coefficients
00910          = pcl_conversions::convertToPCLModelCoefficients(
00911            parallel_edge.coefficients);
00912 
00913        std::vector<IndicesPair> pairs = combinateIndices(edges);
00914        std::vector<CoefficientsPair> coefficients_pair
00915          = combinateCoefficients(coefficients);
00916        std::vector<IndicesPair> filtered_indices_pairs;
00917        std::vector<CoefficientsPair> filtered_coefficients_pairs;
00918 
00919        filtered_indices_pairs = pairs;
00920        filtered_coefficients_pairs = coefficients_pair;
00921        
00922        
00923        
00924 
00925        
00926        std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> convexes;
00927        for (size_t j = 0; j < filtered_coefficients_pairs.size(); j++) {
00928          jsk_recognition_utils::ConvexPolygon::Ptr convex
00929            = convexFromPairs(cloud, filtered_coefficients_pairs[j],
00930                              pairs[j]);
00931          convexes.push_back(convex);
00932        }
00933        std::vector<int> filtered_indices;
00934        filterBasedOnConvex(cloud, convexes, filtered_indices);
00935 
00936        pcl::PointIndices::Ptr filtered_cube_candidate_indices(new pcl::PointIndices);
00937        for (size_t j = 0; j < filtered_indices.size(); j++) {
00938          int index = filtered_indices[j];
00939          jsk_recognition_utils::ConvexPolygon::Ptr target_convex = convexes[index];
00940          IndicesPair target_edge_indices_pair
00941            = filtered_indices_pairs[index];
00942          CoefficientsPair target_edge_coefficients_pair
00943            = filtered_coefficients_pairs[index];
00944          
00945          
00946          pcl::PointIndices::Ptr filtered_indices
00947            = preparePointCloudForRANSAC(
00948              target_convex, target_edge_coefficients_pair, cloud);
00949          
00950          
00951          filtered_cube_candidate_indices
00952            = jsk_recognition_utils::addIndices(*filtered_cube_candidate_indices,
00953                         *filtered_indices);       
00954            
00955          
00956          
00957          
00958          
00959          
00960          
00961          
00962 
00963          
00964          
00965          
00966          
00967          
00968          
00969          
00970          
00971          
00972          
00973          
00974          
00975          
00976          
00977          
00978          
00979          
00980          
00981          
00982          
00983          
00984          
00985          
00986          
00987          
00988          
00989          
00990          
00991          
00992          
00993          
00994          
00995          
00996          
00997          
00998          
00999          
01000          
01001          
01002          
01003         
01004         
01005         
01006         
01007         
01008         
01009         
01010         
01011         
01012         
01013         
01014         
01015         
01016         
01017         
01018         
01019         
01020         
01021         
01022 
01023       
01024       
01025       
01026       
01027         
01028       
01029       
01030       
01031       
01032       
01033       
01034       
01035       
01036       
01037       
01038       
01039       
01040       
01041       
01042       
01043       
01044       
01045       
01046       
01047       
01048       
01049       
01050       
01051        }
01052        candidate_cluster_indices.push_back(filtered_cube_candidate_indices);
01053 
01054        
01055        pcl::PointIndices::Ptr first_inliers(new pcl::PointIndices);
01056        pcl::ModelCoefficients::Ptr first_coefficients(new pcl::ModelCoefficients);
01057        jsk_recognition_utils::ConvexPolygon::Ptr first_polygon
01058          = estimateConvexPolygon(
01059            cloud,
01060            filtered_cube_candidate_indices,
01061            first_coefficients,
01062            first_inliers);
01063        if (first_polygon) {
01064          geometry_msgs::PolygonStamped first_polygon_ros;
01065          first_polygon_ros.polygon = first_polygon->toROSMsg();
01066          first_polygon_ros.header = input_cloud->header;
01067          polygon_array.polygons.push_back(first_polygon_ros);
01068        }
01069       
01070       
01071       
01072       
01073       
01074       
01075       
01076       
01077       
01078       
01079       
01080       
01081       
01082       
01083       
01084       
01085       
01086       
01087       
01088       
01089       
01090       
01091       
01092       
01093       
01094       
01095       
01096       
01097       
01098       
01099       
01100       
01101       
01102       
01103       
01104     }
01105     pub_.publish(ros_output);
01106     pub_pose_array_.publish(pose_array);
01107     pub_debug_marker_.publish(marker);
01108     sensor_msgs::PointCloud2 ros_cloud;
01109     pcl::toROSMsg(*all_filtered_cloud, ros_cloud);
01110     ros_cloud.header = input_cloud->header;
01111     pub_debug_filtered_cloud_.publish(ros_cloud);
01112     pub_debug_polygons_.publish(polygon_array);
01113 
01114     
01115     jsk_recognition_msgs::ClusterPointIndices ros_cluster_indices;
01116     ros_cluster_indices.header = input_cloud->header;
01117     for (size_t i = 0; i < candidate_cluster_indices.size(); i++) {
01118       PCLIndicesMsg indices_msg;
01119       indices_msg.header = input_cloud->header;
01120       indices_msg.indices = candidate_cluster_indices[i]->indices;
01121       ros_cluster_indices.cluster_indices.push_back(indices_msg);
01122     }
01123     pub_debug_clusers_.publish(ros_cluster_indices);
01124   }
01125 
01126   std::vector<IndicesCoefficientsTriple>
01127   EdgebasedCubeFinder::tripleIndicesAndCoefficients(
01128     const std::vector<pcl::PointIndices::Ptr>& indices,
01129     const std::vector<pcl::ModelCoefficients::Ptr>& coefficients)
01130   {
01131     if (indices.size() != coefficients.size()) {
01132       NODELET_ERROR("size of indices and coefficients are not same");
01133       return std::vector<IndicesCoefficientsTriple>();
01134     }
01135 
01136     if (indices.size() <= 2 && coefficients.size() <= 2) {
01137       NODELET_WARN("[EdgebasedCubeFinder::tripleIndicesAndCoefficients] no enough canddiates");
01138       return std::vector<IndicesCoefficientsTriple>();
01139     }
01140     std::vector<IndicesCoefficientsTriple> ret;
01141     for (size_t i = 0; i < indices.size() - 2; i++) {
01142       for (size_t j = i + 1; j < indices.size() - 1; j++) {
01143         for (size_t k = j + 1; k < indices.size(); k++) {
01144           IndicesTriple indices_triple
01145             = boost::make_tuple(indices[i],
01146                                 indices[j],
01147                                 indices[k]);
01148           CoefficientsTriple coefficients_triple
01149             = boost::make_tuple(coefficients[i],
01150                                 coefficients[j],
01151                                 coefficients[k]);
01152           IndicesCoefficientsTriple indices_coefficients_triple
01153             = boost::make_tuple(indices_triple,
01154                                 coefficients_triple);
01155           ret.push_back(indices_coefficients_triple);
01156         }
01157       }
01158     }
01159     return ret;
01160   }
01161   
01162   jsk_recognition_utils::ConvexPolygon::Ptr EdgebasedCubeFinder::estimateConvexPolygon(
01163     const pcl::PointCloud<PointT>::Ptr cloud,
01164     const pcl::PointIndices::Ptr indices,
01165     pcl::ModelCoefficients::Ptr coefficients,
01166     pcl::PointIndices::Ptr inliers)
01167   {
01169     
01171     pcl::SACSegmentation<PointT> seg;
01172     seg.setOptimizeCoefficients (true);
01173     seg.setModelType (pcl::SACMODEL_PLANE);
01174     seg.setMethodType (pcl::SAC_RANSAC);
01175     seg.setInputCloud(cloud);
01176     seg.setIndices(indices);
01177     seg.setDistanceThreshold(0.003);
01178     seg.segment(*inliers, *coefficients);
01180     
01182     if (inliers->indices.size() > 0) {
01183       return jsk_recognition_utils::convexFromCoefficientsAndInliers<PointT>(
01184         cloud, inliers, coefficients);
01185     }
01186     else {
01187       return jsk_recognition_utils::ConvexPolygon::Ptr();
01188     }
01189   }
01190   
01191   std::vector<IndicesPair> EdgebasedCubeFinder::combinateIndices(
01192     const std::vector<pcl::PointIndices::Ptr>& indices)
01193   {
01194     std::vector<IndicesPair> ret;
01195     for(size_t i = 0; i < indices.size() - 1; i++) {
01196       for (size_t j = i + 1; j < indices.size(); j++) {
01197         IndicesPair pair = boost::make_tuple(indices[i],
01198                                              indices[j]);
01199         ret.push_back(pair);
01200       }
01201     }
01202     return ret;
01203   }
01204 
01205   std::vector<CoefficientsPair> EdgebasedCubeFinder::combinateCoefficients(
01206     const std::vector<pcl::ModelCoefficients::Ptr>& coefficients)
01207   {
01208     std::vector<CoefficientsPair> ret;
01209     for(size_t i = 0; i < coefficients.size() - 1; i++) {
01210       for (size_t j = i + 1; j < coefficients.size(); j++) {
01211         CoefficientsPair pair = boost::make_tuple(coefficients[i],
01212                                                   coefficients[j]);
01213         ret.push_back(pair);
01214       }
01215     }
01216     return ret;
01217   }
01218 }
01219 
01220 #include <pluginlib/class_list_macros.h>
01221 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::EdgebasedCubeFinder, nodelet::Nodelet);
01222