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 
00521 #include <pluginlib/class_list_macros.h>
00522 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::AttentionClipper, nodelet::Nodelet);