2015年2月25日水曜日

点群の数を減少させる

 法線の推定などは入力された点群データの全ての点について、一定範囲内の近隣の点を探し、それらを基に法線を推定していた。この処理は点の数が多いほど時間が増大する。Kinectを使用する場合だと得られる点群の数が理論上307200個なので膨大な時間を要し、リアルタイムに処理を行う必要がある場面では、なにかしらの前処理を行って、点群の数を減らす必要がある。
  PCLではダウンサンプリングと呼ばれる手法が用いられる。このダウンサンプリングは一定の範囲内にある点の中心に新たな点を配し、それ以外の点は全て削除する機能である。ちなみにこのダウンサンプリングの正式な名前はVoxelGridFilterという。点群の密度は状況によって大きく変わるのでここでは点群情報の体積から範囲を決定する。

コード

#include "stdafx.h"

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/io/io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>

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

    double max_height = 0, max_width = 0, max_length = 0;
    double min_height = 0, min_width = 0, min_length = 0;
    double height = 0, width = 0, length = 0;

    for(size_t i = 0; i < cloud->points.size(); i++){//入力点群の縦横高さの最大値と最小値を計算する
        if(max_height > cloud->points[i].z)
            max_height = max_height;
        else
            max_height = cloud->points[i].z;

        if(max_width > cloud->points[i].y)
            max_width = max_width;
        else
            max_width = cloud->points[i].y;

        if(max_length > cloud->points[i].x)
            max_length = max_length;
        else
            max_length = cloud->points[i].x;

        if(min_height < cloud->points[i].z)
            min_height = min_height;
        else
            min_height = cloud->points[i].z;

        if(min_width < cloud->points[i].y)
            min_width = min_width;
        else
            min_width = cloud->points[i].y;

        if(min_length < cloud->points[i].x)
            min_length = min_length;
        else
            min_length = cloud->points[i].x;

    }

    height = fabs(max_height) + fabs(min_height);
    width = fabs(max_width) + fabs(min_width);
    length = fabs(max_length) + fabs(min_length);

    double model_volume = 0, voxel_volume, voxel_length = 0;
    model_volume = height * width * length;
    voxel_volume = model_volume / 150000;

    voxel_length = pow(voxel_volume, 1.0 / 3.0);

    pcl::VoxelGrid<pcl::PointXYZ> sor;
    sor.setInputCloud (cloud);
    //sor.setLeafSize (0.01f, 0.01f, 0.01f);
    sor.setLeafSize(voxel_length, voxel_length, voxel_length);
    sor.filter (*cloud_filtered);

    return *cloud_filtered;
}

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

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

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

    return (0); 
}


実行結果




 このプログラムによって点群の数を減らし、処理速度の向上などを見込む事ができる。しかし、この処理はPassThroughFilterと同様、点が有用であるかどうか問わずに削除を行うので注意が必要。もしそれが嫌だったら高機能なコンピュータを容易するかGPUに処理を手伝わせるなどする必要がある。自分はGPUに処理の一部を投げる方法はまだ知らない。

0 件のコメント:

コメントを投稿