object_detection_visualizer_node.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *   http://www.apache.org/licenses/LICENSE-2.0
00009 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016  
00017 
00018 #include <ros/ros.h>
00019 
00020 // topics
00021 #include <message_filters/subscriber.h>
00022 #include <message_filters/synchronizer.h>
00023 #include <message_filters/sync_policies/approximate_time.h>
00024 //#include <image_transport/image_transport.h>
00025 //#include <image_transport/subscriber_filter.h>
00026 
00027 #include <sensor_msgs/PointCloud2.h>
00028 #include <sensor_msgs/Image.h>
00029 #include <sensor_msgs/image_encodings.h>
00030 #include <sensor_msgs/CameraInfo.h>
00031 
00032 #include <visualization_msgs/Marker.h>
00033 #include <visualization_msgs/MarkerArray.h>
00034 
00035 // opencv
00036 #include <opencv2/opencv.hpp>
00037 
00038 #include <cv_bridge/cv_bridge.h>
00039 
00040 // PCL
00041 #include <pcl/point_cloud.h>
00042 #include <pcl/point_types.h>
00043 #include <pcl_ros/point_cloud.h>
00044 
00045 #include <eigen_conversions/eigen_msg.h>
00046 
00047 #include "cob_object_detection_msgs/DetectionArray.h"
00048 
00049 #include <map>
00050 #include <vector>
00051 #include <string>
00052 #include <sstream>
00053 
00054 
00055 class ObjectDetectionVisualizer
00056 {
00057 public:
00058         ObjectDetectionVisualizer(ros::NodeHandle& nh)
00059         : node_handle_(nh), prev_marker_array_size_(0), projection_matrix_received_(false), image_counter_(0)
00060         {
00061                 // parameters
00062                 ros::NodeHandle pnh("~");
00063                 std::cout << "\n========== ObjectDetectionVisualizer Parameters ==========\n";
00064                 pnh.param("display_rviz_markers", display_rviz_markers_, true);
00065                 std::cout << "display_rviz_markers: " << display_rviz_markers_ << std::endl;
00066                 pnh.param("display_detection_image", display_detection_image_, true);
00067                 std::cout << "display_detection_image: " << display_detection_image_ << std::endl;
00068 
00069                 projection_matrix_ = cv::Mat::eye(3, 3, CV_64FC1);
00070 
00071                 // Rviz visualization
00072                 if (display_rviz_markers_ == true)
00073                 {
00074                         detection_array_sub_ = node_handle_.subscribe("detection_array_topic", 1, &ObjectDetectionVisualizer::objectDetectionArrayCallback, this);
00075                         marker_array_publisher_ = node_handle_.advertise<visualization_msgs::MarkerArray>("object_detection_marker_array", 0);
00076                 }
00077 
00078                 // detection image visualization
00079                 if (display_detection_image_ == true)
00080                 {
00081 //                      it_ = new image_transport::ImageTransport(node_handle_);
00082 //                      color_image_sub_.subscribe(*it_, "color_image", 1);
00083                         pointcloud_sub_ = node_handle_.subscribe("pointcloud", 1, &ObjectDetectionVisualizer::pointcloudCallback, this);
00084                         detection_array_sub_ = node_handle_.subscribe("detection_array_topic", 1, &ObjectDetectionVisualizer::objectDetectionDisplayCallback, this);
00085 
00086 //                      sync_detection_array_sub_.subscribe(node_handle_, "detection_array_topic", 1);
00087 //                      sync_input_ = new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_object_detection_msgs::DetectionArray, sensor_msgs::PointCloud2> >(2);
00088 //                      sync_input_->connectInput(sync_detection_array_sub_, pointcloud_sub_);
00089 //                      sync_input_->registerCallback(boost::bind(&ObjectDetectionVisualizer::detectionImageCallback, this, _1, _2));
00090 
00091                         pointcloud_info_sub_ = node_handle_.subscribe("pointcloud_info", 1, &ObjectDetectionVisualizer::pointcloudInfoCallback, this);
00092                 }
00093         }
00094 
00095         ~ObjectDetectionVisualizer()
00096         {
00097 //              if (it_ != NULL)
00098 //                      delete it_;
00099 //              if (sync_input_ != NULL)
00100 //                      delete sync_input_;
00101         }
00102 
00103 private:
00104 
00105         void objectDetectionArrayCallback(const cob_object_detection_msgs::DetectionArray::ConstPtr& object_detection_msg)
00106         {
00107                 // 3 arrows for each coordinate system of each detected fiducial
00108                 const unsigned int detection_array_size = object_detection_msg->detections.size();
00109                 const unsigned int markers_per_detection = 3+1;
00110                 const unsigned int marker_array_size = markers_per_detection * detection_array_size;
00111                 if (marker_array_size >= prev_marker_array_size_) {
00112                         marker_array_msg_.markers.resize(marker_array_size);
00113                 }
00114 
00115                 // publish a coordinate system from arrow markers for each object
00116                 for (unsigned int i = 0; i < detection_array_size; ++i)
00117                 {
00118                         for (unsigned int j = 0; j < 3; ++j)
00119                         {
00120                                 unsigned int idx = markers_per_detection * i + j;
00121                                 marker_array_msg_.markers[idx].header = object_detection_msg->header;
00122                                 marker_array_msg_.markers[idx].ns = "object_detection";
00123                                 marker_array_msg_.markers[idx].id = idx;
00124                                 marker_array_msg_.markers[idx].type = visualization_msgs::Marker::ARROW;
00125                                 marker_array_msg_.markers[idx].action = visualization_msgs::Marker::ADD;
00126                                 marker_array_msg_.markers[idx].color.a = 0.85;
00127                                 marker_array_msg_.markers[idx].color.r = 0;
00128                                 marker_array_msg_.markers[idx].color.g = 0;
00129                                 marker_array_msg_.markers[idx].color.b = 0;
00130 
00131                                 marker_array_msg_.markers[idx].points.resize(2);
00132                                 marker_array_msg_.markers[idx].points[0].x = 0.0;
00133                                 marker_array_msg_.markers[idx].points[0].y = 0.0;
00134                                 marker_array_msg_.markers[idx].points[0].z = 0.0;
00135                                 marker_array_msg_.markers[idx].points[1].x = 0.0;
00136                                 marker_array_msg_.markers[idx].points[1].y = 0.0;
00137                                 marker_array_msg_.markers[idx].points[1].z = 0.0;
00138                                 if (j == 0)
00139                                 {
00140                                         marker_array_msg_.markers[idx].points[1].x = 0.2;
00141                                         marker_array_msg_.markers[idx].color.r = 255;
00142                                 }
00143                                 else if (j == 1)
00144                                 {
00145                                         marker_array_msg_.markers[idx].points[1].y = 0.2;
00146                                         marker_array_msg_.markers[idx].color.g = 255;
00147                                 }
00148                                 else if (j == 2)
00149                                 {
00150                                         marker_array_msg_.markers[idx].points[1].z = 0.2;
00151                                         marker_array_msg_.markers[idx].color.b = 255;
00152                                 }
00153 
00154                                 marker_array_msg_.markers[idx].pose = object_detection_msg->detections[i].pose.pose;
00155 
00156                                 marker_array_msg_.markers[idx].lifetime = ros::Duration(2);
00157                                 marker_array_msg_.markers[idx].scale.x = 0.01; // shaft diameter
00158                                 marker_array_msg_.markers[idx].scale.y = 0.015; // head diameter
00159                                 marker_array_msg_.markers[idx].scale.z = 0; // head length 0=default
00160                         }
00161                         for (unsigned int j = 3; j < 4; ++j)
00162                         {
00163                                 unsigned int idx = markers_per_detection * i + j;
00164                                 marker_array_msg_.markers[idx].header = object_detection_msg->header;
00165                                 marker_array_msg_.markers[idx].ns = "object_detection";
00166                                 marker_array_msg_.markers[idx].id = idx;
00167                                 marker_array_msg_.markers[idx].type = visualization_msgs::Marker::CUBE;
00168                                 marker_array_msg_.markers[idx].action = visualization_msgs::Marker::ADD;
00169                                 marker_array_msg_.markers[idx].color.a = 0.25;
00170                                 marker_array_msg_.markers[idx].color.r = 128;
00171                                 marker_array_msg_.markers[idx].color.g = 128;
00172                                 marker_array_msg_.markers[idx].color.b = 128;
00173 
00174                                 marker_array_msg_.markers[idx].pose = object_detection_msg->detections[i].pose.pose;
00175 
00176                                 marker_array_msg_.markers[idx].lifetime = ros::Duration(2);
00177                                 marker_array_msg_.markers[idx].scale.x = object_detection_msg->detections[i].bounding_box_lwh.x;
00178                                 marker_array_msg_.markers[idx].scale.y = object_detection_msg->detections[i].bounding_box_lwh.y;
00179                                 marker_array_msg_.markers[idx].scale.z = object_detection_msg->detections[i].bounding_box_lwh.z;
00180                         }
00181 
00182                         if (prev_marker_array_size_ > marker_array_size)
00183                                 for (unsigned int i = marker_array_size; i < prev_marker_array_size_; ++i)
00184                                         marker_array_msg_.markers[i].action = visualization_msgs::Marker::DELETE;
00185                         prev_marker_array_size_ = marker_array_size;
00186 
00187                         marker_array_publisher_.publish(marker_array_msg_);
00188                 }
00189         }
00190 
00191         bool convertImageMessageToMat(const sensor_msgs::Image::ConstPtr& image_msg, cv_bridge::CvImageConstPtr& image_ptr, cv::Mat& image)
00192         {
00193                 try
00194                 {
00195                         image_ptr = cv_bridge::toCvShare(image_msg, image_msg->encoding);
00196                 }
00197                 catch (cv_bridge::Exception& e)
00198                 {
00199                         ROS_ERROR("ObjectDetectionVisualizer::convertColorImageMessageToMat: cv_bridge exception: %s", e.what());
00200                         return false;
00201                 }
00202                 image = image_ptr->image;
00203 
00204                 return true;
00205         }
00206 
00207         bool convertPclMessageToMat(const sensor_msgs::PointCloud2::ConstPtr& pointcloud_msg, pcl::PointCloud<pcl::PointXYZRGB>& pointcloud, cv::Mat& color_image)
00208         {
00209                 pcl::fromROSMsg(*pointcloud_msg, pointcloud);
00210                 color_image.create(pointcloud.height, pointcloud.width, CV_8UC3);
00211                 for (int v = 0; v < (int)pointcloud.height; v++)
00212                 {
00213                         for (int u = 0; u < (int)pointcloud.width; u++)
00214                         {
00215                                 const pcl::PointXYZRGB& point = pointcloud(u, v);
00216                                 color_image.at<cv::Vec3b>(v,u) = cv::Vec3b(point.b, point.g, point.r);
00217                         }
00218                 }
00219                 return true;
00220         }
00221 
00222         void pointcloudCallback(const sensor_msgs::PointCloud2::ConstPtr& pointcloud_msg)
00223         {
00224                 // secure this access with a mutex
00225                 boost::mutex::scoped_lock lock(color_image_mutex_);
00226 
00227                 pcl::PointCloud<pcl::PointXYZRGB> pointcloud;
00228                 convertPclMessageToMat(pointcloud_msg, pointcloud, color_image_);
00229         }
00230 
00231         void objectDetectionDisplayCallback(const cob_object_detection_msgs::DetectionArray::ConstPtr& object_detection_msg)
00232         {
00233                 cv::Mat image;
00234                 {
00235                         // secure this access with a mutex
00236                         boost::mutex::scoped_lock lock(color_image_mutex_);
00237                         image = color_image_.clone();
00238                 }
00239                 renderDetections(image, object_detection_msg);
00240 
00241                 cv::Mat display;
00242                 cv::resize(image, display, cv::Size(), 0.5, 0.5);
00243                 cv::imshow("object detections", display);
00244                 cv::waitKey(50);
00245 
00246                 std::stringstream file;
00247                 file << "object_detection_visualizer/" << image_counter_ << ".png";
00248                 cv::imwrite(file.str().c_str(), image);
00249                 image_counter_++;
00250         }
00251 
00252         void detectionImageCallback(const cob_object_detection_msgs::DetectionArray::ConstPtr& object_detection_msg, const sensor_msgs::PointCloud2::ConstPtr& pointcloud_msg)
00253         {
00254 //              // read image
00255 //              cv_bridge::CvImageConstPtr color_image_ptr;
00256 //              cv::Mat color_image;
00257 //              if (convertImageMessageToMat(image_msg, color_image_ptr, color_image) == false)
00258 //                      return;
00259 
00260                 cv::Mat image;
00261                 pcl::PointCloud<pcl::PointXYZRGB> pointcloud;
00262                 convertPclMessageToMat(pointcloud_msg, pointcloud, image);
00263 
00264                 renderDetections(image, object_detection_msg);
00265 
00266                 cv::Mat display;
00267                 cv::resize(image, display, cv::Size(), 0.5, 0.5);
00268                 cv::imshow("object detections", display);
00269                 cv::waitKey(50);
00270 
00271                 std::stringstream file;
00272                 file << "object_detection_visualizer/" << image_counter_ << ".png";
00273                 cv::imwrite(file.str().c_str(), image);
00274                 image_counter_++;
00275         }
00276 
00277         bool renderDetections(cv::Mat& image, const cob_object_detection_msgs::DetectionArray::ConstPtr& object_detection_msg)
00278         {
00279                 if (projection_matrix_received_ == false)
00280                 {
00281                         ROS_WARN("Did not receive a projection matrix yet.");
00282                         return false;
00283                 }
00284 
00285                 // render 3-D detection results
00286                 // project bounding box of the object on the image
00287                 if (object_detection_msg->detections.size() <= 0)
00288                         return false;
00289 
00290                 for (size_t o=0; o<object_detection_msg->detections.size(); ++o)
00291                 {
00292                         const cob_object_detection_msgs::Detection& detection = object_detection_msg->detections[o];
00293 
00294                         // compute 8 corner points of bounding box and transform them into the camera coordinate system
00295                         // reproduce 8 points in a special order (simplifies drawing a box):
00296                         // x y z
00297                         // - - -
00298                         // + - -
00299                         // + + -
00300                         // - + -
00301                         // - - +
00302                         // + - +
00303                         // + + +
00304                         // - + +
00305                         std::cout << "New box corners for object " << detection.label << ": \n";
00306                         Eigen::Affine3d pose;
00307                         tf::poseMsgToEigen(detection.pose.pose, pose);  // i.e. p = the transform pointing from camera to object coordinate system
00308                         std::vector<cv::Vec3d> corners_3d;
00309                         for (int k=0; k<2; ++k) // z is given in full length, the object center is at the bottom
00310                         {
00311                                 int s = 1;
00312                                 for (int j=-1; j<2; j+=2)       // x and y are only provided in half side lengths, center is in the object center
00313                                 {
00314                                         for (int i=-1; i<2; i+=2)
00315                                         {
00316                                                 Eigen::Affine3d corner = pose * Eigen::Translation3d(i*s*detection.bounding_box_lwh.x, j*detection.bounding_box_lwh.y, k*detection.bounding_box_lwh.z);
00317                                                 corners_3d.push_back(cv::Vec3d(corner.translation()(0), corner.translation()(1), corner.translation()(2)));
00318                                                 //std::cout << " > " << corner.translation()(0) << ", " << corner.translation()(1) << ", " << corner.translation()(2) << std::endl;
00319                                         }
00320                                         s *= -1;
00321                                 }
00322                         }
00323 
00324                         // project xyz coordinates to image coordinates
00325                         std::vector<cv::Point> corners_2d(corners_3d.size());
00326                         for (size_t i=0; i<corners_3d.size(); ++i)
00327                                 corners_2d[i] = projectPoint(corners_3d[i]);
00328 
00329                         // draw all detected bounding boxes
00330                         if (object_name_to_color_map_.find(detection.label) == object_name_to_color_map_.end())
00331                                 object_name_to_color_map_[detection.label] = CV_RGB(rand()%256,rand()%256,rand()%256);
00332                         if (drawDetectedModel3D(image, corners_2d, object_name_to_color_map_[detection.label]) == false )
00333                         {
00334                                 ROS_ERROR("Unable to draw detected bounding boxes!");
00335                                 return false;
00336                         }
00337 
00338                         // annotate bounding box with object name
00339                         cv::Point center_top;
00340                         for (int i=4; i<8; ++i)
00341                                 center_top += corners_2d[i];
00342                         center_top *= 0.25;
00343                         cv::putText(image, detection.label, center_top, cv::FONT_HERSHEY_SIMPLEX, 0.75, object_name_to_color_map_[detection.label], 2);
00344                 }
00345 
00346                 return true;
00347         }
00348 
00349         cv::Point projectPoint(const cv::Vec3d& point_3d)
00350         {
00351                 if (projection_matrix_received_ == false)
00352                 {
00353                         ROS_WARN("Did not receive a projection matrix yet.");
00354                         return cv::Point();
00355                 }
00356                 cv::Mat uvw = projection_matrix_ * cv::Mat(point_3d);
00357                 return cv::Point(uvw.at<double>(0,0)/uvw.at<double>(2,0), uvw.at<double>(1,0)/uvw.at<double>(2,0));
00358         }
00359 
00360         bool drawDetectedModel3D(cv::Mat image, const std::vector<cv::Point>& corners_2d, const cv::Scalar& color)
00361         {
00362                 // Draw lower rectangle of bounding box
00363                 for (unsigned int j=0; j<3; ++j)
00364                 {
00365                         cv::line(image, corners_2d[j], corners_2d[j+1], color, 3);
00366                 }
00367                 cv::line(image, corners_2d[3], corners_2d[0], color, 3);
00368 
00369                 // Draw upper rectangle of bounding box
00370                 for (unsigned int j=4; j<corners_2d.size()-1; j++)
00371                 {
00372                         cv::line(image, corners_2d[j], corners_2d[j+1], color, 3);
00373                 }
00374                 cv::line(image, corners_2d[7], corners_2d[4], color, 3);
00375 
00376                 // Draw side lines of bounding box
00377                 for (unsigned int j=0; j<4; j++)
00378                 {
00379                         cv::line(image, corners_2d[j], corners_2d[j+4], color, 3);
00380                 }
00381 
00382                 return true;
00383         }
00384 
00385         void pointcloudInfoCallback(const sensor_msgs::CameraInfoConstPtr &data)
00386         {
00387                 double* f_ptr = projection_matrix_.ptr<double>(0);
00388                 for (int i = 0; i < 9; i++)
00389                         f_ptr[i] = data->K[i];
00390 
00391                 ROS_INFO("[object_detection_visualizer] Received new projection matrix:");
00392                 std::cout << "\t... / " << std::setw(8) <<  projection_matrix_.at<double>(0, 0) << " ";
00393                 std::cout << std::setw(8) << projection_matrix_.at<double>(0, 1) << " ";
00394                 std::cout << std::setw(8) << projection_matrix_.at<double>(0, 2) << " \\ " << std::endl;
00395                 std::cout << "\t... | " << std::setw(8) << projection_matrix_.at<double>(1, 0) << " ";
00396                 std::cout << std::setw(8) << projection_matrix_.at<double>(1, 1) << " ";
00397                 std::cout << std::setw(8) << projection_matrix_.at<double>(1, 2) << " | "<< std::endl;;
00398                 std::cout << "\t... \\ " << std::setw(8) << projection_matrix_.at<double>(2, 0) << " ";
00399                 std::cout << std::setw(8) << projection_matrix_.at<double>(2, 1) << " ";
00400                 std::cout << std::setw(8) << projection_matrix_.at<double>(2, 2) << " / "<< std::endl << std::endl;
00401 
00402                 projection_matrix_received_ = true;
00403                 pointcloud_info_sub_.shutdown();
00404         }
00405 
00406         ros::NodeHandle node_handle_;
00407         ros::Subscriber detection_array_sub_;
00408         ros::Publisher marker_array_publisher_;
00409         unsigned int prev_marker_array_size_;
00410         visualization_msgs::MarkerArray marker_array_msg_;
00411 
00412 //      image_transport::ImageTransport* it_;
00413 //      image_transport::SubscriberFilter color_image_sub_; ///< color camera image topic
00414 //      message_filters::Subscriber<sensor_msgs::PointCloud2> pointcloud_sub_; ///< receives the detection messages
00415 //      message_filters::Subscriber<cob_object_detection_msgs::DetectionArray> sync_detection_array_sub_; ///< receives the detection messages
00416 //      message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_object_detection_msgs::DetectionArray, sensor_msgs::PointCloud2> >* sync_input_;
00417         ros::Subscriber pointcloud_info_sub_;
00418         ros::Subscriber pointcloud_sub_;
00419 
00420         bool projection_matrix_received_;
00421         cv::Mat projection_matrix_;             // 3x3 intrinsic matrix
00422 
00423         boost::mutex color_image_mutex_; // secures read and write operations on camera data
00424         cv::Mat color_image_;
00425 
00426         std::map<std::string, cv::Scalar> object_name_to_color_map_;
00427         int image_counter_;
00428 
00429         // parameters
00430         bool display_rviz_markers_;
00431         bool display_detection_image_;
00432 };
00433 
00434 
00435 //#######################
00436 //#### main programm ####
00437 int main(int argc, char** argv)
00438 {
00440         ros::init(argc, argv, "object_detection_visualizer");
00441 
00443         ros::NodeHandle nh;
00444 
00446         ObjectDetectionVisualizer odv(nh);
00447 
00448 //      ros::MultiThreadedSpinner spinner(2); // Use 4 threads
00449 //      spinner.spin();
00450         ros::spin();
00451 
00452         return 0;
00453 }


cob_object_detection_visualizer
Author(s): Richard Bormann
autogenerated on Fri Mar 15 2019 03:10:11