rgbd
get_3d_point_from_image_roi_node.cpp
Go to the documentation of this file.
1 #include <geolib/datatypes.h>
3 
4 #include <opencv2/core/mat.hpp>
5 #include <opencv2/core/types.hpp>
6 
7 #include <rgbd/view.h>
8 #include <rgbd/client.h>
9 
10 #include <rgbd_msgs/Project2DTo3D.h>
11 
12 #include <ros/console.h>
13 #include <ros/duration.h>
14 #include <ros/init.h>
15 #include <ros/master.h>
16 #include <ros/names.h>
17 #include <ros/node_handle.h>
18 #include <ros/service_client.h>
19 #include <ros/time.h>
20 
21 #include <sensor_msgs/RegionOfInterest.h>
22 
23 #include <memory>
24 
25 #include <boost/circular_buffer.hpp>
26 
27 // ----------------------------------------------------------------------------------------------------
28 
29 boost::circular_buffer<std::shared_ptr<rgbd::Image> > g_last_images_;
30 bool srvGet3dPointFromROI(rgbd_msgs::Project2DTo3D::Request& req, rgbd_msgs::Project2DTo3D::Response& res)
31 {
33 
34  if (!g_last_images_.empty())
35  {
36  if (req.stamp == ros::Time(0))
37  last_image = g_last_images_.back();
38  else
39  {
40  for (auto it = g_last_images_.rbegin(); it != g_last_images_.rend(); ++it)
41  {
42  if ( (*it)->getTimestamp() <= req.stamp.toSec())
43  last_image = *it;
44  }
45  }
46  }
47 
48  if (!last_image)
49  {
50  ROS_ERROR("I could not find an images in my image buffer for timestamp %.2f", req.stamp.toSec());
51  return false;
52  }
53 
54  for (const sensor_msgs::RegionOfInterest& roi : req.rois)
55  {
56  const cv::Mat& depth = last_image->getDepthImage();
57 
58  cv::Rect roi_rgb(static_cast<int>(roi.x_offset), static_cast<int>(roi.y_offset),
59  static_cast<int>(roi.width), static_cast<int>(roi.height));
60  float rgb_depth_width_ratio = static_cast<float>(depth.cols) / static_cast<float>(last_image->getRGBImage().cols);
61  cv::Rect roi_depth(rgb_depth_width_ratio * roi_rgb.tl(), rgb_depth_width_ratio * roi_rgb.br());
62  cv::Point roi_depth_center = 0.5 * (roi_depth.tl() + roi_depth.br());
63 
64  cv::Rect roi_depth_capped(cv::Point(std::max(0, roi_depth.x),
65  std::max(0, roi_depth.y)),
66  cv::Point(std::min(depth.cols - 1, roi_depth.br().x),
67  std::min(depth.rows - 1, roi_depth.br().y)));
68 
69  cv::Mat depth_roi_capped = depth(roi_depth_capped);
70 
71  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
72  // Get median depth of ROI
73 
74  std::vector<float> depths;
75  for (int j = 0; j < depth_roi_capped.cols * depth_roi_capped.rows; ++j)
76  {
77  float d = depth_roi_capped.at<float>(j);
78  if (d > 0 && d == d) // filters NaN
79  depths.push_back(d);
80  }
81 
82  geometry_msgs::PointStamped point_msg;
83  point_msg.header.frame_id = last_image->getFrameId();
84  point_msg.header.stamp.fromSec(last_image->getTimestamp());
85  if (depths.empty())
86  {
87  ROS_ERROR("All depths within ROI are invalid! We will send a NAN point");
88  point_msg.point.x = point_msg.point.y = point_msg.point.z = static_cast<double>(NAN);
89  }
90  else
91  {
92  std::sort(depths.begin(), depths.end());
93  float median_depth = depths[depths.size() / 2];
94 
95  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
96  // Determine roi location
97 
98  rgbd::View view(*last_image, last_image->getDepthImage().cols);
99  geo::Vec3 pos = view.getRasterizer().project2Dto3D(roi_depth_center.x, roi_depth_center.y) * static_cast<double>(median_depth);
100  pos.y = -pos.y;
101  pos.z = -pos.z;
102 
103  ROS_INFO("Pose (%.2f, %.2f, %.2f)", pos.x, pos.y, pos.z);
104  geo::convert(pos, point_msg.point);
105  }
106 
107  res.points.push_back(point_msg);
108  }
109 
110  return true;
111 }
112 
113 // ----------------------------------------------------------------------------------------------------
114 
115 int main(int argc, char **argv)
116 {
117  ros::init(argc, argv, "get_3d_point_from_image_roi");
118  ros::NodeHandle nh;
119  ros::NodeHandle nh_private("~");
120 
121  float rate = 30;
122  nh_private.getParam("rate", rate);
123 
124  // Listener
125  rgbd::Client client;
126 
127  client.initialize(ros::names::resolve("rgbd"));
128 
129  g_last_images_.set_capacity(100);
130 
131  // srv
132  ros::ServiceServer srv_project_2d_to_3d = nh.advertiseService("project_2d_to_3d", srvGet3dPointFromROI);
133  ros::Time last_image_stamp;
134 
135  rgbd::Image image;
136 
137  ros::WallTime last_master_check = ros::WallTime::now();
138 
139  ros::Rate r(rate);
140  while (ros::ok())
141  {
142  if (ros::WallTime::now() >= last_master_check + ros::WallDuration(1))
143  {
144  last_master_check = ros::WallTime::now();
145  if (!ros::master::check())
146  {
147  ROS_FATAL("Lost connection to master");
148  return 1;
149  }
150  }
151  if (client.nextImage(image))
152  {
153  if (image.getDepthImage().data)
154  {
155  last_image_stamp.fromSec(image.getTimestamp());
156 
157  g_last_images_.push_back(std::make_shared<rgbd::Image>(image));
158  ROS_DEBUG("New image added to buffer");
159  }
160  }
161  ros::spinOnce(); // Process service request after getting a new image
162  r.sleep();
163  }
164 }
datatypes.h
std::shared_ptr
rgbd::Image::getDepthImage
const cv::Mat & getDepthImage() const
Get the depth image.
Definition: image.h:72
rgbd::Image::getTimestamp
double getTimestamp() const
Get the timestamp.
Definition: image.h:90
std::vector
std::vector::size
T size(T... args)
geo::Vec3T
std::sort
T sort(T... args)
std::vector::push_back
T push_back(T... args)
geo::Vec3T::y
T y
rgbd::Image
Definition: image.h:43
rgbd::View::getRasterizer
const geo::DepthCamera & getRasterizer() const
Definition: view.h:54
std::vector::at
T at(T... args)
rgbd::Client::initialize
bool initialize(const std::string &server_name, float timeout=5.0)
Initialize the client.
Definition: client.cpp:34
g_last_images_
boost::circular_buffer< std::shared_ptr< rgbd::Image > > g_last_images_
Definition: get_3d_point_from_image_roi_node.cpp:29
main
int main(int argc, char **argv)
Definition: get_3d_point_from_image_roi_node.cpp:115
geo::DepthCamera::project2Dto3D
geo::Vec3T< T > project2Dto3D(int x, int y) const
memory
geo::convert
void convert(const geo::DepthCamera &cam_model, sensor_msgs::CameraInfo &msg)
std::min
T min(T... args)
std::vector::begin
T begin(T... args)
view.h
geo::Vec3T::z
T z
std::vector::empty
T empty(T... args)
srvGet3dPointFromROI
bool srvGet3dPointFromROI(rgbd_msgs::Project2DTo3D::Request &req, rgbd_msgs::Project2DTo3D::Response &res)
Definition: get_3d_point_from_image_roi_node.cpp:30
rgbd::Client
Client which uses the interfaces of ClientRGBD and ClientSHM.
Definition: client.h:29
std::vector::end
T end(T... args)
std::max
T max(T... args)
rgbd::View
Definition: view.h:11
geo::Vec3T::x
T x
client.h
msg_conversions.h
rgbd::Client::nextImage
bool nextImage(Image &image)
Get a new Image. If no new image has been received since the last call, no image will be written and ...
Definition: client.cpp:76