38 #ifndef OCTREE_COMPRESSION_HPP
39 #define OCTREE_COMPRESSION_HPP
57 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void PointCloudCompression<
58 PointT, LeafT, BranchT, OctreeT>::encodePointCloud (
60 std::ostream& compressedTreeDataOut_arg)
62 unsigned char recentTreeDepth =
63 static_cast<unsigned char> (this->getTreeDepth ());
66 this->setInputCloud (cloud_arg);
69 this->addPointsFromInputCloud ();
72 if (this->leafCount_>0) {
76 cloudWithColor_ =
false;
77 std::vector<sensor_msgs::PointField> fields;
86 pointColorOffset_ =
static_cast<unsigned char> (fields[rgba_index].offset);
87 cloudWithColor_ =
true;
91 cloudWithColor_ &= doColorEncoding_;
95 iFrame_ |= (recentTreeDepth != this->getTreeDepth ());
98 if (iFrameCounter_++==iFrameRate_)
108 if (!doVoxelGridEnDecoding_)
110 pointCountDataVector_.clear ();
111 pointCountDataVector_.reserve (cloud_arg->points.size ());
115 colorCoder_.initializeEncoding ();
116 colorCoder_.setPointCount (static_cast<unsigned int> (cloud_arg->points.size ()));
117 colorCoder_.setVoxelCount (static_cast<unsigned int> (this->leafCount_));
120 pointCoder_.initializeEncoding ();
121 pointCoder_.setPointCount (static_cast<unsigned int> (cloud_arg->points.size ()));
126 this->serializeTree (binaryTreeDataVector_,
false);
129 this->serializeTree (binaryTreeDataVector_,
true);
132 this->writeFrameHeader (compressedTreeDataOut_arg);
135 this->entropyEncoding (compressedTreeDataOut_arg);
138 this->switchBuffers ();
143 float bytesPerXYZ =
static_cast<float> (compressedPointDataLen_) / static_cast<float> (pointCount_);
144 float bytesPerColor =
static_cast<float> (compressedColorDataLen_) / static_cast<float> (pointCount_);
146 PCL_INFO (
"*** POINTCLOUD ENCODING ***\n");
147 PCL_INFO (
"Frame ID: %d\n", frameID_);
149 PCL_INFO (
"Encoding Frame: Intra frame\n");
151 PCL_INFO (
"Encoding Frame: Prediction frame\n");
152 PCL_INFO (
"Number of encoded points: %ld\n", pointCount_);
153 PCL_INFO (
"XYZ compression percentage: %f%%\n", bytesPerXYZ / (3.0f *
sizeof(
float)) * 100.0f);
154 PCL_INFO (
"XYZ bytes per point: %f bytes\n", bytesPerXYZ);
155 PCL_INFO (
"Color compression percentage: %f%%\n", bytesPerColor / (
sizeof (
int)) * 100.0f);
156 PCL_INFO (
"Color bytes per point: %f bytes\n", bytesPerColor);
157 PCL_INFO (
"Size of uncompressed point cloud: %f kBytes\n", static_cast<float> (pointCount_) * (
sizeof (
int) + 3.0f *
sizeof (
float)) / 1024);
158 PCL_INFO (
"Size of compressed point cloud: %d kBytes\n", (compressedPointDataLen_ + compressedColorDataLen_) / (1024));
159 PCL_INFO (
"Total bytes per point: %f\n", bytesPerXYZ + bytesPerColor);
160 PCL_INFO (
"Total compression percentage: %f\n", (bytesPerXYZ + bytesPerColor) / (
sizeof (
int) + 3.0f *
sizeof(
float)) * 100.0f);
161 PCL_INFO (
"Compression ratio: %f\n\n", static_cast<float> (
sizeof (
int) + 3.0f *
sizeof (
float)) / static_cast<float> (bytesPerXYZ + bytesPerColor));
165 PCL_INFO (
"Info: Dropping empty point cloud\n");
173 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void
175 std::istream& compressedTreeDataIn_arg,
180 syncToHeader(compressedTreeDataIn_arg);
183 this->switchBuffers ();
184 this->setOutputCloud (cloud_arg);
187 cloudWithColor_ =
false;
188 std::vector<sensor_msgs::PointField> fields;
191 if (rgba_index == -1)
195 pointColorOffset_ =
static_cast<unsigned char> (fields[rgba_index].offset);
196 cloudWithColor_ =
true;
200 this->readFrameHeader (compressedTreeDataIn_arg);
203 this->entropyDecoding (compressedTreeDataIn_arg);
206 colorCoder_.initializeDecoding ();
207 pointCoder_.initializeDecoding ();
210 output_->points.clear ();
211 output_->points.reserve (static_cast<std::size_t> (pointCount_));
215 this->deserializeTree (binaryTreeDataVector_,
false);
218 this->deserializeTree (binaryTreeDataVector_,
true);
222 output_->width =
static_cast<uint32_t
> (cloud_arg->points.size ());
223 output_->is_dense =
false;
227 float bytesPerXYZ =
static_cast<float> (compressedPointDataLen_) / static_cast<float> (pointCount_);
228 float bytesPerColor =
static_cast<float> (compressedColorDataLen_) / static_cast<float> (pointCount_);
230 PCL_INFO (
"*** POINTCLOUD DECODING ***\n");
231 PCL_INFO (
"Frame ID: %d\n", frameID_);
233 PCL_INFO (
"Encoding Frame: Intra frame\n");
235 PCL_INFO (
"Encoding Frame: Prediction frame\n");
236 PCL_INFO (
"Number of encoded points: %ld\n", pointCount_);
237 PCL_INFO (
"XYZ compression percentage: %f%%\n", bytesPerXYZ / (3.0f *
sizeof (
float)) * 100.0f);
238 PCL_INFO (
"XYZ bytes per point: %f bytes\n", bytesPerXYZ);
239 PCL_INFO (
"Color compression percentage: %f%%\n", bytesPerColor / (
sizeof (
int)) * 100.0f);
240 PCL_INFO (
"Color bytes per point: %f bytes\n", bytesPerColor);
241 PCL_INFO (
"Size of uncompressed point cloud: %f kBytes\n", static_cast<float> (pointCount_) * (
sizeof (
int) + 3.0f *
sizeof (
float)) / 1024.0f);
242 PCL_INFO (
"Size of compressed point cloud: %f kBytes\n", static_cast<float> (compressedPointDataLen_ + compressedColorDataLen_) / 1024.0f);
243 PCL_INFO (
"Total bytes per point: %d bytes\n", static_cast<int> (bytesPerXYZ + bytesPerColor));
244 PCL_INFO (
"Total compression percentage: %f%%\n", (bytesPerXYZ + bytesPerColor) / (
sizeof (
int) + 3.0f *
sizeof (
float)) * 100.0f);
245 PCL_INFO (
"Compression ratio: %f\n\n", static_cast<float> (
sizeof (
int) + 3.0f *
sizeof (
float)) / static_cast<float> (bytesPerXYZ + bytesPerColor));
250 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void
253 uint64_t binaryTreeDataVector_size;
254 uint64_t pointAvgColorDataVector_size;
256 compressedPointDataLen_ = 0;
257 compressedColorDataLen_ = 0;
260 binaryTreeDataVector_size = binaryTreeDataVector_.size ();
261 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&binaryTreeDataVector_size),
sizeof (binaryTreeDataVector_size));
262 compressedPointDataLen_ += entropyCoder_.encodeCharVectorToStream (binaryTreeDataVector_,
263 compressedTreeDataOut_arg);
268 std::vector<char>& pointAvgColorDataVector = colorCoder_.getAverageDataVector ();
269 pointAvgColorDataVector_size = pointAvgColorDataVector.size ();
270 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&pointAvgColorDataVector_size),
271 sizeof (pointAvgColorDataVector_size));
272 compressedColorDataLen_ += entropyCoder_.encodeCharVectorToStream (pointAvgColorDataVector,
273 compressedTreeDataOut_arg);
276 if (!doVoxelGridEnDecoding_)
278 uint64_t pointCountDataVector_size;
279 uint64_t pointDiffDataVector_size;
280 uint64_t pointDiffColorDataVector_size;
283 pointCountDataVector_size = pointCountDataVector_.size ();
284 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&pointCountDataVector_size),
sizeof (pointCountDataVector_size));
285 compressedPointDataLen_ += entropyCoder_.encodeIntVectorToStream (pointCountDataVector_,
286 compressedTreeDataOut_arg);
289 std::vector<char>& pointDiffDataVector = pointCoder_.getDifferentialDataVector ();
290 pointDiffDataVector_size = pointDiffDataVector.size ();
291 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&pointDiffDataVector_size),
sizeof (pointDiffDataVector_size));
292 compressedPointDataLen_ += entropyCoder_.encodeCharVectorToStream (pointDiffDataVector,
293 compressedTreeDataOut_arg);
297 std::vector<char>& pointDiffColorDataVector = colorCoder_.getDifferentialDataVector ();
298 pointDiffColorDataVector_size = pointDiffColorDataVector.size ();
299 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&pointDiffColorDataVector_size),
300 sizeof (pointDiffColorDataVector_size));
301 compressedColorDataLen_ += entropyCoder_.encodeCharVectorToStream (pointDiffColorDataVector,
302 compressedTreeDataOut_arg);
306 compressedTreeDataOut_arg.flush ();
310 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void
311 PointCloudCompression<PointT, LeafT, BranchT, OctreeT>::entropyDecoding (std::istream& compressedTreeDataIn_arg)
313 uint64_t binaryTreeDataVector_size;
314 uint64_t pointAvgColorDataVector_size;
316 compressedPointDataLen_ = 0;
317 compressedColorDataLen_ = 0;
320 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&binaryTreeDataVector_size),
sizeof (binaryTreeDataVector_size));
321 binaryTreeDataVector_.resize (static_cast<std::size_t> (binaryTreeDataVector_size));
322 compressedPointDataLen_ += entropyCoder_.decodeStreamToCharVector (compressedTreeDataIn_arg,
323 binaryTreeDataVector_);
328 std::vector<char>& pointAvgColorDataVector = colorCoder_.getAverageDataVector ();
329 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&pointAvgColorDataVector_size),
sizeof (pointAvgColorDataVector_size));
330 pointAvgColorDataVector.resize (static_cast<std::size_t> (pointAvgColorDataVector_size));
331 compressedColorDataLen_ += entropyCoder_.decodeStreamToCharVector (compressedTreeDataIn_arg,
332 pointAvgColorDataVector);
335 if (!doVoxelGridEnDecoding_)
337 uint64_t pointCountDataVector_size;
338 uint64_t pointDiffDataVector_size;
339 uint64_t pointDiffColorDataVector_size;
342 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&pointCountDataVector_size),
sizeof (pointCountDataVector_size));
343 pointCountDataVector_.resize (static_cast<std::size_t> (pointCountDataVector_size));
344 compressedPointDataLen_ += entropyCoder_.decodeStreamToIntVector (compressedTreeDataIn_arg, pointCountDataVector_);
345 pointCountDataVectorIterator_ = pointCountDataVector_.begin ();
348 std::vector<char>& pointDiffDataVector = pointCoder_.getDifferentialDataVector ();
349 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&pointDiffDataVector_size),
sizeof (pointDiffDataVector_size));
350 pointDiffDataVector.resize (static_cast<std::size_t> (pointDiffDataVector_size));
351 compressedPointDataLen_ += entropyCoder_.decodeStreamToCharVector (compressedTreeDataIn_arg,
352 pointDiffDataVector);
357 std::vector<char>& pointDiffColorDataVector = colorCoder_.getDifferentialDataVector ();
358 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&pointDiffColorDataVector_size),
sizeof (pointDiffColorDataVector_size));
359 pointDiffColorDataVector.resize (static_cast<std::size_t> (pointDiffColorDataVector_size));
360 compressedColorDataLen_ += entropyCoder_.decodeStreamToCharVector (compressedTreeDataIn_arg,
361 pointDiffColorDataVector);
367 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void
368 PointCloudCompression<PointT, LeafT, BranchT, OctreeT>::writeFrameHeader (std::ostream& compressedTreeDataOut_arg)
371 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (frameHeaderIdentifier_), strlen (frameHeaderIdentifier_));
373 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&frameID_),
sizeof (frameID_));
375 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&iFrame_),
sizeof (iFrame_));
378 double minX, minY, minZ, maxX, maxY, maxZ;
379 double octreeResolution;
380 unsigned char colorBitDepth;
381 double pointResolution;
384 octreeResolution = this->getResolution ();
385 colorBitDepth = colorCoder_.getBitDepth ();
386 pointResolution= pointCoder_.getPrecision ();
387 this->getBoundingBox (minX, minY, minZ, maxX, maxY, maxZ);
390 if (doVoxelGridEnDecoding_)
391 pointCount_ = this->leafCount_;
393 pointCount_ = this->objectCount_;
396 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&doVoxelGridEnDecoding_),
sizeof (doVoxelGridEnDecoding_));
397 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&cloudWithColor_),
sizeof (cloudWithColor_));
398 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&pointCount_),
sizeof (pointCount_));
399 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&octreeResolution),
sizeof (octreeResolution));
400 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&colorBitDepth),
sizeof (colorBitDepth));
401 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&pointResolution),
sizeof (pointResolution));
404 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&minX),
sizeof (minX));
405 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&minY),
sizeof (minY));
406 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&minZ),
sizeof (minZ));
407 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&maxX),
sizeof (maxX));
408 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&maxY),
sizeof (maxY));
409 compressedTreeDataOut_arg.write (reinterpret_cast<const char*> (&maxZ),
sizeof (maxZ));
414 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void
415 PointCloudCompression<PointT, LeafT, BranchT, OctreeT>::syncToHeader ( std::istream& compressedTreeDataIn_arg)
418 unsigned int headerIdPos = 0;
419 while (headerIdPos < strlen (frameHeaderIdentifier_))
422 compressedTreeDataIn_arg.read (static_cast<char*> (&readChar),
sizeof (readChar));
423 if (readChar != frameHeaderIdentifier_[headerIdPos++])
424 headerIdPos = (frameHeaderIdentifier_[0]==readChar)?1:0;
429 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void
430 PointCloudCompression<PointT, LeafT, BranchT, OctreeT>::readFrameHeader ( std::istream& compressedTreeDataIn_arg)
433 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&frameID_),
sizeof (frameID_));
434 compressedTreeDataIn_arg.read (reinterpret_cast<char*>(&iFrame_),
sizeof (iFrame_));
437 double minX, minY, minZ, maxX, maxY, maxZ;
438 double octreeResolution;
439 unsigned char colorBitDepth;
440 double pointResolution;
443 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&doVoxelGridEnDecoding_),
sizeof (doVoxelGridEnDecoding_));
444 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&dataWithColor_),
sizeof (dataWithColor_));
445 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&pointCount_),
sizeof (pointCount_));
446 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&octreeResolution),
sizeof (octreeResolution));
447 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&colorBitDepth),
sizeof (colorBitDepth));
448 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&pointResolution),
sizeof (pointResolution));
451 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&minX),
sizeof (minX));
452 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&minY),
sizeof (minY));
453 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&minZ),
sizeof (minZ));
454 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&maxX),
sizeof (maxX));
455 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&maxY),
sizeof (maxY));
456 compressedTreeDataIn_arg.read (reinterpret_cast<char*> (&maxZ),
sizeof (maxZ));
460 this->setResolution (octreeResolution);
461 this->defineBoundingBox (minX, minY, minZ, maxX, maxY, maxZ);
464 colorCoder_.setBitDepth (colorBitDepth);
465 pointCoder_.setPrecision (static_cast<float> (pointResolution));
470 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void
471 PointCloudCompression<PointT, LeafT, BranchT, OctreeT>::serializeTreeCallback (
472 LeafNode &leaf_arg,
const OctreeKey & key_arg)
475 const std::vector<int>& leafIdx = leaf_arg.getDataTVector ();
477 if (!doVoxelGridEnDecoding_)
479 double lowerVoxelCorner[3];
482 pointCountDataVector_.push_back (static_cast<int> (leafIdx.size ()));
485 lowerVoxelCorner[0] =
static_cast<double> (key_arg.x) * this->resolution_ + this->minX_;
486 lowerVoxelCorner[1] =
static_cast<double> (key_arg.y) * this->resolution_ + this->minY_;
487 lowerVoxelCorner[2] =
static_cast<double> (key_arg.z) * this->resolution_ + this->minZ_;
490 pointCoder_.encodePoints (leafIdx, lowerVoxelCorner, this->input_);
494 colorCoder_.encodePoints (leafIdx, pointColorOffset_, this->input_);
500 colorCoder_.encodeAverageOfPoints (leafIdx, pointColorOffset_, this->input_);
505 template<
typename Po
intT,
typename LeafT,
typename BranchT,
typename OctreeT>
void
506 PointCloudCompression<PointT, LeafT, BranchT, OctreeT>::deserializeTreeCallback (LeafNode&,
507 const OctreeKey& key_arg)
509 double lowerVoxelCorner[3];
510 std::size_t pointCount, i, cloudSize;
515 if (!doVoxelGridEnDecoding_)
518 cloudSize = output_->points.size ();
521 pointCount = *pointCountDataVectorIterator_;
522 pointCountDataVectorIterator_++;
525 for (i = 0; i < pointCount; i++)
526 output_->points.push_back (newPoint);
529 lowerVoxelCorner[0] =
static_cast<double> (key_arg.x) * this->resolution_ + this->minX_;
530 lowerVoxelCorner[1] =
static_cast<double> (key_arg.y) * this->resolution_ + this->minY_;
531 lowerVoxelCorner[2] =
static_cast<double> (key_arg.z) * this->resolution_ + this->minZ_;
534 pointCoder_.decodePoints (output_, lowerVoxelCorner, cloudSize, cloudSize + pointCount);
539 newPoint.x =
static_cast<float> ((
static_cast<double> (key_arg.x) + 0.5) * this->resolution_ + this->minX_);
540 newPoint.y =
static_cast<float> ((
static_cast<double> (key_arg.y) + 0.5) * this->resolution_ + this->minY_);
541 newPoint.z =
static_cast<float> ((
static_cast<double> (key_arg.z) + 0.5) * this->resolution_ + this->minZ_);
544 output_->points.push_back (newPoint);
551 colorCoder_.decodePoints (output_, output_->points.size () - pointCount,
552 output_->points.size (), pointColorOffset_);
555 colorCoder_.setDefaultColor (output_, output_->points.size () - pointCount,
556 output_->points.size (), pointColorOffset_);
562 #define PCL_INSTANTIATE_PointCloudCompression(T) template class PCL_EXPORTS pcl::octree::PointCloudCompression<T, pcl::octree::OctreeContainerDataTVector<int>, pcl::octree::OctreeContainerEmpty<int>, pcl::octree::Octree2BufBase<int, pcl::octree::OctreeContainerDataTVector<int>, pcl::octree::OctreeContainerEmpty<int> > >;