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_recognition_utils/pcl_conversion_util.h"
00037 #include "jsk_pcl_ros_utils/plane_reasoner.h"
00038 #include <tf_conversions/tf_eigen.h>
00039 
00040 namespace jsk_pcl_ros_utils
00041 {
00042   void PlaneReasoner::onInit()
00043   {
00045     
00047     DiagnosticNodelet::onInit();
00048     tf_listener_ = jsk_recognition_utils::TfListenerSingleton::getInstance();
00049     
00051     
00053     srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00054     dynamic_reconfigure::Server<Config>::CallbackType f =
00055       boost::bind (
00056         &PlaneReasoner::configCallback, this, _1, _2);
00057     srv_->setCallback (f);
00058 
00060     
00062     pub_vertical_inliers_
00063       = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_, "output/vertical/inliers", 1);
00064     pub_vertical_coefficients_
00065       = advertise<jsk_recognition_msgs::ModelCoefficientsArray>(*pnh_, "output/vertical/coefficients", 1);
00066     pub_vertical_polygons_
00067       = advertise<jsk_recognition_msgs::PolygonArray>(*pnh_, "output/vertical/polygons", 1);
00068     pub_horizontal_inliers_
00069       = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_, "output/horizontal/inliers", 1);
00070     pub_horizontal_coefficients_
00071       = advertise<jsk_recognition_msgs::ModelCoefficientsArray>(*pnh_, "output/horizontal/coefficients", 1);
00072     pub_horizontal_polygons_
00073       = advertise<jsk_recognition_msgs::PolygonArray>(*pnh_, "output/horizontal/polygons", 1);
00074 
00075     onInitPostProcess();
00076   }
00077 
00078   void PlaneReasoner::subscribe()
00079   {
00081     
00083     sub_input_.subscribe(*pnh_, "input", 1);
00084     sub_inliers_.subscribe(*pnh_, "input_inliers", 1);
00085     sub_coefficients_.subscribe(*pnh_, "input_coefficients", 1);
00086     sub_polygons_.subscribe(*pnh_, "input_polygons", 1);
00087     sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00088     sync_->connectInput(sub_input_, sub_inliers_,
00089                         sub_coefficients_, sub_polygons_);
00090     sync_->registerCallback(boost::bind(&PlaneReasoner::reason,
00091                                         this, _1, _2, _3, _4));
00092   }
00093 
00094   void PlaneReasoner::unsubscribe()
00095   {
00096     sub_input_.unsubscribe();
00097     sub_inliers_.unsubscribe();
00098     sub_coefficients_.unsubscribe();
00099     sub_polygons_.unsubscribe();
00100   }
00101                                 
00102   
00103   void PlaneReasoner::configCallback(Config &config, uint32_t level)
00104   {
00105     boost::mutex::scoped_lock lock(mutex_);
00106     global_frame_id_ = config.global_frame_id;
00107     horizontal_angular_threshold_ = config.horizontal_angular_threshold;
00108     vertical_angular_threshold_ = config.vertical_angular_threshold;
00109   }
00110 
00111   void PlaneReasoner::reason(
00112       const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
00113       const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& inliers_msg,
00114       const jsk_recognition_msgs::ModelCoefficientsArray::ConstPtr& coefficients_msg,
00115       const jsk_recognition_msgs::PolygonArray::ConstPtr& polygons_msg)
00116   {
00117     boost::mutex::scoped_lock lock(mutex_);
00118     
00119     if ((inliers_msg->cluster_indices.size()
00120          != coefficients_msg->coefficients.size()) ||
00121         (inliers_msg->cluster_indices.size()
00122          != polygons_msg->polygons.size())) {
00123       NODELET_FATAL("the size of inliers, coefficients and polygons are not same");
00124       return;
00125     }
00126     vital_checker_->poke();
00127     pcl::PointCloud<PointT>::Ptr input_cloud (new pcl::PointCloud<PointT>);
00128     pcl::fromROSMsg(*cloud_msg, *input_cloud);
00129     
00130     
00131     std::vector<pcl::PointIndices::Ptr> inliers
00132       = pcl_conversions::convertToPCLPointIndices(inliers_msg->cluster_indices);
00133     std::vector<pcl::ModelCoefficients::Ptr> coefficients
00134       = pcl_conversions::convertToPCLModelCoefficients(
00135         coefficients_msg->coefficients);
00136     std::vector<jsk_recognition_utils::Plane::Ptr> planes = jsk_recognition_utils::convertToPlanes(coefficients);
00137     std::vector<geometry_msgs::PolygonStamped> polygons = polygons_msg->polygons;
00138     std::vector<PlaneInfoContainer> plane_infos
00139       = packInfo(inliers, coefficients, planes, polygons);
00140     std::vector<PlaneInfoContainer> horizontal_planes
00141       = filterHorizontalPlanes(plane_infos);
00142     std::vector<PlaneInfoContainer> vertical_planes
00143       = filterVerticalPlanes(plane_infos);
00144     publishPlaneInfo(vertical_planes,
00145                      cloud_msg->header,
00146                      input_cloud,
00147                      pub_vertical_inliers_,
00148                      pub_vertical_coefficients_,
00149                      pub_vertical_polygons_);
00150     publishPlaneInfo(horizontal_planes,
00151                      cloud_msg->header,
00152                      input_cloud,
00153                      pub_horizontal_inliers_,
00154                      pub_horizontal_coefficients_,
00155                      pub_horizontal_polygons_);
00156   }
00157 
00158   void PlaneReasoner::publishPlaneInfo(
00159     std::vector<PlaneInfoContainer>& containers,
00160     const std_msgs::Header& header,
00161     pcl::PointCloud<PointT>::Ptr cloud,
00162     ros::Publisher& pub_inlier,
00163     ros::Publisher& pub_coefficients,
00164     ros::Publisher& pub_polygons)
00165   {
00166     std::vector<pcl::PointIndices::Ptr> inliers;
00167     std::vector<pcl::ModelCoefficients::Ptr> coefficients;
00168     std::vector<geometry_msgs::PolygonStamped> polygons;
00169     for (size_t i = 0; i < containers.size(); i++) {
00170       inliers.push_back(containers[i].get<0>());
00171       coefficients.push_back(containers[i].get<1>());
00172       polygons.push_back(containers[i].get<3>());
00173     }
00174     jsk_recognition_msgs::ClusterPointIndices ros_indices;
00175     jsk_recognition_msgs::ModelCoefficientsArray ros_coefficients;
00176     jsk_recognition_msgs::PolygonArray ros_polygons;
00177     ros_indices.header = header;
00178     ros_coefficients.header = header;
00179     ros_polygons.header = header;
00180     ros_indices.cluster_indices = pcl_conversions::convertToROSPointIndices(
00181       inliers, header);
00182     ros_coefficients.coefficients
00183       = pcl_conversions::convertToROSModelCoefficients(
00184         coefficients, header);
00185     ros_polygons.polygons = polygons;
00186     pub_inlier.publish(ros_indices);
00187     pub_coefficients.publish(ros_coefficients);
00188     pub_polygons.publish(ros_polygons);
00189   }
00190   
00191   std::vector<PlaneInfoContainer>
00192   PlaneReasoner::filterPlanesAroundAngle(
00193     double reference_angle,
00194     double thrshold,
00195     std::vector<PlaneInfoContainer>& infos)
00196   {
00197     
00198     std::vector<PlaneInfoContainer> ret;
00199     for (size_t i = 0; i < infos.size(); i++) {
00200       PlaneInfoContainer plane_info = infos[i];
00201       if (tf_listener_->canTransform(global_frame_id_,
00202                                      plane_info.get<3>().header.frame_id,
00203                                      plane_info.get<3>().header.stamp)) {
00204         tf::StampedTransform transform;
00205         tf_listener_->lookupTransform(plane_info.get<3>().header.frame_id, global_frame_id_,
00206                                       
00207                                       plane_info.get<3>().header.stamp,
00208                                       transform);
00209         Eigen::Affine3d eigen_transform;
00210         tf::transformTFToEigen(transform, eigen_transform);
00211         Eigen::Affine3f eigen_transform_3f;
00212         Eigen::Vector3d up_d =  (eigen_transform.rotation() * Eigen::Vector3d(0, 0, 1));
00213         Eigen::Vector3f up;
00214         jsk_recognition_utils::pointFromVectorToVector<Eigen::Vector3d, Eigen::Vector3f>(up_d, up);
00215         jsk_recognition_utils::Plane::Ptr plane = plane_info.get<2>();
00216         double angle = plane->angle(up);
00217         
00218         
00219         
00220         if (fabs(angle - reference_angle) < thrshold) {
00221           ret.push_back(plane_info);
00222         }
00223       }
00224     }
00225     return ret;
00226   }
00227   
00228   std::vector<PlaneInfoContainer>
00229   PlaneReasoner::filterHorizontalPlanes(
00230     std::vector<PlaneInfoContainer>& infos)
00231   {
00232     return filterPlanesAroundAngle(
00233       0,
00234       horizontal_angular_threshold_,
00235       infos);
00236   }
00237   
00238   std::vector<PlaneInfoContainer>
00239   PlaneReasoner::filterVerticalPlanes(
00240     std::vector<PlaneInfoContainer>& infos)
00241   {
00242     return filterPlanesAroundAngle(
00243       M_PI / 2.0,
00244       vertical_angular_threshold_,
00245       infos);
00246   }
00247 
00248   std::vector<PlaneInfoContainer>
00249   PlaneReasoner::packInfo(
00250     std::vector<pcl::PointIndices::Ptr>& inliers,
00251     std::vector<pcl::ModelCoefficients::Ptr>& coefficients,
00252     std::vector<jsk_recognition_utils::Plane::Ptr>& planes,
00253     std::vector<geometry_msgs::PolygonStamped>& polygons)
00254   {
00255     std::vector<PlaneInfoContainer> ret;
00256     for (size_t i = 0; i < inliers.size(); i++) {
00257       ret.push_back(boost::make_tuple<pcl::PointIndices::Ptr,
00258                     pcl::ModelCoefficients::Ptr,
00259                     jsk_recognition_utils::Plane::Ptr>(inliers[i], coefficients[i],
00260                                 planes[i], polygons[i]));
00261     }
00262     return ret;
00263   }
00264 
00265   
00266 }
00267 
00268 #include <pluginlib/class_list_macros.h>
00269 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros_utils::PlaneReasoner, nodelet::Nodelet);