引き続きPCL関連の記事を更新していきます。
本日は作成した点群をPCD形式のファイルとして保存し、保存した点群を読み込んで表示する部分を実装してみたいと思います。
読み込み部分のソースを使うことで、独自に入手したPCDファイルに関しても読み込んで確認ができるようになるので、これで様々なPCDファイルを用意すれば、それを対象に処理を行うことができるようになります。
PCLの環境構築や点群の作成については、以下の記事を参考にしてください。
過去記事①:Point Cloud Library(PCL) 1.8.1の環境構築
過去記事②:【PCL第1回】Point Cloud Library 1.8.1を用いた点群の作成と表示
PCDファイルの出力
前回の「【PCL第1回】Point Cloud Library 1.8.1を用いた点群の作成と表示」で作成したソースコードをベースに、そのときに作成した点群をPCDフォーマットとして出力してみます。ソースコードは以下となります。
#include <pcl/visualization/cloud_viewer.h> | |
#include <pcl/io/pcd_io.h> | |
#include <iostream> | |
using namespace std; | |
// ビューワー起動時の一回だけ呼ばれる | |
void viewerOneOff(pcl::visualization::PCLVisualizer& viewer) | |
{ | |
viewer.setBackgroundColor(0.2, 0.2, 0.2); | |
cout << "viewerOneOff" << std::endl; | |
} | |
// ビューワー起動中の毎フレーム実行される | |
void viewerPsycho(pcl::visualization::PCLVisualizer& viewer) | |
{ | |
cout << "viewerPsycho" << std::endl; | |
} | |
int main() | |
{ | |
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr p_cloud(new pcl::PointCloud<pcl::PointXYZRGBA>); | |
// PointCloudの大きさを決定 | |
p_cloud->width = 10; | |
p_cloud->height = 10; | |
p_cloud->points.resize(p_cloud->width * p_cloud->height); | |
cout << "Size : " << p_cloud->width * p_cloud->height << endl; | |
// 直接、値を入力してPointCloudを作成 | |
for (int h = 0; h < p_cloud->height; h++) { | |
for (int w = 0; w < p_cloud->width; w++) { | |
pcl::PointXYZRGBA &point = p_cloud->points[w + h * p_cloud->width]; | |
point.x = w * 0.1; | |
point.y = h * 0.1; | |
point.z = 0.0; | |
point.r = 255; | |
point.g = 0; | |
point.b = 0; | |
point.a = 0; | |
} | |
} | |
// 作成したPointCloudをPCD形式で保存する | |
cout << "savePCDFileASCII" << endl; | |
pcl::io::savePCDFileASCII("p_cloud_ascii.pcd", *p_cloud); // テキスト形式で保存する | |
cout << "savePCDFileBinary" << endl; | |
pcl::io::savePCDFileBinary("p_cloud_binary.pcd", *p_cloud); // バイナリ形式で保存する | |
// ビューワーの作成 | |
pcl::visualization::CloudViewer viewer("PointCloudViewer"); | |
viewer.showCloud(p_cloud); | |
// ビューワー起動時の一回だけ呼ばれる関数をセット | |
viewer.runOnVisualizationThreadOnce(viewerOneOff); | |
// ビューワー起動中の毎フレーム実行される関数をセット | |
viewer.runOnVisualizationThread(viewerPsycho); | |
// ビューワー視聴用ループ | |
while (!viewer.wasStopped()) | |
{ | |
} | |
return 0; | |
} |
前回からソースコードに加えた変更点は、以下のヘッダを加えたことと、
#include <pcl/io/pcd_io.h>
以下のソースコードを加えました。
// 作成したPointCloudをPCD形式で保存する cout << "savePCDFileASCII" << endl; pcl::io::savePCDFileASCII("p_cloud_ascii.pcd", *p_cloud); // テキスト形式で保存する cout << "savePCDFileBinary" << endl; pcl::io::savePCDFileBinary("p_cloud_binary.pcd", *p_cloud); // バイナリ形式で保存する
savePCDFileASCII関数により、テキスト形式のPCDファイルを吐き出すことができます。一方、savePCDFileBinary関数を用いることでバイナリ形式でPCDファイルを吐き出すことができます。
両方記述する必要はないので、どちらかで出力をすればよいでしょう。
テキスト形式であればメモ帳などのファイルでPCDファイルの中を見ることができます。
一方、バイナリの場合は中身は読めませんが、データサイズを比較的軽量に、かつ高速に保存することができます。実用的な利用を考える場合は後者の方が良いかもしれません。
PCDファイルの入力
次に、入力側のソースコードを記載します。
#include <pcl/visualization/cloud_viewer.h> | |
#include <pcl/io/pcd_io.h> | |
#include <iostream> | |
using namespace std; | |
// ビューワー起動時の一回だけ呼ばれる | |
void viewerOneOff(pcl::visualization::PCLVisualizer& viewer) | |
{ | |
viewer.setBackgroundColor(0.2, 0.2, 0.2); | |
cout << "viewerOneOff" << std::endl; | |
} | |
// ビューワー起動中の毎フレーム実行される | |
void viewerPsycho(pcl::visualization::PCLVisualizer& viewer) | |
{ | |
cout << "viewerPsycho" << std::endl; | |
} | |
int main() | |
{ | |
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr p_cloud(new pcl::PointCloud<pcl::PointXYZRGBA>); | |
// 作成したPointCloudを読み込む | |
// pcl::io::loadPCDFile("p_cloud_ascii.pcd", *p_cloud); | |
pcl::io::loadPCDFile("p_cloud_binary.pcd", *p_cloud); | |
// ビューワーの作成 | |
pcl::visualization::CloudViewer viewer("PointCloudViewer"); | |
viewer.showCloud(p_cloud); | |
// ビューワー起動時の一回だけ呼ばれる関数をセット | |
viewer.runOnVisualizationThreadOnce(viewerOneOff); | |
// ビューワー起動中の毎フレーム実行される関数をセット | |
viewer.runOnVisualizationThread(viewerPsycho); | |
// ビューワー視聴用ループ | |
while (!viewer.wasStopped()) | |
{ | |
} | |
return 0; | |
} |
loadPCDFile関数でテキスト形式、バイナリ形式の双方共に読み込むことができます。基本的にはそれだけで読み込みができるため、非常に簡便です。
// 作成したPointCloudを読み込む // pcl::io::loadPCDFile("p_cloud_ascii.pcd", *p_cloud); pcl::io::loadPCDFile("p_cloud_binary.pcd", *p_cloud);
PCDファイルの中身
前述の通り、テキストファイルであればPCDファイルの中身を見ることができます。以下のように、非常に分かりやすい構造をしています。
DATA ascii以降に並ぶ四つの数字は「x y z rgba」を示しています。ポイントとしては、RGBAを一つの数字として記述している点です。
どうも試した限りですが、ここのRGBAの値は、
256*256*256*A + 256*256*R + 256*G+ B
という計算式で示されるようです。
基本的に、上記関数を使っている限りはあまり上の計算式を意識する必要はない気がしますが、参考情報まで。
まとめ
PCDファイルの入力と出力についてのコードを理解することで、PCLで処理した後の点群などを一時的にPCD形式で保存することができるようになりました。
次回は点群に対して、何らかの処理を施してみたいと思います。