[PCL] point単位での法線方向推定

PCLにおいて法線を推定する方法のうち,三つを紹介.

pcl::NormalEstimationクラスを使う

もっとも基本的な法線推定.遅い.距離画像には後述のIntegralImageNormalEstimationを使うほうが良い.

下記のようにヘッダをインクルードする必要あり.

#include <pcl/features/normal_3d.h>

pcl::NormaleEstimationOMPクラスを使う

OpenMPによる並列処理が行われること以外は,上のNormalEstimationクラスと互換.

下記のようにヘッダをインクルードする必要あり.

#include <pcl/features/normal_3d_omp.h>

pcl::IntegralImageNormalEstimationクラスを使う

距離画像(Kinectなどで取得可能)などのように,

ポイントクラウドにおいて点の並びが整列されているものに関しては,この法線推定クラスを使うのが最も高速.

下記のようにヘッダをインクルードする必要あり.

#include <pcl/features/integral_image_normal.h>

コードのサンプルはこちら.

    cv::Mat depth   // 距離画像.解像度320x240,Depthがushortで入っている例
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud ( new pcl::PointCloud<pcl::PointXYZ> );
    Vector4 point;
    cv::Mat pointMatProj( 3, 1, CV_64F );
    // 距離画像の解像度に合わせる
    cloud->width = depth.cols;
    cloud->height = depth.rows;
    cloud->points.resize( cloud->width * cloud->height );
    for( int y = 0; y < depth.rows; y++ ) {
        for( int x = 0; x < depth.cols; x++ ) {
            // 座標をSkeleton座標系に変換する.座標系はKinect座標系
            point = NuiTransformDepthImageToSkeleton( x, y, depth.at<ushort>( cv::Point( x, y ) ) );
            cloud->points[x + y * cloud->width].x = point.x;
            cloud->points[x + y * cloud->width].y = point.y;
            cloud->points[x + y * cloud->width].z = point.z;
        }
    }
    // 法線推定クラス
    pcl::IntegralImageNormalEstimation<pcl::PointXYZ, pcl::Normal>  ne;
    // 出力
    pcl::PointCloud<pcl::Normal>::Ptr cloud_normals( new pcl::PointCloud<pcl::Normal> );
    ne.setNormalEstimationMethod( ne.AVERAGE_DEPTH_CHANGE );
    ne.setMaxDepthChangeFactor( 0.01 );
    ne.setNormalSmoothingSize( 5.0 );   
    ne.setInputCloud( cloud );
    ne.compute( *cloud_normals );
...