ぷろぐ((>ω<))

ぷろぐらみんぐ関係のメモ

PCDファイルの保存読込速度・サイズ比較

ポイントクラウドの保存関数(PCD形式)は下記の3通りがある。

  • pcl::io::savePCDFileASCII
    • 全部テキスト形式で保存
  • pcl::io::savePCDFileBinary
    • ヘッダはテキスト形式で、データ部分はバイナリ形式で保存
  • pcl::io::savePCDFileBinaryCompressed

ちなみに pcl::io::savePCDFile という関数もあるが、この関数では引数でASCIIかBinaryかを選択する。何も指定しないとASCIIになる。

読込に関してはどの形式で保存してもすべて pcl::io::loadPCDFile という関数で可能。

保存読込速度・ファイルサイズ比較

以上の3つの方法について、保存・読込速度とファイルサイズを下記のコードで比較した。

#define PCL_NO_PRECOMPILE	// Workaround for a problem: http://www.pcl-users.org/PCL-Features-Library-Limit-Exceeded-td4026817.html
#define CLOUD_SIZE 100000
#define ITERATION 100
#define FILE_NAME_ASCII "cloud_ascii.pcd"
#define FILE_NAME_BIN "cloud_bin.pcd"
#define FILE_NAME_BIN_CON "cloud_bin_con.pcd"

#include <iostream>
#include <boost/filesystem.hpp>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/console/time.h>

typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
typedef PointCloudT::Ptr PointCloudPtrT;
typedef PointCloudT::ConstPtr PointCloudConstPtrT;

void createRandomPointCloud(PointCloudT &cloud, unsigned int size) {
	cloud.resize(size);
	BOOST_FOREACH(PointT &p, cloud) { p.getVector3fMap() = Eigen::Vector3f::Random(); }
}

double getFileSize(const std::string &file_path) {
	double file_size(-1.0);
	try {
		file_size = boost::filesystem::file_size(boost::filesystem::path(file_path));
	} catch(boost::filesystem::filesystem_error &ex) {
		std::cerr << ex.what() << std::endl;
	}
	return file_size;
}

double getFileSizeKB(const std::string &file_path) { return getFileSize(file_path) / 1024; }
double getFileSizeMB(const std::string &file_path) { return getFileSizeKB(file_path) / 1024; }

void main() {
	pcl::console::TicToc tt;
	std::printf("Cloud size: %d\n", CLOUD_SIZE);
	std::printf("Iteration : %d\n\n", ITERATION);

	// Create data
	PointCloudPtrT cloud(new PointCloudT);
	createRandomPointCloud(*cloud, CLOUD_SIZE);

	// Save as ASCII
	std::printf("---- Save ----\n");

	std::printf("ASCII : ");
	tt.tic();
	for(int i = 0; i < ITERATION; i++) { pcl::io::savePCDFileASCII(FILE_NAME_ASCII, *cloud); }
	std::printf("average %lf ms, %lf MB\n", tt.toc() / ITERATION, getFileSizeMB(FILE_NAME_ASCII));

	std::printf("Binary: ");
	tt.tic();
	for(int i = 0; i < ITERATION; i++) { pcl::io::savePCDFileBinary(FILE_NAME_BIN, *cloud); }
	std::printf("average %lf ms, %lf MB\n", tt.toc() / ITERATION, getFileSizeMB(FILE_NAME_BIN));

	std::printf("BinCon: ");
	tt.tic();
	for(int i = 0; i < ITERATION; i++) { pcl::io::savePCDFileBinaryCompressed(FILE_NAME_BIN_CON, *cloud); }
	std::printf("average %lf ms, %lf MB\n\n", tt.toc() / ITERATION, getFileSizeMB(FILE_NAME_BIN_CON));

	// Save as ASCII
	std::printf("---- Load ----\n");

	std::printf("ASCII : ");
	tt.tic();
	for(int i = 0; i < ITERATION; i++) { pcl::io::loadPCDFile(FILE_NAME_ASCII, *cloud); }
	std::printf("average %lf ms\n", tt.toc() / ITERATION);

	std::printf("Binary: ");
	tt.tic();
	for(int i = 0; i < ITERATION; i++) { pcl::io::loadPCDFile(FILE_NAME_BIN, *cloud); }
	std::printf("average %lf ms\n", tt.toc() / ITERATION);

	std::printf("BinCon: ");
	tt.tic();
	for(int i = 0; i < ITERATION; i++) { pcl::io::loadPCDFile(FILE_NAME_BIN_CON, *cloud); }
	std::printf("average %lf ms\n\n", tt.toc() / ITERATION);

	std:system("pause");
}

結果

私の環境での結果がこちら。

Cloud size: 100000
Iteration : 100

---- Save ----
ASCII : average 716.760000 ms, 3.385189 MB
Binary: average 5.140000 ms, 1.144575 MB
BinCon: average 20.430000 ms, 1.148658 MB

---- Load ----
ASCII : average 1250.230000 ms
Binary: average 5.460000 ms
BinCon: average 10.770000 ms

保存について

  • BinaryがASCIIに比べて約143倍速かった。ファイルサイズは3分の1
  • 圧縮版Binaryは通常Binaryの約4倍の時間がかかった。
  • やはり圧縮率は低かった。(というか増えた)
    • ただ、今回はランダム値なので圧縮する部分が少なかった。
    • たくさんゼロが並んでいるといったポイントクラウドでは効果を発揮するかもしれない。
    • しかし、ゼロな点は普通除去して各種の処理をすると思うので、通常の3次元データでは圧縮版を使う旨味はないだろう
    • 除去できないゼロが多いデータ、例えば特徴量記述子(FPFHとかSHOT等)では効果を発揮するかもしれない(予想)

読み込みについて

  • BinaryがASCIIに比べて約250倍速かった。
  • 圧縮版Binaryは通常Binaryの約2倍の時間がかかった。

まとめ

  • 基本的にはBinaryで保存すればいい。
    • pcl::PointXYZ や pcl::Normal 等
  • ただし特徴量に関しては圧縮版で保存するのもありかもしれない。
    • pcl::FPFHSignature33 や pcl::SHOT1344 等

(追記)

次の記事で、pcl::SHOT1344 の場合についても比較を行った。