00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <ros/ros.h>
00019
00020
00021 #include <message_filters/subscriber.h>
00022 #include <message_filters/synchronizer.h>
00023 #include <message_filters/sync_policies/approximate_time.h>
00024
00025
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
00036 #include <opencv2/opencv.hpp>
00037
00038 #include <cv_bridge/cv_bridge.h>
00039
00040
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
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
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
00079 if (display_detection_image_ == true)
00080 {
00081
00082
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
00087
00088
00089
00090
00091 pointcloud_info_sub_ = node_handle_.subscribe("pointcloud_info", 1, &ObjectDetectionVisualizer::pointcloudInfoCallback, this);
00092 }
00093 }
00094
00095 ~ObjectDetectionVisualizer()
00096 {
00097
00098
00099
00100
00101 }
00102
00103 private:
00104
00105 void objectDetectionArrayCallback(const cob_object_detection_msgs::DetectionArray::ConstPtr& object_detection_msg)
00106 {
00107
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
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;
00158 marker_array_msg_.markers[idx].scale.y = 0.015;
00159 marker_array_msg_.markers[idx].scale.z = 0;
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
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
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
00255
00256
00257
00258
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
00286
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
00295
00296
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);
00308 std::vector<cv::Vec3d> corners_3d;
00309 for (int k=0; k<2; ++k)
00310 {
00311 int s = 1;
00312 for (int j=-1; j<2; j+=2)
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
00319 }
00320 s *= -1;
00321 }
00322 }
00323
00324
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
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
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
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
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
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
00413
00414
00415
00416
00417 ros::Subscriber pointcloud_info_sub_;
00418 ros::Subscriber pointcloud_sub_;
00419
00420 bool projection_matrix_received_;
00421 cv::Mat projection_matrix_;
00422
00423 boost::mutex color_image_mutex_;
00424 cv::Mat color_image_;
00425
00426 std::map<std::string, cv::Scalar> object_name_to_color_map_;
00427 int image_counter_;
00428
00429
00430 bool display_rviz_markers_;
00431 bool display_detection_image_;
00432 };
00433
00434
00435
00436
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
00449
00450 ros::spin();
00451
00452 return 0;
00453 }