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/cluster_point_indices_decomposer.h"
00037 #include <cv_bridge/cv_bridge.h>
00038 #include <pluginlib/class_list_macros.h>
00039 #include <pcl/filters/extract_indices.h>
00040 #include <pcl/common/centroid.h>
00041 #include <pcl/common/common.h>
00042 #include <boost/format.hpp>
00043 #include <boost/range/adaptors.hpp>
00044 #include <boost/range/algorithm.hpp>
00045 #include <boost/range/irange.hpp>
00046 #include <pcl/registration/ia_ransac.h>
00047 #include <pcl/filters/project_inliers.h>
00048 #include <pcl/common/pca.h>
00049 #include <sensor_msgs/image_encodings.h>
00050 #include <jsk_topic_tools/color_utils.h>
00051 #include <Eigen/Geometry>
00052 #include <geometry_msgs/PoseArray.h>
00053
00054 #include "jsk_recognition_utils/geo_util.h"
00055 #include "jsk_recognition_utils/pcl_conversion_util.h"
00056 #include "jsk_recognition_utils/pcl_util.h"
00057
00058 namespace jsk_pcl_ros
00059 {
00060 void ClusterPointIndicesDecomposerZAxis::onInit()
00061 {
00062 ClusterPointIndicesDecomposer::onInit();
00063 sort_by_ = "z_axis";
00064 }
00065
00066 void ClusterPointIndicesDecomposer::onInit()
00067 {
00068 DiagnosticNodelet::onInit();
00069 pnh_->param("publish_tf", publish_tf_, false);
00070 if (publish_tf_) {
00071 br_.reset(new tf::TransformBroadcaster);
00072 }
00073 if (!pnh_->getParam("tf_prefix", tf_prefix_))
00074 {
00075 if (publish_tf_) {
00076 NODELET_WARN("~tf_prefix is not specified, using %s", getName().c_str());
00077 }
00078 tf_prefix_ = getName();
00079 }
00080
00081
00082 pnh_->param("approximate_sync", use_async_, false);
00083 pnh_->param("queue_size", queue_size_, 100);
00084 pnh_->param("publish_clouds", publish_clouds_, false);
00085 if (publish_clouds_) {
00086 NODELET_WARN("~output%%02d are not published before subscribed, you should subscribe ~debug_output in debuging.");
00087 }
00088 pnh_->param("align_boxes", align_boxes_, false);
00089 if (align_boxes_) {
00090 pnh_->param("align_boxes_with_plane", align_boxes_with_plane_, true);
00091 } else if (pnh_->hasParam("align_boxes_with_plane")) {
00092 NODELET_WARN("Rosparam ~align_boxes_with_plane is used only with ~align_boxes:=true, so ignoring it.");
00093 }
00094 if (align_boxes_ && !align_boxes_with_plane_) {
00095 tf_listener_ = jsk_recognition_utils::TfListenerSingleton::getInstance();
00096 if (!pnh_->getParam("target_frame_id", target_frame_id_)) {
00097 NODELET_FATAL("~target_frame_id is not specified");
00098 return;
00099 }
00100 NODELET_INFO("Aligning bboxes with '%s' using tf transform.", target_frame_id_.c_str());
00101 } else if (pnh_->hasParam("target_frame_id")) {
00102 NODELET_WARN("Rosparam ~target_frame_id is used only with ~align_boxes:=true and ~align_boxes_with_plane:=true, so ignoring it.");
00103 }
00104 pnh_->param("use_pca", use_pca_, false);
00105 pnh_->param("force_to_flip_z_axis", force_to_flip_z_axis_, true);
00106 pnh_->param<std::string>("sort_by", sort_by_, "input_indices");
00107
00108 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> >(*pnh_);
00109 dynamic_reconfigure::Server<Config>::CallbackType f =
00110 boost::bind(&ClusterPointIndicesDecomposer::configCallback, this, _1, _2);
00111 srv_->setCallback(f);
00112
00113 negative_indices_pub_ = advertise<pcl_msgs::PointIndices>(*pnh_, "negative_indices", 1);
00114 pc_pub_ = advertise<sensor_msgs::PointCloud2>(*pnh_, "debug_output", 1);
00115 box_pub_ = advertise<jsk_recognition_msgs::BoundingBoxArray>(*pnh_, "boxes", 1);
00116 mask_pub_ = advertise<sensor_msgs::Image>(*pnh_, "mask", 1);
00117 label_pub_ = advertise<sensor_msgs::Image>(*pnh_, "label", 1);
00118 centers_pub_ = advertise<geometry_msgs::PoseArray>(*pnh_, "centroid_pose_array", 1);
00119 indices_pub_ = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_, "cluster_indices", 1);
00120
00121 onInitPostProcess();
00122 }
00123
00124 void ClusterPointIndicesDecomposer::configCallback(Config &config, uint32_t level)
00125 {
00126 boost::mutex::scoped_lock(mutex_);
00127 max_size_ = config.max_size;
00128 min_size_ = config.min_size;
00129 }
00130
00131 void ClusterPointIndicesDecomposer::subscribe()
00132 {
00133 sub_input_.subscribe(*pnh_, "input", 1);
00134 sub_target_.subscribe(*pnh_, "target", 1);
00135 if (align_boxes_ && align_boxes_with_plane_) {
00136 sync_align_ = boost::make_shared<message_filters::Synchronizer<SyncAlignPolicy> >(queue_size_);
00137 sub_polygons_.subscribe(*pnh_, "align_planes", 1);
00138 sub_coefficients_.subscribe(*pnh_, "align_planes_coefficients", 1);
00139 sync_align_->connectInput(sub_input_, sub_target_, sub_polygons_, sub_coefficients_);
00140 sync_align_->registerCallback(boost::bind(&ClusterPointIndicesDecomposer::extract, this, _1, _2, _3, _4));
00141 }
00142 else if (use_async_) {
00143 async_ = boost::make_shared<message_filters::Synchronizer<ApproximateSyncPolicy> >(queue_size_);
00144 async_->connectInput(sub_input_, sub_target_);
00145 async_->registerCallback(boost::bind(&ClusterPointIndicesDecomposer::extract, this, _1, _2));
00146 }
00147 else {
00148 sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(queue_size_);
00149 sync_->connectInput(sub_input_, sub_target_);
00150 sync_->registerCallback(boost::bind(&ClusterPointIndicesDecomposer::extract, this, _1, _2));
00151 }
00152 }
00153
00154 void ClusterPointIndicesDecomposer::unsubscribe()
00155 {
00156 sub_input_.unsubscribe();
00157 sub_target_.unsubscribe();
00158 if (align_boxes_ && align_boxes_with_plane_) {
00159 sub_polygons_.unsubscribe();
00160 sub_coefficients_.unsubscribe();
00161 }
00162 }
00163
00164 void ClusterPointIndicesDecomposer::sortIndicesOrder(
00165 const pcl::PointCloud<pcl::PointXYZ>::Ptr input,
00166 const std::vector<pcl::IndicesPtr> indices_array,
00167 std::vector<size_t>* argsort)
00168 {
00169 std::string sort_by = sort_by_;
00170 bool reverse = false;
00171 if (sort_by.compare(0, 1, "-") == 0)
00172 {
00173 reverse = true;
00174 sort_by = sort_by.substr(1, sort_by.size() - 1);
00175 }
00176 if (sort_by == "input_indices")
00177 {
00178 sortIndicesOrderByIndices(input, indices_array, argsort);
00179 }
00180 else if (sort_by == "z_axis")
00181 {
00182 sortIndicesOrderByZAxis(input, indices_array, argsort);
00183 }
00184 else if (sort_by == "cloud_size")
00185 {
00186 sortIndicesOrderByCloudSize(input, indices_array, argsort);
00187 }
00188 else
00189 {
00190 NODELET_WARN_ONCE("Unsupported ~sort_by param is specified '%s', "
00191 "so using the default: 'input_indices'", sort_by_.c_str());
00192 sortIndicesOrderByIndices(input, indices_array, argsort);
00193 return;
00194 }
00195 if (reverse)
00196 {
00197 std::reverse((*argsort).begin(), (*argsort).end());
00198 }
00199 }
00200
00201 void ClusterPointIndicesDecomposer::sortIndicesOrderByIndices(
00202 const pcl::PointCloud<pcl::PointXYZ>::Ptr input,
00203 const std::vector<pcl::IndicesPtr> indices_array,
00204 std::vector<size_t>* argsort)
00205 {
00206 (*argsort).resize(indices_array.size());
00207 for (size_t i = 0; i < indices_array.size(); i++)
00208 {
00209 (*argsort)[i] = i;
00210 }
00211 }
00212
00213 void ClusterPointIndicesDecomposer::sortIndicesOrderByZAxis(
00214 const pcl::PointCloud<pcl::PointXYZ>::Ptr input,
00215 const std::vector<pcl::IndicesPtr> indices_array,
00216 std::vector<size_t>* argsort)
00217 {
00218 std::vector<double> z_values;
00219 pcl::ExtractIndices<pcl::PointXYZ> ex;
00220 ex.setInputCloud(input);
00221 for (size_t i = 0; i < indices_array.size(); i++)
00222 {
00223 Eigen::Vector4f center;
00224 ex.setIndices(indices_array[i]);
00225 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00226 ex.filter(*cloud);
00227
00228 std::vector<int> nan_indices;
00229 pcl::removeNaNFromPointCloud(*cloud, *cloud, nan_indices);
00230
00231 pcl::compute3DCentroid(*cloud, center);
00232 z_values.push_back(center[2]);
00233 }
00234
00235
00236
00237 (*argsort).resize(indices_array.size());
00238 std::iota(argsort->begin(), argsort->end(), 0);
00239 std::sort(argsort->begin(), argsort->end(),
00240 [&z_values](size_t i1, size_t i2) {return z_values[i1] < z_values[i2];});
00241 }
00242
00243 void ClusterPointIndicesDecomposer::sortIndicesOrderByCloudSize(
00244 const pcl::PointCloud<pcl::PointXYZ>::Ptr input,
00245 const std::vector<pcl::IndicesPtr> indices_array,
00246 std::vector<size_t>* argsort)
00247 {
00248 std::vector<double> cloud_sizes;
00249 pcl::ExtractIndices<pcl::PointXYZ> ex;
00250 ex.setInputCloud(input);
00251 for (size_t i = 0; i < indices_array.size(); i++)
00252 {
00253 Eigen::Vector4f center;
00254 ex.setIndices(indices_array[i]);
00255 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00256 ex.filter(*cloud);
00257
00258 std::vector<int> nan_indices;
00259 pcl::removeNaNFromPointCloud(*cloud, *cloud, nan_indices);
00260
00261 double cloud_size = static_cast<double>(cloud->points.size());
00262 cloud_sizes.push_back(cloud_size);
00263 }
00264
00265
00266 (*argsort).resize(indices_array.size());
00267 std::iota(argsort->begin(), argsort->end(), 0);
00268 std::sort(argsort->begin(), argsort->end(),
00269 [&cloud_sizes](size_t i1, size_t i2) {return cloud_sizes[i1] < cloud_sizes[i2];});
00270 }
00271
00272 void ClusterPointIndicesDecomposer::updateDiagnostic(
00273 diagnostic_updater::DiagnosticStatusWrapper &stat)
00274 {
00275 if (vital_checker_->isAlive()) {
00276 stat.summary(diagnostic_msgs::DiagnosticStatus::OK,
00277 "ClusterPointIndicesDecomposer running");
00278 jsk_topic_tools::addDiagnosticBooleanStat(
00279 "publish_clouds", publish_clouds_, stat);
00280 jsk_topic_tools::addDiagnosticBooleanStat(
00281 "publish_tf", publish_tf_, stat);
00282 jsk_topic_tools::addDiagnosticBooleanStat(
00283 "use_pca", use_pca_, stat);
00284 jsk_topic_tools::addDiagnosticBooleanStat(
00285 "align_boxes", align_boxes_, stat);
00286 stat.add("tf_prefix", tf_prefix_);
00287 stat.add("Clusters (Ave.)", cluster_counter_.mean());
00288 }
00289 DiagnosticNodelet::updateDiagnostic(stat);
00290 }
00291
00292 int ClusterPointIndicesDecomposer::findNearestPlane(
00293 const Eigen::Vector4f& center,
00294 const jsk_recognition_msgs::PolygonArrayConstPtr& planes,
00295 const jsk_recognition_msgs::ModelCoefficientsArrayConstPtr& coefficients)
00296 {
00297 double min_distance = DBL_MAX;
00298 int nearest_index = -1;
00299 for (size_t i = 0; i < coefficients->coefficients.size(); i++) {
00300 geometry_msgs::PolygonStamped polygon_msg = planes->polygons[i];
00301 jsk_recognition_utils::Vertices vertices;
00302 for (size_t j = 0; j < polygon_msg.polygon.points.size(); j++) {
00303 jsk_recognition_utils::Vertex v;
00304 v[0] = polygon_msg.polygon.points[j].x;
00305 v[1] = polygon_msg.polygon.points[j].y;
00306 v[2] = polygon_msg.polygon.points[j].z;
00307 vertices.push_back(v);
00308 }
00309 jsk_recognition_utils::ConvexPolygon p(vertices, coefficients->coefficients[i].values);
00310 double distance = p.distanceToPoint(center);
00311 if (distance < min_distance) {
00312 min_distance = distance;
00313 nearest_index = i;
00314 }
00315 }
00316 return nearest_index;
00317 }
00318
00319 bool ClusterPointIndicesDecomposer::transformPointCloudToAlignWithPlane(
00320 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr segmented_cloud,
00321 pcl::PointCloud<pcl::PointXYZRGB>::Ptr segmented_cloud_transformed,
00322 const Eigen::Vector4f center,
00323 const jsk_recognition_msgs::PolygonArrayConstPtr& planes,
00324 const jsk_recognition_msgs::ModelCoefficientsArrayConstPtr& coefficients,
00325 Eigen::Matrix4f& m4,
00326 Eigen::Quaternionf& q)
00327 {
00328 int nearest_plane_index = findNearestPlane(center, planes, coefficients);
00329 if (nearest_plane_index == -1) {
00330 segmented_cloud_transformed = segmented_cloud;
00331 NODELET_ERROR("no planes to align boxes are given");
00332 }
00333 else {
00334 Eigen::Vector3f normal, z_axis;
00335 if (force_to_flip_z_axis_) {
00336 normal[0] = - coefficients->coefficients[nearest_plane_index].values[0];
00337 normal[1] = - coefficients->coefficients[nearest_plane_index].values[1];
00338 normal[2] = - coefficients->coefficients[nearest_plane_index].values[2];
00339 }
00340 else {
00341 normal[0] = coefficients->coefficients[nearest_plane_index].values[0];
00342 normal[1] = coefficients->coefficients[nearest_plane_index].values[1];
00343 normal[2] = coefficients->coefficients[nearest_plane_index].values[2];
00344 }
00345 normal = normal.normalized();
00346 Eigen::Quaternionf rot;
00347 rot.setFromTwoVectors(Eigen::Vector3f::UnitZ(), normal);
00348 Eigen::AngleAxisf rotation_angle_axis(rot);
00349 Eigen::Vector3f rotation_axis = rotation_angle_axis.axis();
00350 double theta = rotation_angle_axis.angle();
00351 if (std::isnan(theta) ||
00352 std::isnan(rotation_axis[0]) ||
00353 std::isnan(rotation_axis[1]) ||
00354 std::isnan(rotation_axis[2])) {
00355 segmented_cloud_transformed = segmented_cloud;
00356 NODELET_ERROR("cannot compute angle to align the point cloud: [%f, %f, %f], [%f, %f, %f]",
00357 z_axis[0], z_axis[1], z_axis[2],
00358 normal[0], normal[1], normal[2]);
00359 }
00360 else {
00361 Eigen::Matrix3f m = Eigen::Matrix3f::Identity() * rot;
00362 if (use_pca_) {
00363
00364 pcl::PointCloud<pcl::PointXYZRGB>::Ptr projected_cloud
00365 (new pcl::PointCloud<pcl::PointXYZRGB>);
00366 pcl::ProjectInliers<pcl::PointXYZRGB> proj;
00367 proj.setModelType (pcl::SACMODEL_PLANE);
00368 pcl::ModelCoefficients::Ptr
00369 plane_coefficients (new pcl::ModelCoefficients);
00370 plane_coefficients->values
00371 = coefficients->coefficients[nearest_plane_index].values;
00372 proj.setModelCoefficients(plane_coefficients);
00373 proj.setInputCloud(segmented_cloud);
00374 proj.filter(*projected_cloud);
00375 if (projected_cloud->points.size() >= 3) {
00376 pcl::PCA<pcl::PointXYZRGB> pca;
00377 pca.setInputCloud(projected_cloud);
00378 Eigen::Matrix3f eigen = pca.getEigenVectors();
00379 m.col(0) = eigen.col(0);
00380 m.col(1) = eigen.col(1);
00381
00382 if (m.col(0).cross(m.col(1)).dot(m.col(2)) < 0) {
00383 m.col(0) = - m.col(0);
00384 }
00385 if (m.col(0).dot(Eigen::Vector3f::UnitX()) < 0) {
00386
00387 m = m * Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitZ());
00388 }
00389 }
00390 else {
00391 NODELET_ERROR("Too small indices for PCA computation");
00392 return false;
00393 }
00394 }
00395
00396 for (size_t row = 0; row < 3; row++) {
00397 for (size_t column = 0; column < 3; column++) {
00398 m4(row, column) = m(row, column);
00399 }
00400 }
00401 q = m;
00402 q.normalize();
00403 Eigen::Matrix4f inv_m = m4.inverse();
00404 pcl::transformPointCloud(*segmented_cloud, *segmented_cloud_transformed, inv_m);
00405 }
00406 }
00407 return true;
00408 }
00409
00410 bool ClusterPointIndicesDecomposer::computeCenterAndBoundingBox
00411 (const pcl::PointCloud<pcl::PointXYZRGB>::Ptr segmented_cloud,
00412 const std_msgs::Header header,
00413 const jsk_recognition_msgs::PolygonArrayConstPtr& planes,
00414 const jsk_recognition_msgs::ModelCoefficientsArrayConstPtr& coefficients,
00415 geometry_msgs::Pose& center_pose_msg,
00416 jsk_recognition_msgs::BoundingBox& bounding_box)
00417 {
00418 bounding_box.header = header;
00419 if (segmented_cloud->points.size() == 0) {
00420 NODELET_WARN("segmented cloud size is zero");
00421 return true;
00422 }
00423
00424 bool is_center_valid = false;
00425 Eigen::Vector4f center;
00426 pcl::PointCloud<pcl::PointXYZRGB>::Ptr
00427 segmented_cloud_transformed (new pcl::PointCloud<pcl::PointXYZRGB>);
00428 segmented_cloud_transformed->is_dense = segmented_cloud->is_dense;
00429
00430 Eigen::Matrix4f m4 = Eigen::Matrix4f::Identity();
00431 Eigen::Quaternionf q = Eigen::Quaternionf::Identity();
00432 if (align_boxes_) {
00433 if (align_boxes_with_plane_) {
00434 is_center_valid = pcl::compute3DCentroid(*segmented_cloud, center) != 0;
00435 bool success = transformPointCloudToAlignWithPlane(segmented_cloud, segmented_cloud_transformed,
00436 center, planes, coefficients, m4, q);
00437 if (!success) {
00438 return false;
00439 }
00440 }
00441 else {
00442
00443 tf::StampedTransform tf_transform;
00444 try {
00445 tf_transform = jsk_recognition_utils::lookupTransformWithDuration(
00446 tf_listener_,
00447 header.frame_id,
00448 target_frame_id_,
00449 header.stamp,
00450 ros::Duration(1.0));
00451 }
00452 catch (tf2::TransformException &e) {
00453 NODELET_ERROR("Transform error: %s", e.what());
00454 return false;
00455 }
00456 Eigen::Affine3f transform;
00457 tf::transformTFToEigen(tf_transform, transform);
00458 pcl::transformPointCloud(*segmented_cloud, *segmented_cloud, transform);
00459
00460 is_center_valid = pcl::compute3DCentroid(*segmented_cloud, center) != 0;
00461
00462
00463 pcl::PointXYZRGB min_pt, max_pt;
00464 pcl::getMinMax3D(*segmented_cloud, min_pt, max_pt);
00465
00466 pcl_msgs::ModelCoefficients coef_by_frame;
00467 coef_by_frame.values.push_back(0);
00468 coef_by_frame.values.push_back(0);
00469 coef_by_frame.values.push_back(1);
00470 coef_by_frame.values.push_back(- min_pt.z);
00471 jsk_recognition_msgs::ModelCoefficientsArray::Ptr coefficients_by_frame(
00472 new jsk_recognition_msgs::ModelCoefficientsArray);
00473 coefficients_by_frame->header.frame_id = target_frame_id_;
00474 coefficients_by_frame->coefficients.push_back(coef_by_frame);
00475
00476 geometry_msgs::PolygonStamped plane_by_frame;
00477 plane_by_frame.header.frame_id = target_frame_id_;
00478 geometry_msgs::Point32 point;
00479 point.z = min_pt.z;
00480 point.x = min_pt.x;
00481 point.y = min_pt.y;
00482 plane_by_frame.polygon.points.push_back(point);
00483 point.x = max_pt.x;
00484 point.y = min_pt.y;
00485 plane_by_frame.polygon.points.push_back(point);
00486 point.x = max_pt.x;
00487 point.y = max_pt.y;
00488 plane_by_frame.polygon.points.push_back(point);
00489 point.x = min_pt.x;
00490 point.y = max_pt.y;
00491 plane_by_frame.polygon.points.push_back(point);
00492 jsk_recognition_msgs::PolygonArray::Ptr planes_by_frame(
00493 new jsk_recognition_msgs::PolygonArray);
00494 planes_by_frame->header.frame_id = target_frame_id_;
00495 planes_by_frame->polygons.push_back(plane_by_frame);
00496
00497 bool success = transformPointCloudToAlignWithPlane(segmented_cloud, segmented_cloud_transformed,
00498 center, planes_by_frame, coefficients_by_frame, m4, q);
00499 if (!success) {
00500 return false;
00501 }
00502 }
00503 }
00504 else {
00505 segmented_cloud_transformed = segmented_cloud;
00506 is_center_valid = pcl::compute3DCentroid(*segmented_cloud_transformed, center) != 0;
00507 }
00508
00509
00510 Eigen::Vector4f minpt, maxpt;
00511 pcl::getMinMax3D<pcl::PointXYZRGB>(*segmented_cloud_transformed, minpt, maxpt);
00512
00513 double xwidth = maxpt[0] - minpt[0];
00514 double ywidth = maxpt[1] - minpt[1];
00515 double zwidth = maxpt[2] - minpt[2];
00516 if (!pcl_isfinite(xwidth) || !pcl_isfinite(ywidth) || !pcl_isfinite(zwidth))
00517 {
00518
00519 xwidth = ywidth = zwidth = 0;
00520 }
00521
00522 Eigen::Vector4f center2((maxpt[0] + minpt[0]) / 2.0, (maxpt[1] + minpt[1]) / 2.0, (maxpt[2] + minpt[2]) / 2.0, 1.0);
00523 Eigen::Vector4f center_transformed = m4 * center2;
00524
00525
00526 if (is_center_valid) {
00527 center_pose_msg.position.x = center[0];
00528 center_pose_msg.position.y = center[1];
00529 center_pose_msg.position.z = center[2];
00530 center_pose_msg.orientation.x = 0;
00531 center_pose_msg.orientation.y = 0;
00532 center_pose_msg.orientation.z = 0;
00533 center_pose_msg.orientation.w = 1;
00534 }
00535 else {
00536
00537 center_pose_msg = geometry_msgs::Pose();
00538 }
00539
00540
00541 bounding_box.pose.position.x = center_transformed[0];
00542 bounding_box.pose.position.y = center_transformed[1];
00543 bounding_box.pose.position.z = center_transformed[2];
00544 bounding_box.pose.orientation.x = q.x();
00545 bounding_box.pose.orientation.y = q.y();
00546 bounding_box.pose.orientation.z = q.z();
00547 bounding_box.pose.orientation.w = q.w();
00548 bounding_box.dimensions.x = xwidth;
00549 bounding_box.dimensions.y = ywidth;
00550 bounding_box.dimensions.z = zwidth;
00551 return true;
00552 }
00553
00554 void ClusterPointIndicesDecomposer::addToDebugPointCloud
00555 (const pcl::PointCloud<pcl::PointXYZRGB>::Ptr segmented_cloud,
00556 size_t i,
00557 pcl::PointCloud<pcl::PointXYZRGB>& debug_output)
00558 {
00559 uint32_t rgb = colorRGBAToUInt32(jsk_topic_tools::colorCategory20(i));
00560 for (size_t j = 0; j < segmented_cloud->points.size(); j++) {
00561 pcl::PointXYZRGB p;
00562 p.x= segmented_cloud->points[j].x;
00563 p.y= segmented_cloud->points[j].y;
00564 p.z= segmented_cloud->points[j].z;
00565 p.rgb = *reinterpret_cast<float*>(&rgb);
00566 debug_output.points.push_back(p);
00567 }
00568 }
00569
00570 void ClusterPointIndicesDecomposer::publishNegativeIndices(
00571 const sensor_msgs::PointCloud2ConstPtr &input,
00572 const jsk_recognition_msgs::ClusterPointIndicesConstPtr &indices_input)
00573 {
00574 if (negative_indices_pub_.getNumSubscribers() <= 0) {
00575 return;
00576 }
00577 std::vector<int> all_indices;
00578
00579 boost::copy(
00580 boost::irange(0, (int)(input->width * input->height)),
00581 std::inserter(all_indices, all_indices.begin()));
00582
00583 for (size_t i = 0; i < indices_input->cluster_indices.size(); i++) {
00584 for (size_t j = 0; j < indices_input->cluster_indices[i].indices.size(); ++j) {
00585 all_indices[indices_input->cluster_indices[i].indices[j]] = -1;
00586 }
00587 }
00588 all_indices.erase(std::remove(all_indices.begin(), all_indices.end(), -1), all_indices.end());
00589
00590
00591 pcl_msgs::PointIndices ros_indices;
00592 ros_indices.indices = std::vector<int>(all_indices.begin(), all_indices.end());
00593 ros_indices.header = input->header;
00594 negative_indices_pub_.publish(ros_indices);
00595 }
00596
00597 void ClusterPointIndicesDecomposer::extract(
00598 const sensor_msgs::PointCloud2ConstPtr &input,
00599 const jsk_recognition_msgs::ClusterPointIndicesConstPtr &indices_input,
00600 const jsk_recognition_msgs::PolygonArrayConstPtr& planes,
00601 const jsk_recognition_msgs::ModelCoefficientsArrayConstPtr& coefficients)
00602 {
00603 vital_checker_->poke();
00604 if (publish_clouds_) {
00605 allocatePublishers(indices_input->cluster_indices.size());
00606 }
00607 publishNegativeIndices(input, indices_input);
00608 pcl::ExtractIndices<pcl::PointXYZRGB> extract;
00609 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
00610 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz (new pcl::PointCloud<pcl::PointXYZ>);
00611 pcl::fromROSMsg(*input, *cloud);
00612 pcl::fromROSMsg(*input, *cloud_xyz);
00613 cluster_counter_.add(indices_input->cluster_indices.size());
00614
00615 std::vector<pcl::IndicesPtr> converted_indices;
00616
00617 for (size_t i = 0; i < indices_input->cluster_indices.size(); i++)
00618 {
00619 pcl::IndicesPtr vindices;
00620
00621 if (min_size_ > 0 &&
00622 indices_input->cluster_indices[i].indices.size() < min_size_) {
00623 vindices.reset (new std::vector<int> ());
00624 converted_indices.push_back(vindices);
00625 continue;
00626 }
00627 if (max_size_ > 0 &&
00628 indices_input->cluster_indices[i].indices.size() > max_size_) {
00629 vindices.reset (new std::vector<int> ());
00630 converted_indices.push_back(vindices);
00631 continue;
00632 }
00633 vindices.reset (new std::vector<int> (indices_input->cluster_indices[i].indices));
00634 converted_indices.push_back(vindices);
00635 }
00636
00637 std::vector<size_t> argsort;
00638 sortIndicesOrder(cloud_xyz, converted_indices, &argsort);
00639 extract.setInputCloud(cloud);
00640
00641
00642 bool is_sensed_with_camera = (input->height != 1);
00643
00644 cv::Mat mask = cv::Mat::zeros(input->height, input->width, CV_8UC1);
00645 cv::Mat label = cv::Mat::zeros(input->height, input->width, CV_32SC1);
00646 pcl::PointCloud<pcl::PointXYZRGB> debug_output;
00647 jsk_recognition_msgs::BoundingBoxArray bounding_box_array;
00648 jsk_recognition_msgs::ClusterPointIndices out_cluster_indices;
00649 bounding_box_array.header = input->header;
00650 geometry_msgs::PoseArray center_pose_array;
00651 center_pose_array.header = input->header;
00652 out_cluster_indices.header = input->header;
00653 for (size_t i = 0; i < argsort.size(); i++)
00654 {
00655 pcl::PointCloud<pcl::PointXYZRGB>::Ptr segmented_cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
00656 segmented_cloud->is_dense = cloud->is_dense;
00657
00658 pcl_msgs::PointIndices out_indices_msg;
00659 out_indices_msg.header = input->header;
00660 out_indices_msg.indices = *(converted_indices[argsort[i]]);
00661 out_cluster_indices.cluster_indices.push_back(out_indices_msg);
00662
00663 pcl::PointIndices::Ptr segmented_indices (new pcl::PointIndices);
00664 extract.setIndices(converted_indices[argsort[i]]);
00665 extract.filter(*segmented_cloud);
00666 if (publish_clouds_) {
00667 sensor_msgs::PointCloud2::Ptr out_cloud(new sensor_msgs::PointCloud2);
00668 pcl::toROSMsg(*segmented_cloud, *out_cloud);
00669 out_cloud->header = input->header;
00670 publishers_[i].publish(out_cloud);
00671 }
00672
00673 if (is_sensed_with_camera) {
00674
00675 for (size_t j = 0; j < converted_indices[argsort[i]]->size(); j++) {
00676 int index = converted_indices[argsort[i]]->data()[j];
00677 int width_index = index % input->width;
00678 int height_index = index / input->width;
00679 mask.at<uchar>(height_index, width_index) = 255;
00680
00681
00682 label.at<int>(height_index, width_index) = (int)i + 1;
00683 }
00684 }
00685
00686 addToDebugPointCloud(segmented_cloud, i, debug_output);
00687
00688
00689 geometry_msgs::Pose pose_msg;
00690 jsk_recognition_msgs::BoundingBox bounding_box;
00691 bounding_box.label = static_cast<int>(argsort[i]);
00692
00693 if (!segmented_cloud->is_dense) {
00694 std::vector<int> nan_indices;
00695 pcl::removeNaNFromPointCloud(*segmented_cloud, *segmented_cloud, nan_indices);
00696 }
00697
00698 bool successp = computeCenterAndBoundingBox(
00699 segmented_cloud, input->header, planes, coefficients, pose_msg, bounding_box);
00700 if (!successp) {
00701 return;
00702 }
00703 std::string target_frame;
00704 if (align_boxes_ && !align_boxes_with_plane_) {
00705 target_frame = target_frame_id_;
00706 }
00707 else {
00708 target_frame = input->header.frame_id;
00709 }
00710 center_pose_array.poses.push_back(pose_msg);
00711 bounding_box.header.frame_id = target_frame;
00712 bounding_box_array.boxes.push_back(bounding_box);
00713 if (publish_tf_) {
00714 tf::Transform transform;
00715 transform.setOrigin(tf::Vector3(pose_msg.position.x, pose_msg.position.y, pose_msg.position.z));
00716 transform.setRotation(tf::createIdentityQuaternion());
00717 br_->sendTransform(tf::StampedTransform(transform, input->header.stamp, target_frame,
00718 tf_prefix_ + (boost::format("output%02u") % (i)).str()));
00719 }
00720 }
00721
00722
00723 if (align_boxes_ && !align_boxes_with_plane_) {
00724 bounding_box_array.header.frame_id = target_frame_id_;
00725 center_pose_array.header.frame_id = target_frame_id_;
00726 }
00727
00728 if (is_sensed_with_camera) {
00729
00730 cv_bridge::CvImage mask_bridge(indices_input->header,
00731 sensor_msgs::image_encodings::MONO8,
00732 mask);
00733 mask_pub_.publish(mask_bridge.toImageMsg());
00734
00735 cv_bridge::CvImage label_bridge(indices_input->header,
00736 sensor_msgs::image_encodings::TYPE_32SC1,
00737 label);
00738 label_pub_.publish(label_bridge.toImageMsg());
00739 }
00740
00741 sensor_msgs::PointCloud2 debug_ros_output;
00742 pcl::toROSMsg(debug_output, debug_ros_output);
00743 debug_ros_output.header = input->header;
00744 debug_ros_output.is_dense = false;
00745 pc_pub_.publish(debug_ros_output);
00746 centers_pub_.publish(center_pose_array);
00747 box_pub_.publish(bounding_box_array);
00748 indices_pub_.publish(out_cluster_indices);
00749 }
00750
00751 void ClusterPointIndicesDecomposer::extract
00752 (const sensor_msgs::PointCloud2ConstPtr &input,
00753 const jsk_recognition_msgs::ClusterPointIndicesConstPtr &indices_input)
00754 {
00755 extract(input, indices_input,
00756 jsk_recognition_msgs::PolygonArrayConstPtr(),
00757 jsk_recognition_msgs::ModelCoefficientsArrayConstPtr());
00758 }
00759
00760 void ClusterPointIndicesDecomposer::allocatePublishers(size_t num)
00761 {
00762 if (num > publishers_.size())
00763 {
00764 for (size_t i = publishers_.size(); i < num; i++)
00765 {
00766 std::string topic_name = (boost::format("output%02u") % (i)).str();
00767 NODELET_INFO("advertising %s", topic_name.c_str());
00768 ros::Publisher publisher = pnh_->advertise<sensor_msgs::PointCloud2>(topic_name, 1);
00769 publishers_.push_back(publisher);
00770 }
00771 }
00772 }
00773
00774 }
00775
00776 PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::ClusterPointIndicesDecomposer, nodelet::Nodelet);
00777
00778 PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::ClusterPointIndicesDecomposerZAxis, nodelet::Nodelet);