2015年2月24日火曜日

各点の法線の計算とその法線の表示

 3次元の点郡を扱う上で重要になってくるのが各点が持つ法線である。3次元点郡を扱う研究では、頻繁にこの法線を使う。ものによってはこの法線情報のみを特徴として人間の検知をやってしまっている研究さえある。今回は入力された点郡の法線を取得して表示するプログラムを作る。
 今のところPCLのチュートリアルの機能を関数化したりしてるだけだが、ここで作った関数を後で切り貼りすると大きな機能を含んだプログラムを作るのが容易になるはず。

コード

#include "stdafx.h"

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/io/io.h>
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>

pcl::PointCloud<pcl::Normal>::Ptr surface_normals(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
    ne.setInputCloud (cloud);//法線の計算を行いたい点群を指定する

    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());//KDTREEを作る
    ne.setSearchMethod (tree);//検索方法にKDTREEを指定する

    pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);//法線情報を入れる変数

    ne.setRadiusSearch (0.005);//検索する半径を指定する

    ne.compute (*cloud_normals);//法線情報の出力先を指定する

    return cloud_normals;
}

int _tmain(int argc, _TCHAR* argv[])
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::io::loadPCDFile(argv[1], *cloud);

    surface_normals(cloud);

    std::stringstream Filename;
    std::string name;
    name = argv[1];
    name.erase(name.length()-4);
    Filename << name << "_normal.pcd";

    pcl::io::savePCDFileBinary(Filename.str() , *surface_normals(cloud));

    pcl::visualization::PCLVisualizer viewer ("3D Viewer");
    viewer.setBackgroundColor(1.0,0.5,1.0);
    viewer.addPointCloud<pcl::PointXYZ> (cloud, "Input cloud");
    viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,3,"Input cloud");
    viewer.addPointCloudNormals<pcl::PointXYZ,pcl::Normal>(cloud,surface_normals(cloud),10,0.05,"normals");

    while(!viewer.wasStopped())
    {
        viewer.spinOnce (100);
    }
    return (0); 
}



以前作ったViewerでは法線の表示はできないので今回は法線を表示できるViewerをつけている。
 この法線推定プログラムの処理にはそこそこの時間を要する、この理由は各点の周辺(指定した半径)の点の数から法線を求める処理を全ての入力点に対して行っているためである。なので処理を短くしたい場合は、点群の数を減らすなどの工夫が必要。

0 件のコメント:

コメントを投稿