texture_point_cloud.cpp
Go to the documentation of this file.
2 
3 // Make sure cv_bridge is imported before image_transport. Otherwise
4 // getBinaryData with CV::mat overload will not be recognized.
6 
15 
17 
18 #include <mutex>
19 #include <string>
20 
21 #define NODE_CLASS_NAME TexturePointCloudNode
22 #define NODE_NAME "texture_point_cloud"
23 
25 {
26 private:
28 
29  std::mutex mutex;
30 
31  image_transport::Subscriber imageSubscriber;
33  PointCloudPublisher<ensenso::pcl::PointCloudColored> texturedPointCloudPublisher;
34 
35  sensor_msgs::msg::ImageConstPtr latestImage;
36  std::shared_ptr<ensenso::pcl::PointCloud> latestPointCloud;
37 
38 public:
40  {
42 
43  imageSubscriber =
44  ensenso::image_transport::create_subscription(nh, "image", &NODE_CLASS_NAME::onImageReceived, this);
45 
46  pointCloudSubscription = ensenso::pcl::create_subscription<ensenso::pcl::PointCloud>(
47  nh, "point_cloud", 10, &NODE_CLASS_NAME::onPointCloudReceived, this);
48 
49  texturedPointCloudPublisher =
50  ensenso::pcl::create_publisher<ensenso::pcl::PointCloudColored>(nh, "textured_point_cloud", 1);
51 
52  latestPointCloud = std::make_shared<ensenso::pcl::PointCloud>();
53  }
54 
55 private:
56  void onImageReceived(sensor_msgs::msg::ImageConstPtr const& image)
57  {
58  std::lock_guard<std::mutex> lock(mutex);
59 
60  latestImage = image;
61  }
62 
63  void POINT_CLOUD_SUBSCRIPTION_CALLBACK(onPointCloudReceived, ensenso::pcl::PointCloud, pointCloud)
64  {
65  std::lock_guard<std::mutex> lock(mutex);
66 
67  STORE_POINT_CLOUD(pointCloud, latestPointCloud);
68 
69  texture();
70  }
71 
72  void texture()
73  {
74  if (!latestImage.get() || !latestPointCloud.get())
75  {
76  return;
77  }
78 
80  try
81  {
82  image = cv_bridge::toCvShare(latestImage);
83  }
84  catch (cv_bridge::Exception& e)
85  {
86  ENSENSO_ERROR(nh, "cv_bridge exception: %s", e.what());
87  }
88 
89  auto texturedPointCloud = texturePointCloudFromRectifiedImage(image->image);
90 
91  publishPointCloud(texturedPointCloudPublisher, std::move(texturedPointCloud));
92  }
93 
94  std::unique_ptr<ensenso::pcl::PointCloudColored> texturePointCloudFromRectifiedImage(cv::Mat const& image)
95  {
96  auto texturedPointCloud = ensenso::std::make_unique<ensenso::pcl::PointCloudColored>();
97 
98  if (static_cast<int>(latestPointCloud->width) != image.cols ||
99  static_cast<int>(latestPointCloud->height) != image.rows)
100  {
101  ENSENSO_ERROR(nh, "The point cloud does not have the same format as the rectified image!");
102  return texturedPointCloud;
103  }
104 
105  texturedPointCloud->header.frame_id = latestPointCloud->header.frame_id;
106  texturedPointCloud->header.stamp = latestPointCloud->header.stamp;
107 
108  texturedPointCloud->is_dense = latestPointCloud->is_dense;
109  texturedPointCloud->width = latestPointCloud->width;
110  texturedPointCloud->height = latestPointCloud->height;
111  texturedPointCloud->points.resize(texturedPointCloud->width * texturedPointCloud->height);
112 
113  for (size_t x = 0; x < latestPointCloud->width; x++)
114  {
115  for (size_t y = 0; y < latestPointCloud->height; y++)
116  {
117  auto& point = texturedPointCloud->at(x, y);
118 
119  point.x = latestPointCloud->at(x, y).x;
120  point.y = latestPointCloud->at(x, y).y;
121  point.z = latestPointCloud->at(x, y).z;
122 
123  if (image.channels() == 3)
124  {
125  cv::Vec3b color = image.at<cv::Vec3b>(y, x);
126  point.b = color.val[0];
127  point.g = color.val[1];
128  point.r = color.val[2];
129  }
130  else
131  {
132  uchar color = image.at<uchar>(y, x);
133  point.r = color;
134  point.g = color;
135  point.b = color;
136  }
137  }
138  }
139 
140  return texturedPointCloud;
141  }
142 };
143 
144 int main(int argc, char** argv)
145 {
147 
148  return 0;
149 }
cv_bridge.h
pcl.h
boost::shared_ptr
ensenso::image_transport::create_subscription
inline ::image_transport::Subscriber create_subscription(ensenso::ros::NodeHandle &nh, ::std::string const &topic_name, void(T::*callback)(sensor_msgs::msg::ImageConstPtr const &), T *object)
Definition: image_transport.h:79
image_transport.h
CREATE_NODE_HANDLE
#define CREATE_NODE_HANDLE(nh)
Definition: node_handle.h:80
cv_bridge::Exception
namespace.h
STORE_POINT_CLOUD
#define STORE_POINT_CLOUD(point_cloud_boost_ptr, point_cloud_std_ptr)
Definition: pcl.h:90
main
int main(int argc, char **argv)
Definition: texture_point_cloud.cpp:144
image_transport::Subscriber
point_cloud_utilities.h
node.h
ensenso::pcl::PointCloud
::pcl::PointCloud<::pcl::PointXYZ > PointCloud
Definition: point_cloud_utilities.h:9
NODE_NAME
#define NODE_NAME
Definition: texture_point_cloud.cpp:22
ensenso::ros::NodeHandle
::ros::NodeHandle NodeHandle
Definition: node.h:215
publishPointCloud
void publishPointCloud(ensenso::ros::Publisher< T > const &publisher, std::unique_ptr< T > pointCloud)
Definition: pcl.h:95
image.h
SINGLE_NODE_CTOR
#define SINGLE_NODE_CTOR(ClassName, NodeName)
Definition: node.h:207
node_wrapper.h
SINGLE_NODE_CLASS
SINGLE_NODE_CLASS(NODE_CLASS_NAME)
Definition: texture_point_cloud.cpp:24
PointCloudPublisher
ensenso::ros::Publisher< T > PointCloudPublisher
Definition: pcl.h:63
NODE_CLASS_NAME
#define NODE_CLASS_NAME
Definition: texture_point_cloud.cpp:21
logging.h
core.h
ENSENSO_ERROR
void ENSENSO_ERROR(T... args)
Definition: logging.h:278
cv_bridge::toCvShare
CvImageConstPtr toCvShare(const sensor_msgs::Image &source, const boost::shared_ptr< void const > &tracked_object, const std::string &encoding=std::string())
SINGLE_NODE_WRAPPER
#define SINGLE_NODE_WRAPPER(ClassName, NodeName)
Definition: node_wrapper.h:48
ros::Subscriber
node_handle.h
POINT_CLOUD_SUBSCRIPTION_CALLBACK
#define POINT_CLOUD_SUBSCRIPTION_CALLBACK(callback, T, arg_name)
Definition: pcl.h:68


ensenso_camera
Author(s): Ensenso
autogenerated on Wed Apr 2 2025 02:37:46