Skip to content

Commit 9cbd443

Browse files
committed
Start on spherical projection
1 parent dcc54da commit 9cbd443

File tree

3 files changed

+80
-3
lines changed

3 files changed

+80
-3
lines changed

projected_point_cloud_transport/include/projected_point_cloud_transport/projected_publisher.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#include <sensor_msgs/msg/point_cloud2.hpp>
3939

40+
#include <point_cloud_interfaces/msg/compressed_point_cloud2.hpp>
4041
#include <point_cloud_transport/point_cloud_transport.hpp>
4142

4243
#include <point_cloud_transport/simple_publisher_plugin.hpp>

projected_point_cloud_transport/src/projected_publisher.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131

3232
#include <string>
3333

34+
#include <sensor_msgs/msg/point_cloud2.hpp>
35+
#include <sensor_msgs/point_cloud_iterator.hpp>
36+
3437
#include <projected_point_cloud_transport/projected_publisher.hpp>
3538

3639
namespace projected_point_cloud_transport
@@ -59,7 +62,39 @@ ProjectedPublisher::TypedEncodeResult ProjectedPublisher::encodeTyped(
5962

6063
// TODO ([email protected]): Apply selected projection method
6164

65+
// SPHERICAL PROJECTION
66+
double phi_resolution = 0.5; // radians
67+
double theta_resolution = 0.5; // radians
68+
int phi_bins = 2 * M_PI / phi_resolution;
69+
int theta_bins = 2 * M_PI / rho_resolution;
70+
71+
cv::Mat spherical_image{phi_bins, theta_bins, CV_16UC1, cv::Scalar(0)};
72+
73+
// iterate over the pointcloud and convert to polar coordinates
74+
sensor_msgs::PointCloud2ConstIterator<float> iter_x(raw, "x");
75+
sensor_msgs::PointCloud2ConstIterator<float> iter_y(raw, "y");
76+
sensor_msgs::PointCloud2ConstIterator<float> iter_z(raw, "z");
77+
78+
for (; iter_x != iter_x.end(); ++iter_x, ++iter_y, ++iter_z) {
79+
double x = *iter_x;
80+
double y = *iter_y;
81+
double z = *iter_z;
82+
83+
double rho = std::sqrt(x * x + y * y + z * z);
84+
double phi = std::atan2(y, x);
85+
double theta = std::acos(z / rho);
86+
87+
int phi_index = phi / phi_resolution;
88+
int theta_index = theta / theta_resolution;
89+
90+
auto& cell = spherical_image.at<uint16_t>(phi_index, rho_index);
91+
cell = std::min(cell, static_cast<uint16_t>(rho * 1000)); // mm resolution
92+
}
93+
6294
// TODO ([email protected]): Apply png compression
95+
point_cloud_interfaces::msg::CompressPointCloud2 compressed;
96+
97+
cv::imencode(".png", spherical_image, compressed.compressed_data);
6398

6499
compressed.width = raw.width;
65100
compressed.height = raw.height;

projected_point_cloud_transport/src/projected_subscriber.cpp

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include <string>
3333

3434
#include <sensor_msgs/msg/point_cloud2.hpp>
35+
#include <sensor_msgs/point_cloud2_iterator.hpp>
36+
#include <sensor_msgs/point_cloud2_modifier.hpp>
3537

3638
#include <projected_point_cloud_transport/projected_subscriber.hpp>
3739

@@ -61,10 +63,49 @@ ProjectedSubscriber::DecodeResult ProjectedSubscriber::decodeTyped(
6163
// - spherical deprojection relative to some origin:
6264
// ---> viewpoint origin
6365

64-
// TODO ([email protected]): Apply selected deprojection method
66+
// SPHERICAL PROJECTION
67+
cv::Mat spherical_image = cv::imdecode(cv::Mat(msg.compressed_data), cv::IMREAD_UNCHANGED);
68+
int phi_bins = spherical_image.rows;
69+
int theta_bins = spherical_image.cols;
70+
double phi_resolution = phi_bins / 2.0 / M_PI; // radians
71+
double theta_resolution = theta_bins / 2.0 / M_PI; // radians
6572

66-
result->width = msg.width;
67-
result->height = msg.height;
73+
sensor_msgs::msg::PointCloud2 cloud;
74+
cloud.header = msg.header;
75+
76+
sensor_msgs::PointCloud2Modifier modifier(cloud);
77+
modifier.setPointCloud2Fields(3, "x", 1, sensor_msgs::msg::PointField::FLOAT32, "y", 1,
78+
sensor_msgs::msg::PointField::FLOAT32, "z", 1,
79+
sensor_msgs::msg::PointField::FLOAT32);
80+
modifier.resize(spherical_image.rows * spherical_image.cols);
81+
sensor_msgs::PointCloud2Iterator<float> pcl_itr(cloud, "x");
82+
83+
size_t valid_points = 0;
84+
// convert the spherical image to a point cloud
85+
for(int row = 0; row < spherical_image.rows; row++)
86+
{
87+
for(int col = 0; col < spherical_image.cols; col++)
88+
{
89+
uint16_t cell = spherical_image.at<uint16_t>(row, col);
90+
if(cell == 0)
91+
{
92+
continue;
93+
}
94+
// convert the spherical image pixel to a point cloud point
95+
double rho = static_cast<double>(cell) / 1000.0; // meters
96+
double phi = (row - phi_bins / 2.0) / phi_resolution;
97+
double theta = (col - theta_bins / 2.0) / theta_resolution;
98+
pcl_itr[0] = rho * std::sin(phi) * std::cos(theta);
99+
pcl_itr[1] = rho * std::sin(phi) * std::sin(theta);
100+
pcl_itr[2] = rho * std::cos(phi);
101+
++pcl_itr;
102+
valid_points++;
103+
}
104+
}
105+
modifier.resize(valid_points);
106+
107+
result->width = valid_points;
108+
result->height = 1;
68109
result->row_step = msg.row_step;
69110
result->point_step = msg.point_step;
70111
result->is_bigendian = msg.is_bigendian;

0 commit comments

Comments
 (0)