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 #define BOOST_PARAMETER_MAX_ARITY 7
00037
00038 #include "jsk_pcl_ros/environment_plane_modeling.h"
00039 #include <pcl/filters/extract_indices.h>
00040 #include <pcl/common/distances.h>
00041 #include <pcl_conversions/pcl_conversions.h>
00042 #include <pcl/filters/project_inliers.h>
00043 #include <pcl/surface/convex_hull.h>
00044 #include <pcl/filters/project_inliers.h>
00045 #include <jsk_recognition_msgs/SparseOccupancyGridArray.h>
00046
00047 #include <pluginlib/class_list_macros.h>
00048 #include <geometry_msgs/PoseArray.h>
00049 #include "jsk_recognition_utils/geo_util.h"
00050 #include "jsk_pcl_ros/grid_map.h"
00051 #include <jsk_topic_tools/rosparam_utils.h>
00052 namespace jsk_pcl_ros
00053 {
00054 void EnvironmentPlaneModeling::onInit()
00055 {
00056 DiagnosticNodelet::onInit();
00057
00058 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00059 typename dynamic_reconfigure::Server<Config>::CallbackType f =
00060 boost::bind (&EnvironmentPlaneModeling::configCallback, this, _1, _2);
00061 srv_->setCallback (f);
00062
00063 pnh_->param("complete_footprint_region", complete_footprint_region_, false);
00064 pub_debug_magnified_polygons_
00065 = pnh_->advertise<jsk_recognition_msgs::PolygonArray>(
00066 "debug/magnified_polygons", 1);
00067 pub_debug_convex_point_cloud_
00068 = pnh_->advertise<sensor_msgs::PointCloud2>(
00069 "debug/convex_cloud", 1);
00070 pub_debug_raw_grid_map_
00071 = pnh_->advertise<jsk_recognition_msgs::SimpleOccupancyGridArray>(
00072 "debug/raw_grid_map", 1);
00073 pub_debug_noeroded_grid_map_
00074 = pnh_->advertise<jsk_recognition_msgs::SimpleOccupancyGridArray>(
00075 "debug/noeroded_grid_map", 1);
00076 pub_debug_plane_coords_
00077 = pnh_->advertise<geometry_msgs::PoseArray>(
00078 "debug/plane_poses", 1);
00079 pub_debug_magnified_plane_coords_
00080 = pnh_->advertise<geometry_msgs::PoseArray>(
00081 "debug/magnified_plane_poses", 1);
00082 pub_grid_map_
00083 = pnh_->advertise<jsk_recognition_msgs::SimpleOccupancyGridArray>(
00084 "output", 1, true);
00085 pub_snapped_move_base_simple_goal_ = pnh_->advertise<geometry_msgs::PoseStamped>(
00086 "/footstep_simple/goal", 1);
00087 pub_non_plane_indices_ = pnh_->advertise<PCLIndicesMsg>(
00088 "output/non_plane_indices", 1);
00089 if (complete_footprint_region_) {
00090 tf_listener_ = TfListenerSingleton::getInstance();
00091
00092 sub_leg_bbox_ = pnh_->subscribe(
00093 "input/leg_bounding_box", 1,
00094 &EnvironmentPlaneModeling::boundingBoxCallback, this);
00095
00096 jsk_topic_tools::readVectorParameter(
00097 *pnh_, "footprint_frames", footprint_frames_);
00098
00099 }
00100 sub_move_base_simple_goal_ = pnh_->subscribe(
00101 "/move_base_simple/goal", 1,
00102 &EnvironmentPlaneModeling::moveBaseSimpleGoalCallback, this);
00103 sub_cloud_.subscribe(*pnh_, "input", 1);
00104 sub_full_cloud_.subscribe(*pnh_, "input/full_cloud", 1);
00105 sub_indices_.subscribe(*pnh_, "input/indices", 1);
00106 sub_polygons_.subscribe(*pnh_, "input/polygons", 1);
00107 sub_coefficients_.subscribe(*pnh_, "input/coefficients", 1);
00108 sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00109 sync_->connectInput(sub_cloud_, sub_full_cloud_, sub_polygons_,
00110 sub_coefficients_, sub_indices_);
00111 sync_->registerCallback(
00112 boost::bind(&EnvironmentPlaneModeling::inputCallback,
00113 this, _1, _2, _3, _4, _5));
00114
00115 onInitPostProcess();
00116 }
00117
00118 void EnvironmentPlaneModeling::configCallback(Config &config, uint32_t level)
00119 {
00120 boost::mutex::scoped_lock lock(mutex_);
00121 magnify_distance_ = config.magnify_distance;
00122 distance_threshold_ = config.distance_threshold;
00123 normal_threshold_ = config.normal_threshold;
00124 resolution_ = config.resolution;
00125 morphological_filter_size_ = config.morphological_filter_size;
00126 erode_filter_size_ = config.erode_filter_size;
00127 footprint_plane_angular_threshold_ = config.footprint_plane_angular_threshold;
00128 footprint_plane_distance_threshold_ = config.footprint_plane_distance_threshold;
00129 }
00130
00131 void EnvironmentPlaneModeling::printInputData(
00132 const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
00133 const sensor_msgs::PointCloud2::ConstPtr& full_cloud_msg,
00134 const jsk_recognition_msgs::PolygonArray::ConstPtr& polygon_msg,
00135 const jsk_recognition_msgs::ModelCoefficientsArray::ConstPtr& coefficients_msg,
00136 const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& indices_msg)
00137 {
00138 NODELET_INFO("Input data --");
00139 NODELET_INFO(" Number of points -- %d", cloud_msg->width * cloud_msg->height);
00140 NODELET_INFO(" Number of full points -- %d", full_cloud_msg->width * full_cloud_msg->height);
00141 NODELET_INFO(" Number of clusters: -- %lu", indices_msg->cluster_indices.size());
00142 NODELET_INFO(" Frame Id: %s", cloud_msg->header.frame_id.c_str());
00143 NODELET_INFO(" Complete Footprint: %s", complete_footprint_region_? "true": "false");
00144 }
00145
00146 bool EnvironmentPlaneModeling::isValidFrameIds(
00147 const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
00148 const sensor_msgs::PointCloud2::ConstPtr& full_cloud_msg,
00149 const jsk_recognition_msgs::PolygonArray::ConstPtr& polygon_msg,
00150 const jsk_recognition_msgs::ModelCoefficientsArray::ConstPtr& coefficients_msg,
00151 const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& indices_msg)
00152 {
00153 std::string frame_id = cloud_msg->header.frame_id;
00154 if (full_cloud_msg->header.frame_id != frame_id) {
00155 return false;
00156 }
00157 if (polygon_msg->header.frame_id != frame_id) {
00158 return false;
00159 }
00160 for (size_t i = 0; i < polygon_msg->polygons.size(); i++) {
00161 if (polygon_msg->polygons[i].header.frame_id != frame_id) {
00162 return false;
00163 }
00164 }
00165 if (coefficients_msg->header.frame_id != frame_id) {
00166 return false;
00167 }
00168 for (size_t i = 0; i < coefficients_msg->coefficients.size(); i++) {
00169 if (coefficients_msg->coefficients[i].header.frame_id != frame_id) {
00170 return false;
00171 }
00172 }
00173 if (indices_msg->header.frame_id != frame_id) {
00174 return false;
00175 }
00176 for (size_t i = 0; i < indices_msg->cluster_indices.size(); i++) {
00177 if (indices_msg->cluster_indices[i].header.frame_id != frame_id) {
00178 return false;
00179 }
00180 }
00181 return true;
00182 }
00183
00184 void EnvironmentPlaneModeling::moveBaseSimpleGoalCallback(
00185 const geometry_msgs::PoseStamped::ConstPtr& msg)
00186 {
00187 boost::mutex::scoped_lock lock(mutex_);
00188 if (latest_grid_maps_.size() == 0) {
00189 NODELET_WARN("not yet grid maps are available");
00190 return;
00191 }
00192
00193 tf::StampedTransform tf_transform = lookupTransformWithDuration(
00194 tf_listener_,
00195 latest_global_header_.frame_id,
00196 msg->header.frame_id,
00197 latest_global_header_.stamp,
00198 ros::Duration(1.0));
00199
00200 Eigen::Affine3f local_coords, transform;
00201 tf::poseMsgToEigen(msg->pose, local_coords);
00202 tf::transformTFToEigen(tf_transform, transform);
00203 Eigen::Affine3f global_coords = transform * local_coords;
00204
00205
00206 double max_height = - DBL_MAX;
00207 GridPlane::Ptr max_grid;
00208 Eigen::Affine3f max_projected_coords = Eigen::Affine3f::Identity();
00209 for (size_t i = 0; i < latest_grid_maps_.size(); i++) {
00210 GridPlane::Ptr target_grid = latest_grid_maps_[i];
00211 Eigen::Affine3f projected_coords;
00212 target_grid->getPolygon()->projectOnPlane(global_coords, projected_coords);
00213 Eigen::Vector3f projected_point(projected_coords.translation());
00214 if (target_grid->isOccupiedGlobal(projected_point)) {
00215 double height = projected_point[2];
00216 if (max_height < height) {
00217 max_height = height;
00218 max_grid = target_grid;
00219 max_projected_coords = projected_coords;
00220 }
00221 }
00222 }
00223 if (max_grid) {
00224
00225 geometry_msgs::PoseStamped ros_coords;
00226 tf::poseEigenToMsg(max_projected_coords, ros_coords.pose);
00227 ros_coords.header.stamp = msg->header.stamp;
00228 ros_coords.header.frame_id = latest_global_header_.frame_id;
00229 pub_snapped_move_base_simple_goal_.publish(ros_coords);
00230 }
00231 else {
00232 NODELET_ERROR("Failed to find corresponding grid");
00233 }
00234 }
00235
00236 void EnvironmentPlaneModeling::boundingBoxCallback(
00237 const jsk_recognition_msgs::BoundingBox::ConstPtr& box)
00238 {
00239 boost::mutex::scoped_lock lock(mutex_);
00240 latest_leg_bounding_box_ = box;
00241 }
00242
00243 void EnvironmentPlaneModeling::inputCallback(
00244 const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
00245 const sensor_msgs::PointCloud2::ConstPtr& full_cloud_msg,
00246 const jsk_recognition_msgs::PolygonArray::ConstPtr& polygon_msg,
00247 const jsk_recognition_msgs::ModelCoefficientsArray::ConstPtr& coefficients_msg,
00248 const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& indices_msg)
00249 {
00250 boost::mutex::scoped_lock lock(mutex_);
00251 try {
00252
00253 if (!isValidFrameIds(cloud_msg, full_cloud_msg, polygon_msg, coefficients_msg, indices_msg)) {
00254 NODELET_FATAL("frame_id is not correct");
00255 return;
00256 }
00257 if (complete_footprint_region_ && !latest_leg_bounding_box_) {
00258 NODELET_ERROR("Bounding Box for Footprint is not yet ready");
00259 return;
00260 }
00261
00262 printInputData(cloud_msg, full_cloud_msg, polygon_msg, coefficients_msg, indices_msg);
00263
00264
00265 pcl::PointCloud<pcl::PointNormal>::Ptr cloud (new pcl::PointCloud<pcl::PointNormal>);
00266 pcl::fromROSMsg(*cloud_msg, *cloud);
00267
00268 pcl::PointCloud<pcl::PointNormal>::Ptr full_cloud (new pcl::PointCloud<pcl::PointNormal>);
00269 pcl::fromROSMsg(*full_cloud_msg, *full_cloud);
00270
00271
00272 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> convexes = convertToConvexPolygons(cloud, indices_msg, coefficients_msg);
00273
00274 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> magnified_convexes = magnifyConvexes(convexes);
00275 publishConvexPolygonsBoundaries(pub_debug_convex_point_cloud_, cloud_msg->header, magnified_convexes);
00276
00277 publishConvexPolygons(pub_debug_magnified_polygons_, cloud_msg->header, magnified_convexes);
00278
00279 {
00280 geometry_msgs::PoseArray pose_array;
00281 pose_array.header = cloud_msg->header;
00282 for (size_t i = 0; i < convexes.size(); i++) {
00283 Eigen::Affine3f pose = convexes[i]->coordinates();
00284 geometry_msgs::Pose ros_pose;
00285 tf::poseEigenToMsg(pose, ros_pose);
00286 pose_array.poses.push_back(ros_pose);
00287 }
00288 pub_debug_plane_coords_.publish(pose_array);
00289 }
00290 {
00291 geometry_msgs::PoseArray pose_array;
00292 pose_array.header = cloud_msg->header;
00293 for (size_t i = 0; i < magnified_convexes.size(); i++) {
00294 Eigen::Affine3f pose = magnified_convexes[i]->coordinates();
00295 geometry_msgs::Pose ros_pose;
00296 tf::poseEigenToMsg(pose, ros_pose);
00297 pose_array.poses.push_back(ros_pose);
00298 }
00299 pub_debug_magnified_plane_coords_.publish(pose_array);
00300 }
00301
00302
00303 std::set<int> non_plane_indices;
00304 std::vector<GridPlane::Ptr> raw_grid_planes = buildGridPlanes(full_cloud, magnified_convexes, non_plane_indices);
00305
00306 publishGridMaps(pub_debug_raw_grid_map_, cloud_msg->header, raw_grid_planes);
00307 PCLIndicesMsg ros_non_plane_indices;
00308 ros_non_plane_indices.indices = std::vector<int>(non_plane_indices.begin(),
00309 non_plane_indices.end());
00310 ros_non_plane_indices.header = cloud_msg->header;
00311 pub_non_plane_indices_.publish(ros_non_plane_indices);
00312 std::vector<GridPlane::Ptr> morphological_filtered_grid_planes
00313 = morphologicalFiltering(raw_grid_planes);
00314
00315 publishGridMaps(pub_debug_noeroded_grid_map_, cloud_msg->header,
00316 morphological_filtered_grid_planes);
00317
00318 std::vector<GridPlane::Ptr> eroded_grid_planes
00319 = erodeFiltering(morphological_filtered_grid_planes);
00320 std::vector<GridPlane::Ptr> result_grid_planes;
00321
00322 if (complete_footprint_region_) {
00323 result_grid_planes
00324 = completeFootprintRegion(cloud_msg->header,
00325 eroded_grid_planes);
00326 }
00327 else {
00328 result_grid_planes = eroded_grid_planes;
00329 }
00330
00331 publishGridMaps(pub_grid_map_, cloud_msg->header,
00332 result_grid_planes);
00333
00334 latest_global_header_ = cloud_msg->header;
00335 latest_grid_maps_ = result_grid_planes;
00336 }
00337 catch (tf2::TransformException& e) {
00338 NODELET_ERROR("Failed to lookup transformation: %s", e.what());
00339 }
00340 }
00341
00342 std::vector<GridPlane::Ptr> EnvironmentPlaneModeling::erodeFiltering(
00343 std::vector<GridPlane::Ptr>& grid_maps)
00344 {
00345 std::vector<GridPlane::Ptr> ret;
00346 for (size_t i = 0; i < grid_maps.size(); i++) {
00347 GridPlane::Ptr eroded_grid_map = grid_maps[i]->erode(erode_filter_size_);
00348 ret.push_back(eroded_grid_map);
00349 }
00350 return ret;
00351 }
00352
00353 int EnvironmentPlaneModeling::lookupGroundPlaneForFootprint(
00354 const Eigen::Affine3f& pose, const std::vector<GridPlane::Ptr>& grid_maps)
00355 {
00356 Eigen::Vector3f foot_z = (pose.rotation() * Eigen::Vector3f::UnitZ()).normalized();
00357 Eigen::Vector3f foot_p(pose.translation());
00358 double min_distance = DBL_MAX;
00359 int min_index = -1;
00360 for (size_t i = 0; i < grid_maps.size(); i++) {
00361 GridPlane::Ptr grid = grid_maps[i];
00362 Eigen::Vector3f normal = grid->getPolygon()->getNormal();
00363 if (std::abs(normal.dot(foot_z)) > cos(footprint_plane_angular_threshold_)) {
00364
00365 if (grid->getPolygon()->distanceToPoint(foot_p) < footprint_plane_distance_threshold_) {
00366 Eigen::Vector3f foot_center(pose.translation());
00367 if (!grid->isOccupiedGlobal(foot_center)) {
00368
00369 double d = grid->getPolygon()->distanceFromVertices(foot_center);
00370 if (d < min_distance) {
00371 min_distance = d;
00372 min_index = i;
00373 }
00374 }
00375 else {
00376 NODELET_INFO("Foot print is already occupied");
00377 return -1;
00378 }
00379
00380 }
00381 }
00382 }
00383 return min_index;
00384 }
00385
00386 int EnvironmentPlaneModeling::lookupGroundPlaneForFootprint(
00387 const std::string& footprint_frame, const std_msgs::Header& header,
00388 const std::vector<GridPlane::Ptr>& grid_maps)
00389 {
00390
00391 tf::StampedTransform transform
00392 = lookupTransformWithDuration(tf_listener_,
00393 header.frame_id, footprint_frame,
00394 header.stamp,
00395 ros::Duration(1.0));
00396 Eigen::Affine3f eigen_transform;
00397 tf::transformTFToEigen(transform, eigen_transform);
00398
00399 return lookupGroundPlaneForFootprint(eigen_transform, grid_maps);
00400 }
00401
00402 GridPlane::Ptr EnvironmentPlaneModeling::completeGridMapByBoundingBox(
00403 const jsk_recognition_msgs::BoundingBox::ConstPtr& box,
00404 const std_msgs::Header& header,
00405 GridPlane::Ptr grid_map)
00406 {
00407
00408 tf::StampedTransform tf_transform = lookupTransformWithDuration(
00409 tf_listener_,
00410 header.frame_id,
00411 box->header.frame_id,
00412 header.stamp,
00413 ros::Duration(1.0));
00414 Eigen::Affine3f transform;
00415 tf::transformTFToEigen(tf_transform, transform);
00416 Eigen::Affine3f local_pose;
00417 tf::poseMsgToEigen(box->pose, local_pose);
00418 Eigen::Affine3f global_pose = transform * local_pose;
00419 std::vector<double> dimensions;
00420 dimensions.push_back(box->dimensions.x);
00421 dimensions.push_back(box->dimensions.y);
00422 dimensions.push_back(box->dimensions.z);
00423 jsk_recognition_utils::Cube::Ptr cube (new Cube(Eigen::Vector3f(global_pose.translation()),
00424 Eigen::Quaternionf(global_pose.rotation()),
00425 dimensions));
00426 GridPlane::Ptr completed_grid_map = grid_map->clone();
00427 completed_grid_map->fillCellsFromCube(*cube);
00428 return completed_grid_map;
00429 }
00430
00431 std::vector<GridPlane::Ptr> EnvironmentPlaneModeling::completeFootprintRegion(
00432 const std_msgs::Header& header, std::vector<GridPlane::Ptr>& grid_maps)
00433 {
00434 try {
00435 std::vector<GridPlane::Ptr> completed_grid_maps(grid_maps.size());
00436 std::set<int> ground_plane_indices;
00437 for (size_t i = 0; i < footprint_frames_.size(); i++) {
00438 std::string footprint_frame = footprint_frames_[i];
00439 int grid_index = lookupGroundPlaneForFootprint(
00440 footprint_frame, header, grid_maps);
00441 if (grid_index != -1) {
00442 NODELET_INFO("Found ground plane for %s: %d", footprint_frame.c_str(), grid_index);
00443 ground_plane_indices.insert(grid_index);
00444 }
00445 else {
00446 NODELET_WARN("Cannnot find ground plane for %s: %d", footprint_frame.c_str(), grid_index);
00447 }
00448 }
00449 for (size_t i = 0; i < grid_maps.size(); i++) {
00450 if (ground_plane_indices.find(i) == ground_plane_indices.end()) {
00451
00452 completed_grid_maps[i] = grid_maps[i];
00453 }
00454 else {
00455 completed_grid_maps[i] = completeGridMapByBoundingBox(
00456 latest_leg_bounding_box_, header, grid_maps[i]);
00457 }
00458 }
00459 return completed_grid_maps;
00460 }
00461 catch (tf2::TransformException& e) {
00462 NODELET_FATAL("Failed to lookup transformation: %s", e.what());
00463 return std::vector<GridPlane::Ptr>();
00464 }
00465 }
00466
00467 std::vector<GridPlane::Ptr> EnvironmentPlaneModeling::morphologicalFiltering(
00468 std::vector<GridPlane::Ptr>& raw_grid_maps)
00469 {
00470 std::vector<GridPlane::Ptr> ret;
00471 for (size_t i = 0; i < raw_grid_maps.size(); i++) {
00472 GridPlane::Ptr dilated_grid_map = raw_grid_maps[i]->dilate(morphological_filter_size_);
00473 GridPlane::Ptr eroded_grid_map = dilated_grid_map->erode(morphological_filter_size_);
00474 ret.push_back(eroded_grid_map);
00475 }
00476 return ret;
00477 }
00478
00479
00480 void EnvironmentPlaneModeling::publishConvexPolygonsBoundaries(
00481 ros::Publisher& pub,
00482 const std_msgs::Header& header,
00483 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr>& convexes)
00484 {
00485 pcl::PointCloud<pcl::PointXYZ>::Ptr
00486 boundary_cloud (new pcl::PointCloud<pcl::PointXYZ>);
00487 for (size_t i = 0; i < convexes.size(); i++) {
00488 pcl::PointCloud<pcl::PointXYZ>::Ptr
00489 one_boundary_cloud (new pcl::PointCloud<pcl::PointXYZ>);
00490 convexes[i]->boundariesToPointCloud<pcl::PointXYZ>(
00491 *one_boundary_cloud);
00492 *boundary_cloud = *boundary_cloud + *one_boundary_cloud;
00493 }
00494 sensor_msgs::PointCloud2 ros_cloud;
00495 pcl::toROSMsg(*boundary_cloud, ros_cloud);
00496 ros_cloud.header = header;
00497 pub.publish(ros_cloud);
00498 }
00499
00500 void EnvironmentPlaneModeling::publishGridMaps(
00501 ros::Publisher& pub,
00502 const std_msgs::Header& header,
00503 std::vector<GridPlane::Ptr>& grids)
00504 {
00505 jsk_recognition_msgs::SimpleOccupancyGridArray grid_array;
00506 grid_array.header = header;
00507 for (size_t i = 0; i < grids.size(); i++) {
00508 jsk_recognition_msgs::SimpleOccupancyGrid grid = grids[i]->toROSMsg();
00509 grid.header = header;
00510 grid_array.grids.push_back(grid);
00511 }
00512 pub.publish(grid_array);
00513 }
00514
00515
00516 std::vector<GridPlane::Ptr> EnvironmentPlaneModeling::buildGridPlanes(
00517 pcl::PointCloud<pcl::PointNormal>::Ptr& cloud,
00518 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> convexes,
00519 std::set<int>& non_plane_indices)
00520 {
00521 std::vector<GridPlane::Ptr> ret(convexes.size());
00522
00523 for (size_t i = 0; i < convexes.size(); i++) {
00524 GridPlane::Ptr grid(new GridPlane(convexes[i], resolution_));
00525 size_t num = grid->fillCellsFromPointCloud(cloud, distance_threshold_,
00526 normal_threshold_,
00527 non_plane_indices);
00528 NODELET_INFO("%lu plane contains %lu points",
00529 i, num);
00530 ret[i] = grid;
00531 }
00532 return ret;
00533 }
00534
00535
00536
00537 void EnvironmentPlaneModeling::publishConvexPolygons(
00538 ros::Publisher& pub,
00539 const std_msgs::Header& header,
00540 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr>& convexes)
00541 {
00542 jsk_recognition_msgs::PolygonArray polygon_array;
00543 polygon_array.header = header;
00544 for (size_t i = 0; i < convexes.size(); i++) {
00545 geometry_msgs::PolygonStamped polygon;
00546 polygon.polygon = convexes[i]->toROSMsg();
00547 polygon.header = header;
00548 polygon_array.polygons.push_back(polygon);
00549 }
00550 pub.publish(polygon_array);
00551 }
00552
00553 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> EnvironmentPlaneModeling::magnifyConvexes(
00554 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr>& convexes)
00555 {
00556 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> ret(0);
00557 for (size_t i = 0; i < convexes.size(); i++) {
00558 jsk_recognition_utils::ConvexPolygon::Ptr vertices_convex(new jsk_recognition_utils::ConvexPolygon(convexes[i]->getVertices()));
00559 jsk_recognition_utils::ConvexPolygon::Ptr new_convex = vertices_convex->magnifyByDistance(magnify_distance_);
00560
00561 if (new_convex->getNormalFromVertices().dot(Eigen::Vector3f::UnitZ()) < 0) {
00562 new_convex = boost::make_shared<jsk_recognition_utils::ConvexPolygon>(new_convex->flipConvex());
00563 }
00564 ret.push_back(new_convex);
00565 }
00566 return ret;
00567 }
00568
00569 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> EnvironmentPlaneModeling::convertToConvexPolygons(
00570 const pcl::PointCloud<pcl::PointNormal>::Ptr& cloud,
00571 const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& indices_msg,
00572 const jsk_recognition_msgs::ModelCoefficientsArray::ConstPtr& coefficients_msg)
00573 {
00574 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> convexes(0);
00575 for (size_t i = 0; i < indices_msg->cluster_indices.size(); i++) {
00576 pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00577 inliers->indices = indices_msg->cluster_indices[i].indices;
00578 pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
00579 coefficients->values = coefficients_msg->coefficients[i].values;
00580 jsk_recognition_utils::ConvexPolygon::Ptr convex
00581 = jsk_recognition_utils::convexFromCoefficientsAndInliers<pcl::PointNormal>(
00582 cloud, inliers, coefficients);
00583 convexes.push_back(convex);
00584 }
00585
00586 return convexes;
00587 }
00588
00589 }
00590
00591 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::EnvironmentPlaneModeling,
00592 nodelet::Nodelet);