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 #define BOOST_PARAMETER_MAX_ARITY 7
00036 #include "jsk_pcl_ros/attention_clipper.h"
00037 #include <eigen_conversions/eigen_msg.h>
00038 #include <tf_conversions/tf_eigen.h>
00039 #include <opencv2/opencv.hpp>
00040 #include <cv_bridge/cv_bridge.h>
00041 #include <sensor_msgs/image_encodings.h>
00042 #include <pcl/filters/crop_box.h>
00043 #include <pcl_ros/transforms.h>
00044 #include "jsk_pcl_ros/pcl_conversion_util.h"
00045 #include <jsk_topic_tools/rosparam_utils.h>
00046 #include "jsk_pcl_ros/pcl_util.h"
00047 #include <algorithm>
00048 #include <set>
00049 namespace jsk_pcl_ros
00050 {
00051 void AttentionClipper::onInit()
00052 {
00053 DiagnosticNodelet::onInit();
00054 tf_listener_ = TfListenerSingleton::getInstance();
00055 pnh_->param("negative", negative_, false);
00056 pnh_->param("use_multiple_attention", use_multiple_attention_, false);
00057 if (!use_multiple_attention_) {
00058 Eigen::Affine3f pose = Eigen::Affine3f::Identity();
00059 std::vector<double> initial_pos;
00060 if (jsk_topic_tools::readVectorParameter(*pnh_,
00061 "initial_pos",
00062 initial_pos))
00063 {
00064 pose.translation() = Eigen::Vector3f(initial_pos[0],
00065 initial_pos[1],
00066 initial_pos[2]);
00067 }
00068
00069 std::vector<double> initial_rot;
00070 if (jsk_topic_tools::readVectorParameter(*pnh_,
00071 "initial_rot",
00072 initial_rot))
00073 {
00074 pose = pose
00075 * Eigen::AngleAxisf(initial_rot[0],
00076 Eigen::Vector3f::UnitX())
00077 * Eigen::AngleAxisf(initial_rot[1],
00078 Eigen::Vector3f::UnitY())
00079 * Eigen::AngleAxisf(initial_rot[2],
00080 Eigen::Vector3f::UnitZ());
00081 }
00082
00083
00084
00085 double dimension_x, dimension_y, dimension_z;
00086 pnh_->param("dimension_x", dimension_x, 0.1);
00087 pnh_->param("dimension_y", dimension_y, 0.1);
00088 pnh_->param("dimension_z", dimension_z, 0.1);
00089 dimensions_.push_back(Eigen::Vector3f(dimension_x,
00090 dimension_y,
00091 dimension_z));
00092 std::string frame_id;
00093 pnh_->param("frame_id", frame_id, std::string("base_link"));
00094 frame_id_list_.push_back(frame_id);
00095 pose_list_.push_back(pose);
00096 }
00097 else {
00098
00099
00100 std::vector<std::vector<double> > initial_pos_list;
00101 std::vector<std::vector<double> > initial_rot_list;
00102 std::vector<std::vector<double> > dimensions;
00103 jsk_topic_tools::readVectorParameter(*pnh_, "initial_pos_list",
00104 initial_pos_list);
00105 jsk_topic_tools::readVectorParameter(*pnh_, "initial_rot_list",
00106 initial_rot_list);
00107 jsk_topic_tools::readVectorParameter(*pnh_, "dimensions", dimensions);
00108 jsk_topic_tools::readVectorParameter(*pnh_, "prefixes", prefixes_);
00109 if (initial_pos_list.size() != 0) {
00110 initializePoseList(initial_pos_list.size());
00111 for (size_t i = 0; i < initial_pos_list.size(); i++) {
00112 if (initial_pos_list[i].size() != 3) {
00113 JSK_NODELET_FATAL("element of ~initial_pos_list should be [x, y, z]");
00114 return;
00115 }
00116 pose_list_[i].translation() = Eigen::Vector3f(initial_pos_list[i][0],
00117 initial_pos_list[i][1],
00118 initial_pos_list[i][2]);
00119 }
00120 }
00121
00122
00123 if (initial_rot_list.size() != 0) {
00124
00125 if (initial_pos_list.size() != 0 &&
00126 initial_rot_list.size() != initial_pos_list.size()) {
00127 JSK_NODELET_FATAL(
00128 "the size of ~initial_pos_list and ~initial_rot_list are different");
00129 return;
00130 }
00131 if (initial_pos_list.size() == 0) {
00132 initializePoseList(initial_rot_list.size());
00133 }
00134 for (size_t i = 0; i < initial_rot_list.size(); i++) {
00135 if (initial_rot_list[i].size() != 3) {
00136 JSK_NODELET_FATAL("element of ~initial_rot_list should be [rx, ry, rz]");
00137 return;
00138 }
00139 pose_list_[i] = pose_list_[i]
00140 * Eigen::AngleAxisf(initial_rot_list[i][0],
00141 Eigen::Vector3f::UnitX())
00142 * Eigen::AngleAxisf(initial_rot_list[i][1],
00143 Eigen::Vector3f::UnitY())
00144 * Eigen::AngleAxisf(initial_rot_list[i][2],
00145 Eigen::Vector3f::UnitZ());
00146 }
00147 }
00148
00149
00150 if (dimensions.size() != 0) {
00151
00152 if (pose_list_.size() != 0 &&
00153 pose_list_.size() != dimensions.size()) {
00154 JSK_NODELET_FATAL(
00155 "the size of ~dimensions and ~initial_pos_list or ~initial_rot_list are different");
00156 return;
00157 }
00158 if (pose_list_.size() == 0) {
00159 initializePoseList(dimensions.size());
00160 }
00161 for (size_t i = 0; i < dimensions.size(); i++) {
00162 dimensions_.push_back(Eigen::Vector3f(dimensions[i][0],
00163 dimensions[i][1],
00164 dimensions[i][2]));
00165 }
00166 }
00167
00168
00169
00170 if (prefixes_.size() != 0) {
00171
00172 if (prefixes_.size() != dimensions.size()) {
00173 JSK_NODELET_FATAL(
00174 "the size of ~prefixes and ~dimensions are different");
00175 return;
00176 }
00177 for(int i = 0; i < prefixes_.size(); i++){
00178 multiple_pub_indices_.push_back(advertise<PCLIndicesMsg>(*pnh_, prefixes_[i]+std::string("/point_indices"), 1));
00179 }
00180 }
00181
00182 jsk_topic_tools::readVectorParameter(*pnh_, "frame_id_list", frame_id_list_);
00183 }
00184 pub_camera_info_ = advertise<sensor_msgs::CameraInfo>(*pnh_, "output", 1);
00185 pub_bounding_box_array_
00186 = advertise<jsk_recognition_msgs::BoundingBoxArray>(*pnh_, "output/box_array", 1);
00187 pub_mask_ = advertise<sensor_msgs::Image>(*pnh_, "output/mask", 1);
00188 pub_indices_ = advertise<PCLIndicesMsg>(*pnh_, "output/point_indices", 1);
00189 pub_cluster_indices_ = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_, "output/cluster_point_indices", 1);
00190 }
00191
00192 void AttentionClipper::initializePoseList(size_t num)
00193 {
00194 pose_list_.resize(num);
00195 for (size_t i = 0; i < pose_list_.size(); i++) {
00196 pose_list_[i].setIdentity();
00197 }
00198 }
00199
00200 void AttentionClipper::subscribe()
00201 {
00202 sub_ = pnh_->subscribe("input", 1, &AttentionClipper::clip, this);
00203 sub_points_ = pnh_->subscribe("input/points", 1,
00204 &AttentionClipper::clipPointcloud, this);
00205 if (!use_multiple_attention_) {
00206 sub_pose_ = pnh_->subscribe("input/pose",
00207 1, &AttentionClipper::poseCallback, this);
00208 sub_box_ = pnh_->subscribe("input/box",
00209 1, &AttentionClipper::boxCallback, this);
00210 }
00211 else {
00212 sub_pose_ = pnh_->subscribe("input/pose_array",
00213 1, &AttentionClipper::poseArrayCallback, this);
00214 sub_box_ = pnh_->subscribe("input/box_array",
00215 1, &AttentionClipper::boxArrayCallback, this);
00216 }
00217 }
00218
00219 void AttentionClipper::unsubscribe()
00220 {
00221 sub_.shutdown();
00222 sub_points_.shutdown();
00223 sub_pose_.shutdown();
00224 sub_box_.shutdown();
00225 }
00226
00227 Vertices AttentionClipper::cubeVertices(Eigen::Vector3f& dimension)
00228 {
00229 Vertices nonoffsetted_vertices;
00230 nonoffsetted_vertices.push_back(
00231 Eigen::Vector3f(-dimension[0]/2, -dimension[1]/2, -dimension[2]/2));
00232 nonoffsetted_vertices.push_back(
00233 Eigen::Vector3f(-dimension[0]/2, -dimension[1]/2, dimension[2]/2));
00234 nonoffsetted_vertices.push_back(
00235 Eigen::Vector3f(-dimension[0]/2, dimension[1]/2, -dimension[2]/2));
00236 nonoffsetted_vertices.push_back(
00237 Eigen::Vector3f(-dimension[0]/2, dimension[1]/2, dimension[2]/2));
00238 nonoffsetted_vertices.push_back(
00239 Eigen::Vector3f(dimension[0]/2, -dimension[1]/2, -dimension[2]/2));
00240 nonoffsetted_vertices.push_back(
00241 Eigen::Vector3f(dimension[0]/2, -dimension[1]/2, dimension[2]/2));
00242 nonoffsetted_vertices.push_back(
00243 Eigen::Vector3f(dimension[0]/2, dimension[1]/2, -dimension[2]/2));
00244 nonoffsetted_vertices.push_back(
00245 Eigen::Vector3f(dimension[0]/2, dimension[1]/2, dimension[2]/2));
00246 return nonoffsetted_vertices;
00247 }
00248
00249
00250 void AttentionClipper::poseCallback(
00251 const geometry_msgs::PoseStamped::ConstPtr& pose)
00252 {
00253 boost::mutex::scoped_lock lock(mutex_);
00254 frame_id_list_[0] = pose->header.frame_id;
00255 tf::poseMsgToEigen(pose->pose, pose_list_[0]);
00256 }
00257
00258 void AttentionClipper::boxCallback(
00259 const jsk_recognition_msgs::BoundingBox::ConstPtr& box)
00260 {
00261 boost::mutex::scoped_lock lock(mutex_);
00262 dimensions_[0][0] = box->dimensions.x;
00263 dimensions_[0][1] = box->dimensions.y;
00264 dimensions_[0][2] = box->dimensions.z;
00265 frame_id_list_[0] = box->header.frame_id;
00266 tf::poseMsgToEigen(box->pose, pose_list_[0]);
00267 }
00268
00269
00270 void AttentionClipper::poseArrayCallback(
00271 const geometry_msgs::PoseArray::ConstPtr& pose_array)
00272 {
00273 boost::mutex::scoped_lock lock(mutex_);
00274
00275 initializePoseList(pose_array->poses.size());
00276 frame_id_list_.resize(pose_array->poses.size());
00277 std::fill(frame_id_list_.begin(), frame_id_list_.end(),
00278 pose_array->header.frame_id);
00279 for (size_t i = 0; i < pose_list_.size(); i++) {
00280 tf::poseMsgToEigen(pose_array->poses[i], pose_list_[i]);
00281 }
00282 }
00283
00284 void AttentionClipper::boxArrayCallback(
00285 const jsk_recognition_msgs::BoundingBoxArray::ConstPtr& box_array)
00286 {
00287 boost::mutex::scoped_lock lock(mutex_);
00288 initializePoseList(box_array->boxes.size());
00289 frame_id_list_.resize(box_array->boxes.size());
00290 dimensions_.resize(box_array->boxes.size());
00291 for (size_t i = 0; i < pose_list_.size(); i++) {
00292 tf::poseMsgToEigen(box_array->boxes[i].pose, pose_list_[i]);
00293 frame_id_list_[i] = box_array->boxes[i].header.frame_id;
00294 dimensions_[i] = Eigen::Vector3f(box_array->boxes[i].dimensions.x,
00295 box_array->boxes[i].dimensions.y,
00296 box_array->boxes[i].dimensions.z);
00297 }
00298 }
00299
00300 void AttentionClipper::publishBoundingBox(
00301 const std_msgs::Header& header)
00302 {
00303 jsk_recognition_msgs::BoundingBoxArray box_array;
00304 box_array.header.frame_id = header.frame_id;
00305 box_array.header.stamp = header.stamp;
00306 for (size_t i = 0; i < pose_list_.size(); i++) {
00307 jsk_recognition_msgs::BoundingBox box;
00308 box.header.stamp = header.stamp;
00309 box.header.frame_id = frame_id_list_[i];
00310 tf::poseEigenToMsg(pose_list_[i], box.pose);
00311 jsk_pcl_ros::pointFromVectorToXYZ(dimensions_[i], box.dimensions);
00312 box_array.boxes.push_back(box);
00313 }
00314 pub_bounding_box_array_.publish(box_array);
00315 }
00316
00317 void AttentionClipper::computeROI(
00318 const sensor_msgs::CameraInfo::ConstPtr& msg,
00319 std::vector<cv::Point2d>& points,
00320 cv::Mat& mask)
00321 {
00322 double min_u, min_v, max_u, max_v;
00323 min_u = msg->width;
00324 min_v = msg->height;
00325 max_u = max_v = 0;
00326 for (size_t i = 0; i < points.size(); i++) {
00327 cv::Point2d uv(points[i]);
00328
00329 if (uv.x < 0) {
00330 uv.x = 0;
00331 }
00332 if (uv.y < 0) {
00333 uv.y = 0;
00334 }
00335 if (uv.x > msg->width) {
00336 uv.x = msg->width;
00337 }
00338
00339 if (uv.y > msg->height) {
00340 uv.y = msg->height;
00341 }
00342 if (min_u > uv.x) {
00343 min_u = uv.x;
00344 }
00345 if (max_u < uv.x) {
00346 max_u = uv.x;
00347 }
00348 if (min_v > uv.y) {
00349 min_v = uv.y;
00350 }
00351
00352 if (max_v < uv.y) {
00353 max_v = uv.y;
00354 }
00355 }
00356
00357 cv::Rect raw_roi(min_u, min_v, (max_u - min_u), (max_v - min_v));
00358 cv::Rect original(0, 0, msg->width, msg->height);
00359 cv::Rect roi_region = raw_roi & original;
00360 sensor_msgs::CameraInfo roi(*msg);
00361 roi.roi.x_offset = roi_region.x;
00362 roi.roi.y_offset = roi_region.y;
00363 roi.roi.width = roi_region.width;
00364 roi.roi.height = roi_region.height;
00365 roi.roi.do_rectify = true;
00366 pub_camera_info_.publish(roi);
00367
00368 mask = cv::Mat::zeros(msg->height, msg->width, CV_8UC1);
00369 cv::Size roi_size(roi_region.width, roi_region.height);
00370 cv::Rect roi_rect(cv::Point(roi_region.x, roi_region.y), roi_size);
00371 const cv::Scalar white(255);
00372 cv::rectangle(mask, roi_rect, white, CV_FILLED);
00373 }
00374
00375 void AttentionClipper::clipPointcloud(
00376 const sensor_msgs::PointCloud2::ConstPtr& msg)
00377 {
00378 boost::mutex::scoped_lock lock(mutex_);
00379 JSK_NODELET_DEBUG("clipPointcloud");
00380 vital_checker_->poke();
00381 try {
00382
00383
00384
00385 pcl::PointIndices::Ptr all_indices (new pcl::PointIndices);
00386 jsk_recognition_msgs::ClusterPointIndices cluster_indices_msg;
00387 std::map<std::string, tf::StampedTransform> transforms;
00388 for (size_t i = 0; i < pose_list_.size(); i++) {
00389 std::string frame_id = frame_id_list_[i];
00390
00391 if (transforms.find(frame_id) == transforms.end()) {
00392 tf::StampedTransform new_transform = lookupTransformWithDuration(
00393 tf_listener_,
00394 frame_id, msg->header.frame_id,
00395 msg->header.stamp,
00396 ros::Duration(1.0));
00397 transforms[frame_id] = new_transform;
00398 }
00399 tf::StampedTransform tf_transform = transforms[frame_id];
00400 Eigen::Affine3f transform;
00401 tf::transformTFToEigen(tf_transform, transform);
00402 pcl::PointCloud<pcl::PointXYZ>::Ptr
00403 cloud(new pcl::PointCloud<pcl::PointXYZ>);
00404 pcl::PointCloud<pcl::PointXYZ>::Ptr
00405 input_cloud(new pcl::PointCloud<pcl::PointXYZ>);
00406 pcl::fromROSMsg(*msg, *input_cloud);
00407 pcl::transformPointCloud(*input_cloud, *cloud, transform);
00408 pcl::CropBox<pcl::PointXYZ> crop_box(false);
00409 pcl::PointIndices::Ptr indices (new pcl::PointIndices);
00410 JSK_NODELET_DEBUG("max_points: [%f, %f, %f]", dimensions_[i][0]/2,
00411 dimensions_[i][1]/2,
00412 dimensions_[i][2]/2);
00413 JSK_NODELET_DEBUG("min_points: [%f, %f, %f]",
00414 -dimensions_[i][0]/2,
00415 -dimensions_[i][1]/2,
00416 -dimensions_[i][2]/2);
00417 Eigen::Vector4f max_points(dimensions_[i][0]/2,
00418 dimensions_[i][1]/2,
00419 dimensions_[i][2]/2,
00420 0);
00421 Eigen::Vector4f min_points(-dimensions_[i][0]/2,
00422 -dimensions_[i][1]/2,
00423 -dimensions_[i][2]/2,
00424 0);
00425 float roll, pitch, yaw;
00426 pcl::getEulerAngles(pose_list_[i], roll, pitch, yaw);
00427 crop_box.setInputCloud(cloud);
00428 crop_box.setMax(max_points);
00429 crop_box.setMin(min_points);
00430 crop_box.setTranslation(pose_list_[i].translation());
00431 crop_box.setRotation(Eigen::Vector3f(roll, pitch, yaw));
00432 crop_box.filter(indices->indices);
00433
00434
00435 pcl::PointIndices non_nan_indices;
00436 for (size_t j = 0; j < indices->indices.size(); j++) {
00437 pcl::PointXYZ p = cloud->points[indices->indices[j]];
00438 if (pcl_isfinite(p.x) && pcl_isfinite(p.y) && pcl_isfinite(p.z)) {
00439 non_nan_indices.indices.push_back(indices->indices[j]);
00440 }
00441 }
00442 PCLIndicesMsg indices_msg;
00443 pcl_conversions::fromPCL(non_nan_indices, indices_msg);
00444 cluster_indices_msg.cluster_indices.push_back(indices_msg);
00445 if(prefixes_.size()){
00446 indices_msg.header = msg->header;
00447 multiple_pub_indices_[i].publish(indices_msg);
00448 }
00449
00450 all_indices = addIndices(*all_indices, non_nan_indices);
00451 }
00452 if (negative_) {
00453
00454 pcl::PointIndices::Ptr tmp_indices (new pcl::PointIndices);
00455 std::set<int> positive_indices(all_indices->indices.begin(), all_indices->indices.end());
00456 for (size_t i = 0; i < msg->width * msg->height; i++) {
00457 if (positive_indices.find(i) == positive_indices.end()) {
00458 tmp_indices->indices.push_back(i);
00459 }
00460 }
00461 all_indices = tmp_indices;
00462 }
00463 PCLIndicesMsg indices_msg;
00464 pcl_conversions::fromPCL(*all_indices, indices_msg);
00465 cluster_indices_msg.header = indices_msg.header = msg->header;
00466 pub_indices_.publish(indices_msg);
00467 pub_cluster_indices_.publish(cluster_indices_msg);
00468 publishBoundingBox(msg->header);
00469 }
00470 catch (std::runtime_error &e) {
00471 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00472 }
00473 }
00474
00475 void AttentionClipper::clip(const sensor_msgs::CameraInfo::ConstPtr& msg)
00476 {
00477 boost::mutex::scoped_lock lock(mutex_);
00478 vital_checker_->poke();
00479
00480 try {
00481 image_geometry::PinholeCameraModel model;
00482 cv::Mat all_mask_image = cv::Mat::zeros(msg->height, msg->width, CV_8UC1);
00483 bool model_success_p = model.fromCameraInfo(msg);
00484 if (!model_success_p) {
00485 JSK_ROS_ERROR("failed to create camera model");
00486 return;
00487 }
00488 for (size_t i = 0; i < pose_list_.size(); i++) {
00489 std::string frame_id = frame_id_list_[i];
00490 tf_listener_->waitForTransform(frame_id,
00491 msg->header.frame_id,
00492 msg->header.stamp,
00493 ros::Duration(1.0));
00494 Eigen::Affine3f offset = pose_list_[i];
00495 if (tf_listener_->canTransform(msg->header.frame_id,
00496 frame_id,
00497 msg->header.stamp)) {
00498 tf::StampedTransform transform;
00499 tf_listener_->lookupTransform(frame_id, msg->header.frame_id,
00500 msg->header.stamp, transform);
00501 Eigen::Affine3f eigen_transform;
00502 tf::transformTFToEigen(transform, eigen_transform);
00503 Vertices original_vertices = cubeVertices(dimensions_[i]);
00504 Vertices vertices;
00505 for (size_t i = 0; i < original_vertices.size(); i++) {
00506 vertices.push_back(eigen_transform.inverse()
00507 * (offset * original_vertices[i]));
00508 }
00509 std::vector<cv::Point2d> local_points;
00510 for (size_t i = 0; i < vertices.size(); i++) {
00511 cv::Point3d p(vertices[i][0], vertices[i][1], vertices[i][2]);
00512 cv::Point2d uv = model.project3dToPixel(p);
00513 local_points.push_back(uv);
00514 }
00515 cv::Mat mask_image;
00516 computeROI(msg, local_points, mask_image);
00517 all_mask_image = all_mask_image | mask_image;
00518 }
00519 }
00520
00521 cv_bridge::CvImage mask_bridge(msg->header,
00522 sensor_msgs::image_encodings::MONO8,
00523 all_mask_image);
00524 pub_mask_.publish(mask_bridge.toImageMsg());
00525 publishBoundingBox(msg->header);
00526 }
00527 catch (std::runtime_error &e) {
00528 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00529 }
00530 }
00531
00532 void AttentionClipper::updateDiagnostic(
00533 diagnostic_updater::DiagnosticStatusWrapper &stat)
00534 {
00535 if (vital_checker_->isAlive()) {
00536 stat.summary(diagnostic_msgs::DiagnosticStatus::OK,
00537 "AttentionClipper running");
00538 }
00539 else {
00540 jsk_topic_tools::addDiagnosticErrorSummary(
00541 "AttentionClipper", vital_checker_, stat);
00542 }
00543 }
00544
00545 }
00546
00547 #include <pluginlib/class_list_macros.h>
00548 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::AttentionClipper, nodelet::Nodelet);