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_ros/transforms.h>
00043 #include "jsk_recognition_utils/pcl_conversion_util.h"
00044 #include <jsk_topic_tools/rosparam_utils.h>
00045 #include "jsk_recognition_utils/pcl_ros_util.h"
00046 #include "jsk_recognition_utils/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 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 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 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 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 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 onInitPostProcess();
00192 }
00193
00194 void AttentionClipper::initializePoseList(size_t num)
00195 {
00196 pose_list_.resize(num);
00197 for (size_t i = 0; i < pose_list_.size(); i++) {
00198 pose_list_[i].setIdentity();
00199 }
00200 }
00201
00202 void AttentionClipper::subscribe()
00203 {
00204 sub_ = pnh_->subscribe("input", 1, &AttentionClipper::clip, this);
00205 sub_points_ = pnh_->subscribe("input/points", 1,
00206 &AttentionClipper::clipPointcloud, this);
00207 if (!use_multiple_attention_) {
00208 sub_pose_ = pnh_->subscribe("input/pose",
00209 1, &AttentionClipper::poseCallback, this);
00210 sub_box_ = pnh_->subscribe("input/box",
00211 1, &AttentionClipper::boxCallback, this);
00212 }
00213 else {
00214 sub_pose_ = pnh_->subscribe("input/pose_array",
00215 1, &AttentionClipper::poseArrayCallback, this);
00216 sub_box_ = pnh_->subscribe("input/box_array",
00217 1, &AttentionClipper::boxArrayCallback, this);
00218 }
00219 }
00220
00221 void AttentionClipper::unsubscribe()
00222 {
00223 sub_.shutdown();
00224 sub_points_.shutdown();
00225 sub_pose_.shutdown();
00226 sub_box_.shutdown();
00227 }
00228
00229 jsk_recognition_utils::Vertices AttentionClipper::cubeVertices(Eigen::Vector3f& dimension)
00230 {
00231 jsk_recognition_utils::Vertices nonoffsetted_vertices;
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 nonoffsetted_vertices.push_back(
00247 Eigen::Vector3f(dimension[0]/2, dimension[1]/2, dimension[2]/2));
00248 return nonoffsetted_vertices;
00249 }
00250
00251
00252 void AttentionClipper::poseCallback(
00253 const geometry_msgs::PoseStamped::ConstPtr& pose)
00254 {
00255 boost::mutex::scoped_lock lock(mutex_);
00256 frame_id_list_[0] = pose->header.frame_id;
00257 tf::poseMsgToEigen(pose->pose, pose_list_[0]);
00258 }
00259
00260 void AttentionClipper::boxCallback(
00261 const jsk_recognition_msgs::BoundingBox::ConstPtr& box)
00262 {
00263 boost::mutex::scoped_lock lock(mutex_);
00264 dimensions_[0][0] = box->dimensions.x;
00265 dimensions_[0][1] = box->dimensions.y;
00266 dimensions_[0][2] = box->dimensions.z;
00267 frame_id_list_[0] = box->header.frame_id;
00268 tf::poseMsgToEigen(box->pose, pose_list_[0]);
00269 }
00270
00271
00272 void AttentionClipper::poseArrayCallback(
00273 const geometry_msgs::PoseArray::ConstPtr& pose_array)
00274 {
00275 boost::mutex::scoped_lock lock(mutex_);
00276
00277 initializePoseList(pose_array->poses.size());
00278 frame_id_list_.resize(pose_array->poses.size());
00279 std::fill(frame_id_list_.begin(), frame_id_list_.end(),
00280 pose_array->header.frame_id);
00281 for (size_t i = 0; i < pose_list_.size(); i++) {
00282 tf::poseMsgToEigen(pose_array->poses[i], pose_list_[i]);
00283 }
00284 }
00285
00286 void AttentionClipper::boxArrayCallback(
00287 const jsk_recognition_msgs::BoundingBoxArray::ConstPtr& box_array)
00288 {
00289 boost::mutex::scoped_lock lock(mutex_);
00290 initializePoseList(box_array->boxes.size());
00291 frame_id_list_.resize(box_array->boxes.size());
00292 dimensions_.resize(box_array->boxes.size());
00293 for (size_t i = 0; i < pose_list_.size(); i++) {
00294 tf::poseMsgToEigen(box_array->boxes[i].pose, pose_list_[i]);
00295 frame_id_list_[i] = box_array->boxes[i].header.frame_id;
00296 dimensions_[i] = Eigen::Vector3f(box_array->boxes[i].dimensions.x,
00297 box_array->boxes[i].dimensions.y,
00298 box_array->boxes[i].dimensions.z);
00299 }
00300 }
00301
00302 void AttentionClipper::publishBoundingBox(
00303 const std_msgs::Header& header)
00304 {
00305 jsk_recognition_msgs::BoundingBoxArray box_array;
00306 box_array.header.frame_id = header.frame_id;
00307 box_array.header.stamp = header.stamp;
00308 for (size_t i = 0; i < pose_list_.size(); i++) {
00309 jsk_recognition_msgs::BoundingBox box;
00310 box.header = header;
00311 tf::poseEigenToMsg(transformed_pose_list_[i], box.pose);
00312 jsk_recognition_utils::pointFromVectorToXYZ(dimensions_[i], box.dimensions);
00313 box_array.boxes.push_back(box);
00314 }
00315 pub_bounding_box_array_.publish(box_array);
00316 }
00317
00318 void AttentionClipper::computeROI(
00319 const sensor_msgs::CameraInfo::ConstPtr& msg,
00320 std::vector<cv::Point2d>& points,
00321 cv::Mat& mask)
00322 {
00323 double min_u, min_v, max_u, max_v;
00324 min_u = msg->width;
00325 min_v = msg->height;
00326 max_u = max_v = 0;
00327 for (size_t i = 0; i < points.size(); i++) {
00328 cv::Point2d uv(points[i]);
00329
00330 if (uv.x < 0) {
00331 uv.x = 0;
00332 }
00333 if (uv.y < 0) {
00334 uv.y = 0;
00335 }
00336 if (uv.x > msg->width) {
00337 uv.x = msg->width;
00338 }
00339
00340 if (uv.y > msg->height) {
00341 uv.y = msg->height;
00342 }
00343 if (min_u > uv.x) {
00344 min_u = uv.x;
00345 }
00346 if (max_u < uv.x) {
00347 max_u = uv.x;
00348 }
00349 if (min_v > uv.y) {
00350 min_v = uv.y;
00351 }
00352
00353 if (max_v < uv.y) {
00354 max_v = uv.y;
00355 }
00356 }
00357
00358 cv::Rect raw_roi(min_u, min_v, (max_u - min_u), (max_v - min_v));
00359 cv::Rect original(0, 0, msg->width, msg->height);
00360 cv::Rect roi_region = raw_roi & original;
00361 sensor_msgs::CameraInfo roi(*msg);
00362 roi.roi.x_offset = roi_region.x;
00363 roi.roi.y_offset = roi_region.y;
00364 roi.roi.width = roi_region.width;
00365 roi.roi.height = roi_region.height;
00366 roi.roi.do_rectify = true;
00367 pub_camera_info_.publish(roi);
00368
00369 mask = cv::Mat::zeros(msg->height, msg->width, CV_8UC1);
00370 cv::Size roi_size(roi_region.width, roi_region.height);
00371 cv::Rect roi_rect(cv::Point(roi_region.x, roi_region.y), roi_size);
00372 const cv::Scalar white(255);
00373 cv::rectangle(mask, roi_rect, white, CV_FILLED);
00374 }
00375
00376 void AttentionClipper::clipPointcloud(
00377 const sensor_msgs::PointCloud2::ConstPtr& msg)
00378 {
00379 boost::mutex::scoped_lock lock(mutex_);
00380 NODELET_DEBUG("clipPointcloud");
00381 vital_checker_->poke();
00382 try {
00383
00384
00385
00386 pcl::PointIndices::Ptr all_indices (new pcl::PointIndices);
00387 jsk_recognition_msgs::ClusterPointIndices cluster_indices_msg;
00388 std::map<std::string, tf::StampedTransform> transforms;
00389 transformed_pose_list_.clear();
00390 for (size_t i = 0; i < pose_list_.size(); i++) {
00391 std::string frame_id = frame_id_list_[i];
00392
00393 if (transforms.find(frame_id) == transforms.end()) {
00394 tf::StampedTransform new_transform = lookupTransformWithDuration(
00395 tf_listener_,
00396 frame_id,
00397 msg->header.frame_id,
00398 msg->header.stamp,
00399 ros::Duration(1.0));
00400 transforms[frame_id] = new_transform;
00401 }
00402 tf::StampedTransform tf_transform = transforms[frame_id];
00403 Eigen::Affine3f transform;
00404 tf::transformTFToEigen(tf_transform, transform);
00405 pcl::PointCloud<pcl::PointXYZ>::Ptr
00406 cloud(new pcl::PointCloud<pcl::PointXYZ>);
00407 pcl::fromROSMsg(*msg, *cloud);
00408
00409 Eigen::Affine3f transformed_box_pose = transform * pose_list_[i];
00410 transformed_pose_list_.push_back(transformed_box_pose);
00411
00412 pcl::PointIndices::Ptr indices (new pcl::PointIndices);
00413 jsk_recognition_msgs::BoundingBox bbox_msg;
00414 bbox_msg.header.frame_id = cloud->header.frame_id;
00415 tf::poseEigenToMsg(transformed_box_pose, bbox_msg.pose);
00416 bbox_msg.dimensions.x = dimensions_[i][0];
00417 bbox_msg.dimensions.y = dimensions_[i][1];
00418 bbox_msg.dimensions.z = dimensions_[i][2];
00419 jsk_recognition_utils::cropPointCloud<pcl::PointXYZ>(cloud, bbox_msg, &(indices->indices));
00420
00421
00422
00423 pcl::PointIndices non_nan_indices;
00424 for (size_t j = 0; j < indices->indices.size(); j++) {
00425 pcl::PointXYZ p = cloud->points[indices->indices[j]];
00426 if (pcl_isfinite(p.x) && pcl_isfinite(p.y) && pcl_isfinite(p.z)) {
00427 non_nan_indices.indices.push_back(indices->indices[j]);
00428 }
00429 }
00430 PCLIndicesMsg indices_msg;
00431 pcl_conversions::fromPCL(non_nan_indices, indices_msg);
00432 cluster_indices_msg.cluster_indices.push_back(indices_msg);
00433 if(prefixes_.size()){
00434 indices_msg.header = msg->header;
00435 multiple_pub_indices_[i].publish(indices_msg);
00436 }
00437
00438 all_indices = jsk_recognition_utils::addIndices(*all_indices, non_nan_indices);
00439 }
00440 if (negative_) {
00441
00442 pcl::PointIndices::Ptr tmp_indices (new pcl::PointIndices);
00443 std::set<int> positive_indices(all_indices->indices.begin(), all_indices->indices.end());
00444 for (size_t i = 0; i < msg->width * msg->height; i++) {
00445 if (positive_indices.find(i) == positive_indices.end()) {
00446 tmp_indices->indices.push_back(i);
00447 }
00448 }
00449 all_indices = tmp_indices;
00450 }
00451 PCLIndicesMsg indices_msg;
00452 pcl_conversions::fromPCL(*all_indices, indices_msg);
00453 cluster_indices_msg.header = indices_msg.header = msg->header;
00454 pub_indices_.publish(indices_msg);
00455 pub_cluster_indices_.publish(cluster_indices_msg);
00456 publishBoundingBox(msg->header);
00457 }
00458 catch (std::runtime_error &e) {
00459 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00460 }
00461 }
00462
00463 void AttentionClipper::clip(const sensor_msgs::CameraInfo::ConstPtr& msg)
00464 {
00465 boost::mutex::scoped_lock lock(mutex_);
00466 vital_checker_->poke();
00467
00468 try {
00469 image_geometry::PinholeCameraModel model;
00470 cv::Mat all_mask_image = cv::Mat::zeros(msg->height, msg->width, CV_8UC1);
00471 bool model_success_p = model.fromCameraInfo(msg);
00472 if (!model_success_p) {
00473 ROS_ERROR("failed to create camera model");
00474 return;
00475 }
00476 for (size_t i = 0; i < pose_list_.size(); i++) {
00477 std::string frame_id = frame_id_list_[i];
00478 tf_listener_->waitForTransform(frame_id,
00479 msg->header.frame_id,
00480 msg->header.stamp,
00481 ros::Duration(1.0));
00482 Eigen::Affine3f offset = pose_list_[i];
00483 if (tf_listener_->canTransform(msg->header.frame_id,
00484 frame_id,
00485 msg->header.stamp)) {
00486 tf::StampedTransform transform;
00487 tf_listener_->lookupTransform(frame_id, msg->header.frame_id,
00488 msg->header.stamp, transform);
00489 Eigen::Affine3f eigen_transform;
00490 tf::transformTFToEigen(transform, eigen_transform);
00491 jsk_recognition_utils::Vertices original_vertices = cubeVertices(dimensions_[i]);
00492 jsk_recognition_utils::Vertices vertices;
00493 for (size_t i = 0; i < original_vertices.size(); i++) {
00494 vertices.push_back(eigen_transform.inverse()
00495 * (offset * original_vertices[i]));
00496 }
00497 std::vector<cv::Point2d> local_points;
00498 for (size_t i = 0; i < vertices.size(); i++) {
00499 cv::Point3d p(vertices[i][0], vertices[i][1], vertices[i][2]);
00500 cv::Point2d uv = model.project3dToPixel(p);
00501 local_points.push_back(uv);
00502 }
00503 cv::Mat mask_image;
00504 computeROI(msg, local_points, mask_image);
00505 all_mask_image = all_mask_image | mask_image;
00506 }
00507 }
00508
00509 cv_bridge::CvImage mask_bridge(msg->header,
00510 sensor_msgs::image_encodings::MONO8,
00511 all_mask_image);
00512 pub_mask_.publish(mask_bridge.toImageMsg());
00513
00514 }
00515 catch (std::runtime_error &e) {
00516 NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
00517 }
00518 }
00519
00520 void AttentionClipper::updateDiagnostic(
00521 diagnostic_updater::DiagnosticStatusWrapper &stat)
00522 {
00523 if (vital_checker_->isAlive()) {
00524 stat.summary(diagnostic_msgs::DiagnosticStatus::OK,
00525 "AttentionClipper running");
00526 }
00527 else {
00528 jsk_topic_tools::addDiagnosticErrorSummary(
00529 "AttentionClipper", vital_checker_, stat);
00530 }
00531 }
00532
00533 }
00534
00535 #include <pluginlib/class_list_macros.h>
00536 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::AttentionClipper, nodelet::Nodelet);