川崎ロボティクス

個人的なお勉強の備忘録です。

PCL(Point Cloud Library)のまとめ

はじめに

最近、3次元点群を扱うことが増えてきました。 今までまったく使ったことないので結構、苦戦しました。 なので、忘れないようにまとめていこうと思います。
使用環境はUbuntu16.04、使用言語はC++です。

目次

点群オブジェクトの宣言

型の種類

点群を扱うために変数を宣言する必要があります。 今回は例として、cloudという変数を宣言します。

pcl::PointCloud<pcl::PointXYZ> cloud;
pcl::PointCloud<pcl::PointXYZRGB> cloud;
pcl::PointCloud<pcl::PointXYZI> cloud;

上記のように様々な型の宣言があり、扱う点群の種類よって変える必要があります。 <pcl::PointXYZ>型は、点群の位置情報(XYZ)。
<pcl::PointXYZRGB>型は、点群の位置情報(XYZ)と色の情報(RGB)。
<pcl::PointXYZI>型は、点群の位置情報(XYZ)と輝度値。

qiita.com

宣言の種類

色々調べているとサンプルによっては宣言の仕方が、

pcl::PointCloud<pcl::PointXYZ> cloud;
pcl::PointCloud<pcl::PointXYZ> Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

など様々あり、どれが正しいのかわからなくなりました。 実際はどっちを使ってもコンパイルは通りますが、要素のアクセスの仕方や関数の引数の記述方法が異なります。 じゃあ、どっちを使えば良いのかという疑問がありますよね。

pcl::PointCloud<pcl::PointXYZ> Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

上記はスマートポインタを使用した点群オブジェクトの宣言方法になります。 点群はかなり大きいデータになるので、オブジェクトをディープコピーするとメモリを浪費してしまいます。 この問題を避けるのが、スマートポインタを用いた宣言の仕方です。 なので、PCLで扱う多くの関数の引数はスマートポインタを取るようになっています。

pcl::PointCloud<pcl::PointXYZ> cloud;

上記はスマートポインタを使用してない生の点群オブジェクトを宣言しています。 使えないわけでもないですが、関数の引数でこの宣言方法だと使えないものがいくつかあったので注意が必要です。

blog.innovotion.co.jp

サンプルコード

今回は長方形の点群を生成し、PCDファイルを保存します。 上記で述べた2通りの宣言方法で記述します。

  • スマートポインタを使用しない宣言
#include <pcl_conversions/pcl_conversions.h>
#include <iostream>

using namespace std;

int main(int argc, char **argv){
    double x;
    double y;

    //型の宣言
    pcl::PointCloud<pcl::PointXYZ> cloud;

    //点群の大きさを指定
    cloud.width = 5000;
    cloud.height = 1;
    cloud.points.resize(cloud.width * cloud.height);

    //点群の生成
    for(int i = 0 ; i < cloud.points.size() ; i++)
    {
        x = 3.0*rand() / (RAND_MAX + 1.0f);
        y = 1.0*rand() / (RAND_MAX + 1.0f);
        cloud.points[i].x = x;
        cloud.points[i].y = y;
        cloud.points[i].z = 1.0*rand() / (RAND_MAX + 1.0f);
    }
 
    //PCDファイルの出力
    pcl::io::savePCDFile('cloud',cloud);

    return 0;
}
  • スマートポインタを使用する宣言
#include <pcl_conversions/pcl_conversions.h>
#include <iostream>

using namespace std;

int main(int argc, char **argv){
    double x;
    double y;

    //型の宣言
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

    //点群の大きさを指定
    cloud->width = 5000;
    cloud->height = 1;
    cloud->points.resize(cloud->width * cloud->height);

    //点群の生成
    for(int i = 0 ; i < cloud->points.size() ; i++)
    {
        x = 3.0*rand() / (RAND_MAX + 1.0f);
        y = 1.0*rand() / (RAND_MAX + 1.0f);
        cloud->points[i].x = x;
        cloud->points[i].y = y;
        cloud->points[i].z = 1.0*rand() / (RAND_MAX + 1.0f);
    }

    //PCDファイルの出力
    pcl::io::savePCDFile('cloud',*cloud_pcl);
    
    return 0;
}