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/organized_edge_detector.h"
00037 #include "jsk_recognition_utils/pcl_conversion_util.h"
00038
00039 #include <pcl/features/organized_edge_detection.h>
00040 #include <pcl/features/integral_image_normal.h>
00041 #include "jsk_recognition_utils/pcl_util.h"
00042 #include <cv_bridge/cv_bridge.h>
00043 #include <sensor_msgs/image_encodings.h>
00044 #include <std_msgs/ColorRGBA.h>
00045 #include <jsk_topic_tools/color_utils.h>
00046
00047 #include <opencv2/opencv.hpp>
00048 #include <jsk_recognition_msgs/ClusterPointIndices.h>
00049
00050 namespace jsk_pcl_ros
00051 {
00052 void OrganizedEdgeDetector::onInit()
00053 {
00054 ConnectionBasedNodelet::onInit();
00055
00057
00059 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00060 dynamic_reconfigure::Server<Config>::CallbackType f =
00061 boost::bind (&OrganizedEdgeDetector::configCallback, this, _1, _2);
00062 srv_->setCallback (f);
00064
00066 pub_nan_boundary_edges_indices_
00067 = advertise<PCLIndicesMsg>(*pnh_, "output_nan_boundary_edge_indices", 1);
00068 pub_occluding_edges_indices_
00069 = advertise<PCLIndicesMsg>(*pnh_, "output_occluding_edge_indices", 1);
00070 pub_occluded_edges_indices_
00071 = advertise<PCLIndicesMsg>(*pnh_, "output_occluded_edge_indices", 1);
00072 pub_curvature_edges_indices_
00073 = advertise<PCLIndicesMsg>(*pnh_, "output_curvature_edge_indices", 1);
00074 pub_rgb_edges_indices_
00075 = advertise<PCLIndicesMsg>(*pnh_, "output_rgb_edge_indices", 1);
00076 pub_all_edges_indices_
00077 = advertise<PCLIndicesMsg>(*pnh_, "output_indices", 1);
00078 pub_straight_edges_indices_
00079 = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_,
00080 "output_straight_edges_indices", 1);
00082
00084 pub_normal_ = advertise<sensor_msgs::PointCloud2>(*pnh_, "output_normal", 1);
00085 pub_nan_boundary_edges_
00086 = advertise<sensor_msgs::PointCloud2>(*pnh_, "output_nan_boundary_edge", 1);
00087 pub_occluding_edges_
00088 = advertise<sensor_msgs::PointCloud2>(*pnh_, "output_occluding_edge", 1);
00089 pub_occluded_edges_
00090 = advertise<sensor_msgs::PointCloud2>(*pnh_, "output_occluded_edge", 1);
00091 pub_curvature_edges_
00092 = advertise<sensor_msgs::PointCloud2>(*pnh_, "output_curvature_edge", 1);
00093 pub_rgb_edges_
00094 = advertise<sensor_msgs::PointCloud2>(*pnh_, "output_rgb_edge", 1);
00095 pub_all_edges_
00096 = advertise<sensor_msgs::PointCloud2>(*pnh_, "output", 1);
00098
00100 image_transport::ImageTransport it(*pnh_);
00101 pub_edge_image_ = it.advertise("edge_image", 1);
00102 pub_hough_image_ = it.advertise("hough_image", 1);
00103 onInitPostProcess();
00104 }
00105
00106 void OrganizedEdgeDetector::subscribe()
00107 {
00108 sub_ = pnh_->subscribe("input", 1, &OrganizedEdgeDetector::estimate, this);
00109 }
00110
00111 void OrganizedEdgeDetector::unsubscribe()
00112 {
00113 sub_.shutdown();
00114 }
00115
00116 void OrganizedEdgeDetector::estimateNormal(
00117 const pcl::PointCloud<PointT>::Ptr& input,
00118 pcl::PointCloud<pcl::Normal>::Ptr output,
00119 const std_msgs::Header& header)
00120 {
00121 pcl::IntegralImageNormalEstimation<PointT, pcl::Normal> ne;
00122 if (estimation_method_ == 0) {
00123 ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
00124 }
00125 else if (estimation_method_ == 1) {
00126 ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);
00127 }
00128 else if (estimation_method_ == 2) {
00129 ne.setNormalEstimationMethod (ne.AVERAGE_DEPTH_CHANGE);
00130 }
00131 else {
00132 NODELET_FATAL("unknown estimation method: %d", estimation_method_);
00133 return;
00134 }
00135
00136 if (border_policy_ignore_) {
00137 ne.setBorderPolicy(pcl::IntegralImageNormalEstimation<PointT, pcl::Normal>::BORDER_POLICY_IGNORE);
00138 }
00139 else {
00140 ne.setBorderPolicy(pcl::IntegralImageNormalEstimation<PointT, pcl::Normal>::BORDER_POLICY_MIRROR);
00141 }
00142
00143 ne.setMaxDepthChangeFactor(max_depth_change_factor_);
00144 ne.setNormalSmoothingSize(normal_smoothing_size_);
00145 ne.setDepthDependentSmoothing(depth_dependent_smoothing_);
00146 ne.setInputCloud(input);
00147 ne.compute(*output);
00148 if (publish_normal_) {
00149 sensor_msgs::PointCloud2 ros_output;
00150 pcl::toROSMsg(*output, ros_output);
00151 ros_output.header = header;
00152 pub_normal_.publish(ros_output);
00153 }
00154 }
00155
00156 void OrganizedEdgeDetector::configCallback (Config &config, uint32_t level)
00157 {
00158 boost::mutex::scoped_lock lock(mutex_);
00159 max_depth_change_factor_ = config.max_depth_change_factor;
00160 normal_smoothing_size_ = config.normal_smoothing_size;
00161 depth_dependent_smoothing_ = config.depth_dependent_smoothing;
00162 estimation_method_ = config.estimation_method;
00163 border_policy_ignore_ = config.border_policy_ignore;
00164 max_search_neighbors_ = config.max_search_neighbors;
00165 depth_discontinuation_threshold_ = config.depth_discontinuation_threshold;
00166 publish_normal_ = config.publish_normal;
00167 use_nan_boundary_ = config.use_nan_boundary;
00168 use_occluding_ = config.use_occluding;
00169 use_occluded_ = config.use_occluded;
00170 use_curvature_ = config.use_curvature;
00171 use_rgb_ = config.use_rgb;
00172 use_straightline_detection_ = config.use_straightline_detection;
00173 rho_ = config.rho;
00174 theta_ = config.theta;
00175 straightline_threshold_ = config.straightline_threshold;
00176 min_line_length_ = config.min_line_length;
00177 max_line_gap_ = config.max_line_gap;
00178 publish_debug_image_ = config.publish_debug_image;
00179 }
00180
00181 void OrganizedEdgeDetector::estimateEdge(
00182 const pcl::PointCloud<PointT>::Ptr& input,
00183 const pcl::PointCloud<pcl::Normal>::Ptr& normal,
00184 pcl::PointCloud<pcl::Label>::Ptr& output,
00185 std::vector<pcl::PointIndices>& label_indices)
00186 {
00187 pcl::OrganizedEdgeFromRGBNormals<PointT, pcl::Normal, pcl::Label> oed;
00188 oed.setDepthDisconThreshold (depth_discontinuation_threshold_);
00189 oed.setMaxSearchNeighbors (max_search_neighbors_);
00190 int flags = 0;
00191 if (use_nan_boundary_) {
00192 flags |= oed.EDGELABEL_NAN_BOUNDARY;
00193 }
00194 if (use_occluding_) {
00195 flags |= oed.EDGELABEL_OCCLUDING;
00196 }
00197 if (use_occluded_) {
00198 flags |= oed.EDGELABEL_OCCLUDED;
00199 }
00200 if (use_curvature_) {
00201 flags |= oed.EDGELABEL_HIGH_CURVATURE;
00202 }
00203 if (use_rgb_) {
00204 flags |= oed.EDGELABEL_RGB_CANNY;
00205 }
00206 oed.setEdgeType (flags);
00207 oed.setInputNormals(normal);
00208 oed.setInputCloud(input);
00209 oed.compute(*output, label_indices);
00210 }
00211
00212 void OrganizedEdgeDetector::publishIndices(
00213 ros::Publisher& pub,
00214 ros::Publisher& pub_indices,
00215 const pcl::PointCloud<PointT>::Ptr& cloud,
00216 const std::vector<int>& indices,
00217 const std_msgs::Header& header)
00218 {
00220
00222 PCLIndicesMsg msg;
00223 msg.header = header;
00224 msg.indices = indices;
00225 pub_indices.publish(msg);
00226
00228
00230 pcl::PointCloud<PointT>::Ptr output(new pcl::PointCloud<PointT>);
00231 pcl::copyPointCloud(*cloud, indices, *output);
00232 sensor_msgs::PointCloud2 ros_output;
00233 pcl::toROSMsg(*output, ros_output);
00234 ros_output.header = header;
00235 pub.publish(ros_output);
00236 }
00237
00238 void OrganizedEdgeDetector::publishStraightEdges(
00239 const pcl::PointCloud<PointT>::Ptr& cloud,
00240 const std_msgs::Header& header,
00241 const std::vector<std::vector<int> > indices)
00242 {
00243
00244 jsk_recognition_msgs::ClusterPointIndices ros_msg;
00245 ros_msg.header = header;
00246 ros_msg.cluster_indices.resize(indices.size());
00247 for (size_t i = 0; i < indices.size(); i++) {
00248 PCLIndicesMsg ros_indices;
00249 ros_indices.header = header;
00250 ros_indices.indices = indices[i];
00251 ros_msg.cluster_indices[i] = ros_indices;
00252 }
00253 pub_straight_edges_indices_.publish(ros_msg);
00254 }
00255
00256 void OrganizedEdgeDetector::estimateStraightEdges(
00257 const pcl::PointCloud<PointT>::Ptr& cloud,
00258 const std::vector<int>& indices,
00259 const std_msgs::Header& header,
00260 std::vector<std::vector<int> >& output_indices)
00261 {
00262
00263 cv::Mat mat = cv::Mat(cloud->height, cloud->width, CV_8UC1) * 0;
00264 for (size_t i = 0; i < indices.size(); i++) {
00265 int index = indices[i];
00266 int index_height = index / cloud->width;
00267 int index_width = index % cloud->width;
00268 mat.data[index_height * mat.step + index_width * mat.elemSize()] = 255;
00269 }
00270
00271 std::vector<cv::Vec4i> lines;
00272 cv::HoughLinesP(mat, lines, rho_, theta_ * CV_PI/180,
00273 straightline_threshold_, min_line_length_, max_line_gap_);
00274 output_indices.resize(lines.size());
00275 std::set<int> all_indices_set(indices.begin(), indices.end());
00276 for (size_t i_line = 0; i_line < lines.size(); i_line++) {
00277 std::vector<int> pixels;
00278 cv::LineIterator it(mat,
00279 cv::Point(lines[i_line][0], lines[i_line][1]),
00280 cv::Point(lines[i_line][2], lines[i_line][3]), 4);
00281 for(int i_pixel = 0; i_pixel < it.count; i_pixel++, ++it) {
00282 cv::Point point = it.pos();
00283 int flatten_index = point.x + point.y * cloud->width;
00284
00285 if (all_indices_set.find(flatten_index) != all_indices_set.end()) {
00286 pixels.push_back(flatten_index);
00287 }
00288 }
00289 output_indices[i_line] = pixels;
00290 }
00291 if (publish_debug_image_) {
00292 cv::Mat color_dst;
00293 cv::cvtColor(mat, color_dst, CV_GRAY2BGR );
00294 for( size_t i = 0; i < lines.size(); i++ )
00295 {
00296 std_msgs::ColorRGBA c = jsk_topic_tools::colorCategory20(i);
00297 cv::line(color_dst,
00298 cv::Point(lines[i][0], lines[i][1]),
00299 cv::Point(lines[i][2], lines[i][3]),
00300 cv::Scalar((uint8_t)(c.b * 255), (uint8_t)(c.g * 255), (uint8_t)(c.r * 255)), 3, 8);
00301 }
00302 sensor_msgs::Image::Ptr ros_edge_image
00303 = cv_bridge::CvImage(header,
00304 sensor_msgs::image_encodings::MONO8,
00305 mat).toImageMsg();
00306 pub_edge_image_.publish(ros_edge_image);
00307 sensor_msgs::Image::Ptr ros_hough_image
00308 = cv_bridge::CvImage(header,
00309 sensor_msgs::image_encodings::BGR8,
00310 color_dst).toImageMsg();
00311 pub_hough_image_.publish(ros_hough_image);
00312 }
00313 }
00314
00315 void OrganizedEdgeDetector::estimate(
00316 const sensor_msgs::PointCloud2::ConstPtr& msg)
00317 {
00318 boost::mutex::scoped_lock lock(mutex_);
00319 if (msg->height == 1) {
00320 NODELET_ERROR("[OrganizedEdgeDetector] organized pointcloud is required");
00321 return;
00322 }
00323 pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
00324 pcl::PointCloud<pcl::Normal>::Ptr normal(new pcl::PointCloud<pcl::Normal>);
00325 pcl::PointCloud<pcl::Label>::Ptr label(new pcl::PointCloud<pcl::Label>);
00326 std::vector<pcl::PointIndices> label_indices;
00327 pcl::fromROSMsg(*msg, *cloud);
00328
00329 estimateNormal(cloud, normal, msg->header);
00330 estimateEdge(cloud, normal, label, label_indices);
00332
00334 std::vector<int> tmp1 = jsk_recognition_utils::addIndices(label_indices[0].indices,
00335 label_indices[1].indices);
00336 std::vector<int> tmp2 = jsk_recognition_utils::addIndices(tmp1,
00337 label_indices[2].indices);
00338 std::vector<int> tmp3 = jsk_recognition_utils::addIndices(tmp2,
00339 label_indices[3].indices);
00340 std::vector<int> all = jsk_recognition_utils::addIndices(tmp3,
00341 label_indices[4].indices);
00342 if (use_straightline_detection_) {
00343 std::vector<std::vector<int> > straightline_indices;
00344 estimateStraightEdges(cloud, all, msg->header, straightline_indices);
00345
00346 publishStraightEdges(cloud, msg->header, straightline_indices);
00347 }
00349
00351 publishIndices(pub_nan_boundary_edges_, pub_nan_boundary_edges_indices_,
00352 cloud,
00353 label_indices[0].indices, msg->header);
00354 publishIndices(pub_occluding_edges_, pub_occluding_edges_indices_,
00355 cloud,
00356 label_indices[1].indices, msg->header);
00357 publishIndices(pub_occluded_edges_, pub_occluded_edges_indices_,
00358 cloud,
00359 label_indices[2].indices, msg->header);
00360 publishIndices(pub_curvature_edges_, pub_curvature_edges_indices_,
00361 cloud,
00362 label_indices[3].indices, msg->header);
00363 publishIndices(pub_rgb_edges_, pub_rgb_edges_indices_,
00364 cloud,
00365 label_indices[4].indices, msg->header);
00366 publishIndices(pub_all_edges_, pub_all_edges_indices_,
00367 cloud,
00368 all, msg->header);
00369 }
00370 }
00371
00372 #include <pluginlib/class_list_macros.h>
00373 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::OrganizedEdgeDetector, nodelet::Nodelet);