続・PCDファイルの保存読込速度・サイズ比較
1つ前の記事で、点群データ(pcl::PointXYZ)に関して保存読込速度とサイズ比較をした。
最後のまとめで、特徴量記述子については違う結果になるかもと予想したが、せっかくなので今回実際に比較してみた。
続きを読むPCDファイルの保存読込速度・サイズ比較
ポイントクラウドの保存関数(PCD形式)は下記の3通りがある。
- pcl::io::savePCDFileASCII
- 全部テキスト形式で保存
- pcl::io::savePCDFileBinary
- ヘッダはテキスト形式で、データ部分はバイナリ形式で保存
- pcl::io::savePCDFileBinaryCompressed
- ヘッダはテキスト形式で、データ部分はLZF形式で圧縮保存
- LZF形式は圧縮率は低いが圧縮・展開が高速らしい
ちなみに pcl::io::savePCDFile という関数もあるが、この関数では引数でASCIIかBinaryかを選択する。何も指定しないとASCIIになる。
読込に関してはどの形式で保存してもすべて pcl::io::loadPCDFile という関数で可能。
保存読込速度・ファイルサイズ比較
以上の3つの方法について、保存・読込速度とファイルサイズを下記のコードで比較した。
PCL1.7.2で一部のライブラリがエラーLNK1189でビルドできない問題の対処
PCLのビルド中にpcl_featureについては下記のようなエラーメッセージが出て使えなくなってしまった。
fatal error LNK1189: オブジェクトまたはメンバーの数がライブラリの最大許容数 65535 を超えています。
調べたところ下記のページが見つかった。被害者の共通点は Visual Studio を使っていること。
- Link error 1189 library limit of 65535 objects exceeded · Issue #833 · PointCloudLibrary/pcl · GitHub
- Point Cloud Library (PCL) Users mailing list - PCL Features Library Limit Exceeded
Visual Studio のコンパイラはライブラリ内のメンバー数に制限を課しているそう。
この問題を回避するには『PCLビルド時の PCL_ONLY_CORE_POINT_TYPES をONにして、pcl_featureのメンバーを減らす』しか方法がないそう。
ただし、これを行うとpcl::PointNormal等の一部のポイントタイプが、今まで通りには使えなくなる。
というわけで、以下では
- LNK1189エラーの解消方法
- 今まで通りにポイントタイプを使うための方法
をメモ。
LNK1189エラーの解消方法
- cmake-gui で PCL_ONLY_CORE_POINT_TYPES を ON にする
- Configure を押す
- Generate を押す
- 生成された PCL.sln を開いて ALL_BUILD する
- クリーン・リビルドする必要はなく、単純にビルドでよい
今まで通りにポイントタイプを使うための方法
- 今まで作ったプロジェクトに PCL_NO_PRECOMPILE マクロを定義する
CMakeLists.txt内に書いておきたい場合:
add_definitions(-DPCL_NO_PRECOMPILE)
ソースファイル内に書いておきたい場合:
#define PCL_NO_PRECOMPILE
動作確認
下記のコードの PointT, NormalT の typedef を自分が使いたいポイントタイプに書き換えて、1,2行目のコメントを入れ替えて実行してみる。
pcl::PointCloudやEigenを含むvectorをresizeするとエラーが発生する場合の対処
C++行列演算ライブラリ「Eigen」を含む構造体などのstd::vectorは、下記のページで説明されているような工夫が必要となる。
Eigen: Using STL Containers with Eigen
例えばこんなコードが書ける。
#include <vector> #include <Eigen/Core> #include <Eigen/StdVector> struct Hoge { Eigen::Vector4f v; EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; void main() { std::vector<Hoge, Eigen::aligned_allocator<Eigen::Vector4f>> hoges; hoges.resize(4); }
だが、Visual Studio 2010またはそれ以前のバージョンのIDEを使用していると、上記コードではvectorのresizeをすると、コンパイル時に次のようなエラーが発生する。
3>c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector(870): error C2719: '_Val': __declspec(align('16')) の仮引数は配置されません。
そのような場合の対処方法。PCLの Users mailing list ではVSのC++のvectorインクルードファイルを次のように修正すればよいと書かれていた。
I solved this issue by changing the signature of resize() funtion from Microsoft Visual Studio 10.0/VC/include/vector like this:
from:
void resize(size_type _Newsize, _Ty _Val)to:
void resize(size_type _Newsize, _Ty &_Val)Hope this helps!
http://www.pcl-users.org/point-cloud-h-alignment-issue-td4021525.html
ただ、個人的には編集可能な状態で渡すのは気持ち悪いので下記のように変更した。これでもちゃんと動作する。
void resize(size_type _Newsize, const _Ty &_Val)
ちなみに Visual Studio 2013 のvectorファイルを見てみたが下記のように書かれていたので、上記の問題は起こらないと思う。
void resize(size_type _Newsize, const value_type& _Val)
VeloViewで出力した点群データ(CSV)をPCLで読み込む
Velodyne社のLIDAR「HDL-32e」や「HDL-64e」用のViewerにVeloViewというものがあります。VeloViewでは点群データをCSV形式でエクスポートできます。そのCSVデータをpcl::PointCloudとして読み込むコードのメモ。
CSVデータの1行目は、カラム名が出力されていて下記のようになっています。
- Points:0
- Points:1
- Points:2
- intensity
- laser_id
- azimuth
- distance_m
- timestamp
今回のコードはpcl::PointXYZIの形式で、intensityにはレーザの反射強度が入ります。
#include <fstream> #include <pcl/pcl_base.h> #include <pcl/point_cloud.h> int loadPointCloudFromCSV(const std::string &file_path, pcl::PointCloud<pcl::PointXYZI> &cloud) { std::ifstream ifs(file_path, std::ios::in); if(!ifs) return 1; // File open failed std::string buf; std::getline(ifs, buf); // Skip first line ("Points:0","Points:1","Points:2","intensity","laser_id","azimuth","distance_m","timestamp") while(ifs && std::getline(ifs, buf)) { std::vector<std::string> v; boost::algorithm::split(v, buf, boost::is_any_of(",")); if(v.size() < 4) continue; pcl::PointXYZI p; p.x = std::atof(v[0].c_str()); p.y = std::atof(v[1].c_str()); p.z = std::atof(v[2].c_str()); p.intensity = std::atof(v[3].c_str()); cloud.push_back(p); } return 0; }
PCLVisualizerでポイントクラウドの透明度を反映させて描画する方法
pcl::PointXYZRGBAというタイプのポイントクラウドを作り、アルファ値(a)を0にしてもPCLVisualizerで透明にならないなぁと思っていたのですが、カラーハンドラーを設定すればちゃんと透明度に合わせて描画されることに気づきました。
以下、サンプル
#include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/visualization/pcl_visualizer.h> int main(int argc, char** argv) { pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGBA>); // 適当なポイントクラウドを作成 cloud->width = 256; cloud->height = 128; cloud->points.resize (cloud->width * cloud->height); for(int i = 0, y = 0; y < cloud->height; y++) { for(int x = 0; x < cloud->width; x++, i++) { pcl::PointXYZRGBA &p = cloud->points[i]; p.x = x; p.y = y; p.z = 0.0; p.r = 255; p.g = static_cast<float>(y) / cloud->height * 255; p.b = 0; p.a = static_cast<float>(x) / cloud->width * 255; } } // 表示 int vp[2]; pcl::visualization::PCLVisualizer viewer("Viewer"); pcl::visualization::PointCloudColorHandlerRGBAField<pcl::PointXYZRGBA> rgba(cloud); viewer.createViewPort(0.0, 0.0, 0.5, 1.0, vp[0]); viewer.createViewPort(0.5, 0.0, 1.0, 1.0, vp[1]); viewer.addPointCloud(cloud, "cloud_without_color_handler", vp[0]); // 透明度が反映されない viewer.addPointCloud(cloud, rgba, "cloud_with_color_handler", vp[1]); // 透明度が反映される viewer.addText("Without color handler", 10, 10, "text_without_color_handler", vp[0]); viewer.addText("With color handler", 10, 10, "text_with_color_handler", vp[1]); viewer.spin(); return 0; }
実行したときの画像がこちら