6 #include <unordered_map> 10 #include <draco/compression/expert_encode.h> 11 #include <draco/compression/encode.h> 12 #include <draco/point_cloud/point_cloud_builder.h> 19 #include <draco_point_cloud_transport/CompressedPointCloud2.h> 26 static std::unordered_map<std::string, draco::GeometryAttribute::Type>
attributeTypes = {
27 {
"x", draco::GeometryAttribute::Type::POSITION},
28 {
"y", draco::GeometryAttribute::Type::POSITION},
29 {
"z", draco::GeometryAttribute::Type::POSITION},
30 {
"pos", draco::GeometryAttribute::Type::POSITION},
31 {
"position", draco::GeometryAttribute::Type::POSITION},
32 {
"vp_x", draco::GeometryAttribute::Type::POSITION},
33 {
"vp_y", draco::GeometryAttribute::Type::POSITION},
34 {
"vp_z", draco::GeometryAttribute::Type::POSITION},
35 {
"rgb", draco::GeometryAttribute::Type::COLOR},
36 {
"rgba", draco::GeometryAttribute::Type::COLOR},
37 {
"r", draco::GeometryAttribute::Type::COLOR},
38 {
"g", draco::GeometryAttribute::Type::COLOR},
39 {
"b", draco::GeometryAttribute::Type::COLOR},
40 {
"a", draco::GeometryAttribute::Type::COLOR},
41 {
"nx", draco::GeometryAttribute::Type::NORMAL},
42 {
"ny", draco::GeometryAttribute::Type::NORMAL},
43 {
"nz", draco::GeometryAttribute::Type::NORMAL},
44 {
"normal_x", draco::GeometryAttribute::Type::NORMAL},
45 {
"normal_y", draco::GeometryAttribute::Type::NORMAL},
46 {
"normal_z", draco::GeometryAttribute::Type::NORMAL},
50 const sensor_msgs::PointCloud2& PC2,
const std::string& topic,
bool deduplicate,
bool expert_encoding)
53 draco::PointCloudBuilder builder;
55 uint64_t number_of_points = PC2.height * PC2.width;
57 builder.Start(number_of_points);
59 std::vector<int> att_ids;
62 draco::GeometryAttribute::Type attribute_type = draco::GeometryAttribute::INVALID;
63 draco::DataType attribute_data_type = draco::DT_INVALID;
66 bool rgba_tweak =
false;
67 bool rgba_tweak_64bit =
false;
70 bool expert_settings_ok =
true;
72 std::string expert_attribute_data_type;
75 for (
const auto& field : PC2.fields)
81 expert_attribute_data_type))
83 if (expert_attribute_data_type ==
"POSITION")
85 attribute_type = draco::GeometryAttribute::POSITION;
87 else if (expert_attribute_data_type ==
"NORMAL")
89 attribute_type = draco::GeometryAttribute::NORMAL;
91 else if (expert_attribute_data_type ==
"COLOR")
93 attribute_type = draco::GeometryAttribute::COLOR;
96 else if (expert_attribute_data_type ==
"TEX_COORD")
98 attribute_type = draco::GeometryAttribute::TEX_COORD;
100 else if (expert_attribute_data_type ==
"GENERIC")
102 attribute_type = draco::GeometryAttribute::GENERIC;
106 CRAS_ERROR_STREAM(
"Attribute data type not recognized for " + field.name +
" field entry. " 107 "Using regular type recognition instead.");
108 expert_settings_ok =
false;
113 CRAS_ERROR_STREAM(
"Attribute data type not specified for " + field.name +
" field entry." 114 "Using regular type recognition instead.");
115 CRAS_INFO_STREAM(
"To set attribute type for " + field.name +
" field entry, set " + topic +
116 "/draco/attribute_mapping/attribute_type/" + field.name);
117 expert_settings_ok =
false;
122 if ((!expert_encoding) || (!expert_settings_ok))
124 rgba_tweak = field.name ==
"rgb" || field.name ==
"rgba";
125 attribute_type = draco::GeometryAttribute::GENERIC;
126 const auto& it = attributeTypes.find(field.name);
127 if (it != attributeTypes.end())
129 attribute_type = it->second;
134 switch (field.datatype)
136 case sensor_msgs::PointField::INT8:attribute_data_type = draco::DT_INT8;
138 case sensor_msgs::PointField::UINT8:attribute_data_type = draco::DT_UINT8;
140 case sensor_msgs::PointField::INT16:attribute_data_type = draco::DT_INT16;
142 case sensor_msgs::PointField::UINT16:attribute_data_type = draco::DT_UINT16;
144 case sensor_msgs::PointField::INT32:attribute_data_type = draco::DT_INT32;
145 rgba_tweak_64bit =
false;
147 case sensor_msgs::PointField::UINT32:attribute_data_type = draco::DT_UINT32;
148 rgba_tweak_64bit =
false;
150 case sensor_msgs::PointField::FLOAT32:attribute_data_type = draco::DT_FLOAT32;
151 rgba_tweak_64bit =
false;
153 case sensor_msgs::PointField::FLOAT64:attribute_data_type = draco::DT_FLOAT64;
154 rgba_tweak_64bit =
true;
156 default:
return cras::make_unexpected(
"Invalid data type in PointCloud2 to Draco conversion");
162 if (rgba_tweak_64bit)
164 att_ids.push_back(builder.AddAttribute(attribute_type, 4 * field.count, draco::DT_UINT16));
168 att_ids.push_back(builder.AddAttribute(attribute_type, 4 * field.count, draco::DT_UINT8));
173 att_ids.push_back(builder.AddAttribute(attribute_type, field.count, attribute_data_type));
176 if ((!att_ids.empty()) && (attribute_data_type != draco::DT_INVALID))
178 builder.SetAttributeValuesForAllPoints(
179 static_cast<int>(att_ids.back()), &PC2.data[0] + field.offset, PC2.point_step);
183 std::unique_ptr<draco::PointCloud> pc = builder.Finalize(deduplicate);
187 return cras::make_unexpected(
"Conversion from sensor_msgs::PointCloud2 to Draco::PointCloud failed");
191 std::unique_ptr<draco::GeometryMetadata> metadata = std::make_unique<draco::GeometryMetadata>();
195 metadata->AddEntryInt(
"deduplicate", 1);
199 metadata->AddEntryInt(
"deduplicate", 0);
201 pc->AddMetadata(std::move(metadata));
203 if ((pc->num_points() != number_of_points) && !deduplicate)
205 return cras::make_unexpected(
"Number of points in Draco::PointCloud differs from sensor_msgs::PointCloud2!");
208 return std::move(pc);
217 const sensor_msgs::PointCloud2& raw,
const draco_point_cloud_transport::DracoPublisherConfig& config)
const 220 sensor_msgs::PointCloud2Ptr rawCleaned;
222 rawCleaned = boost::make_shared<sensor_msgs::PointCloud2>();
223 CREATE_FILTERED_CLOUD(raw, *rawCleaned,
false, std::isfinite(*x_it) && std::isfinite(*y_it) && std::isfinite(*z_it))
226 const sensor_msgs::PointCloud2& rawDense = raw.is_dense ? raw : *rawCleaned;
229 draco_point_cloud_transport::CompressedPointCloud2 compressed;
236 return cras::make_unexpected(res.error());
239 const auto& pc = res.value();
241 if (config.deduplicate)
243 compressed.height = 1;
244 compressed.width = pc->num_points();
245 compressed.row_step = compressed.width * compressed.point_step;
246 compressed.is_dense =
true;
249 draco::EncoderBuffer encode_buffer;
252 bool expert_settings_ok =
true;
255 if (config.expert_quantization)
257 draco::ExpertEncoder expert_encoder(*pc);
258 expert_encoder.SetSpeedOptions(config.encode_speed, config.decode_speed);
261 if ((config.encode_method == 0) && (!config.force_quantization))
266 else if ((config.encode_method == 1) || (config.force_quantization))
268 if (config.force_quantization)
272 int attribute_quantization_bits;
274 for (
const auto& field : rawDense.fields)
277 attribute_quantization_bits))
279 expert_encoder.SetAttributeQuantization(att_id, attribute_quantization_bits);
283 CRAS_ERROR_STREAM(
"Attribute quantization not specified for " + field.name +
" field entry. " 284 "Using regular encoder instead.");
286 "/draco/attribute_mapping/quantization_bits/" + field.name);
287 expert_settings_ok =
false;
292 expert_encoder.SetEncodingMethod(draco::POINT_CLOUD_KD_TREE_ENCODING);
297 expert_encoder.SetEncodingMethod(draco::POINT_CLOUD_SEQUENTIAL_ENCODING);
302 draco::Status status = expert_encoder.EncodeToBuffer(&encode_buffer);
304 if (status.code() != 0)
306 return cras::make_unexpected(
307 cras::format(
"Draco encoder returned code %i: %s.", status.code(), status.error_msg()));
313 if ((!config.expert_quantization) || (!expert_settings_ok))
315 draco::Encoder encoder;
316 encoder.SetSpeedOptions(config.encode_speed, config.decode_speed);
319 if ((config.encode_method == 0) && (!config.force_quantization))
324 else if ((config.encode_method == 1) || (config.force_quantization))
326 if (config.force_quantization)
328 encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, config.quantization_POSITION);
329 encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, config.quantization_NORMAL);
330 encoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, config.quantization_COLOR);
331 encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, config.quantization_TEX_COORD);
332 encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, config.quantization_GENERIC);
334 encoder.SetEncodingMethod(draco::POINT_CLOUD_KD_TREE_ENCODING);
339 encoder.SetEncodingMethod(draco::POINT_CLOUD_SEQUENTIAL_ENCODING);
343 draco::Status status = encoder.EncodePointCloudToBuffer(*pc, &encode_buffer);
347 return cras::make_unexpected(
348 cras::format(
"Draco encoder returned code %i: %s.", status.code(), status.error_msg()));
353 uint32_t compressed_data_size = encode_buffer.size();
354 auto cast_buffer =
reinterpret_cast<const unsigned char*
>(encode_buffer.data());
355 std::vector<unsigned char> vec_data(cast_buffer, cast_buffer + compressed_data_size);
356 compressed.compressed_data = vec_data;
363 attributeTypes[field] = draco::GeometryAttribute::Type::POSITION;
368 attributeTypes[field] = draco::GeometryAttribute::Type::COLOR;
373 attributeTypes[field] = draco::GeometryAttribute::Type::NORMAL;
std::string getTransportName() const override
#define CRAS_INFO_STREAM(args)
static void registerColorField(const std::string &field)
static void registerNormalField(const std::string &field)
void copyCloudMetadata(PC1 &target, const PC2 &source)
copies header, width, ... between clouds
static std::unordered_map< std::string, draco::GeometryAttribute::Type > attributeTypes
cras::expected< cras::optional< CompressedPointCloud2 >, std::string > TypedEncodeResult
#define CRAS_ERROR_STREAM(args)
ROSCPP_DECL bool getCached(const std::string &key, std::string &s)
inline ::std::string format(const char *format, ::va_list args)
#define CREATE_FILTERED_CLOUD(IN, OUT, KEEP_ORGANIZED, FILTER)
static void registerPositionField(const std::string &field)
TypedEncodeResult encodeTyped(const sensor_msgs::PointCloud2 &raw, const draco_point_cloud_transport::DracoPublisherConfig &config) const override
cras::expected< std::unique_ptr< draco::PointCloud >, std::string > convertPC2toDraco(const sensor_msgs::PointCloud2 &PC2, const std::string &topic, bool deduplicate, bool expert_encoding)