PCL
- 4. PCLの紹介
• Point Cloud Library
– 点群(ポントクラウド)処理のためのラ
ブラリ
• PCL開発チーム
– スポンサー:Willow Garage, NVidia, Google,
Toyota, Trimble, Urban Robotics.
4
- 7. どんなことができるか
• filters
• features
• keypoints
• registration
• kdtree
• octree
• segmentation
• sample_consensus
• surface
• range_data
• io
• visualization
7
- 23. PCLの仕様
• プログラミング言語:C++
• 対応OS:Windows、MacOS、Linux
• ラセンス:BSD
• 公式サト:
– http://pointclouds.org/
23
- 27. 導入
• 今回は64bit 、Visual Studio 2010を対象
• 最新版:PCL 1.4.0(2012/1/1)
• ンストーラで関連するラブラリを一
括でンストール可能
– OpenNIだけは別途ンストール
• デフォルトのンストールデゖレクトリ
– C:¥Program files¥PCL1.4.0
27
- 28. 関連するラブラリ
• Boost:C++準標準ラブラリ
– スマートポンタ、関数オブジェクト、ス
レッド、シグナルなど
• VTK:GUIツールキット
• Eigen:行列ラブラリ
• FLANN:最近傍探索ラブラリ
• qHull:凸包、三角面化、ドロネー分割
• OpenNI:Kinect
28
- 29. ンクルードパス
• C:¥Program files¥PCL1.4.0¥include¥pcl-1.4
• C:¥Program files¥PCL1.4.0¥3rdParty¥Boost¥include
• C:¥Program files¥PCL1.4.0¥3rdParty¥Eigen¥include
• C:¥Program files¥PCL1.4.0¥3rdParty¥flann¥include
• C:¥Program files¥PCL1.4.0¥3rdParty¥qhull¥include
• C:¥Program files¥PCL1.4.0¥3rdParty¥VTK 5.8.0¥include¥vtk-5.8
• C:¥Program files¥OpenNI¥include
29
- 30. ラブラリパス
• C:¥Program files¥PCL1.4.0¥lib
• C:¥Program files¥PCL1.4.0¥3rdParty¥Boost¥lib
• C:¥Program files¥PCL1.4.0¥3rdParty¥flann¥lib
• C:¥Program files¥PCL1.4.0¥3rdParty¥qhull¥lib
• C:¥Program files¥PCL1.4.0¥3rdParty¥VTK 5.8.0¥lib¥vtk-5.8
• C:¥Program files¥OpenNI¥lib
30
- 31. リンクするラブラリ(Release版)
pcl_common.lib openNI64.lib vtkIO.lib
pcl_features.lib OpenNI.jni64.lib vtkjpeg.lib
pcl_filters.lib NiSampleModule64.lib vtklibxml2.lib
pcl_io.lib NiSampleExtensionModule64.lib vtkmetaio.lib
pcl_kdtree.lib MapReduceMPI.lib vtkNetCDF.lib
pcl_keypoints.lib mpistubs.lib vtkNetCDF_cxx.lib
pcl_octree.lib vtkalglib.lib vtkpng.lib
pcl_range_image.lib vtkCharts.lib vtkproj4.lib
pcl_range_image_border_extractor.lib vtkCommon.lib vtkRendering.lib
pcl_registration.lib vtkDICOMParser.lib vtksqlite.lib
pcl_sample_consensus.lib vtkexoIIc.lib vtksys.lib
pcl_segmentation.lib vtkexpat.lib vtktiff.lib
pcl_surface.lib vtkFiltering.lib vtkverdict.lib
pcl_visualization.lib vtkfreetype.lib vtkViews.lib
flann.lib vtkftgl.lib vtkVolumeRendering.lib
flann_s.lib vtkGenericFiltering.lib vtkWidgets.lib
flann_cpp_s.lib vtkGeovis.lib vtkzlib.lib
qhull6.lib vtkGraphics.lib opengl32.lib
qhullcpp.lib vtkHybrid.lib
qhullstatic.lib vtkImaging.lib
qhullstatic_p.lib vtkInfovis.lib
31
- 35. サンプルコード
int main()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr data( new pcl::PointCloud<pcl::PointXYZ>() );
pcl::io::loadPCDFile( “filename.pcd", *data );
pcl::visualization::CloudViewer *viewer = new pcl::visualization::CloudViewer( “Sample" );
viewer->showCloud( cloud_filtered );
while( !viewer->wasStopped() )
{
boost::this_thread::sleep (boost::posix_time::microseconds (100000));
}
return 0;
}
35
- 36. 点群データ
pcl::PointCloud< PointT >::Ptr cloud( new PointCloud< PointT >() );
点群データクラス スマートポンタ
PointT:点の型
pcl::PointXYZ :位置
pcl::PointXYZI :位置+輝度
pcl::PointXYZRGB :位置+輝度(RGB)
pcl::PointNormal :位置+法線
・・・
36
- 37. スマートポンタ
• pcl::PointCloud< PointT >::Ptr
• pcl::PointCloud< PointT >::ConstPtr
– 中身はboost::shared_ptr
• 通常のポンタ
– newしたら必ずdeleteする必要がある
• スマートポンタ
– deleteをスマートポンタが担当
37
- 43. Viewerの操作方法
• 左ドラッグ:視点の回転
• Shift+左ドラッグ:視点の平行移動
• Ctrl+左ドラッグ:画面上の回転
• 右ドラッグ:ズーム
• g:メジャーの表示
• j:スクリーンショットの保存
43
- 45. pcl::visualization::PCLVisualizer
pcl::visualization::PCLVisualizer *viewer = new pcl::visualization::PCLVisualizer();
viewer->setBackgroundColor (0, 0, 0);
viewer->addCoordinateSystem (0.1);
viewer->initCameraParameters ();
viewer->addPointCloud( cloud );
while( !viewer->wasStopped() )
{
viewer->spinOnce();
boost::this_thread::sleep (boost::posix_time::microseconds( 100000 ) );
}
45
- 46. 点群の作成
• テスト用などに点群を作成したい場合
pcl::PointCloud< PointT >::Ptr cloud( new PointCloud< PointT >() );
for( int i = 0 ; i < 10000 ; ++i )
{
// PointT = PointXYZの場合
PointXYZ point;
point.x = rand();
point.y = rand();
point.z = rand();
cloud->points.push_back( point );
}
cloud->width = cloud->points.size();
cloud->height = 1; 46
- 47. boost::random
• C標準のrand関数は線形合同法
– 高次元で乱数に周期が発生
• 任意の乱数生成器、分布を設定可能
boost::mt19937 gen( static_cast<unsigned long>(time(0)) );
boost::uniform_real<> dst( -0.1, 0.1 );
boost::variate_generator< boost::mt19937&, boost::uniform_real<> > rand( gen, dst );
// 乱数生成
rand()
47
- 48. Kinectからの入力
• 内部でOpenNIを利用
pcl::Grabber* interface = new pcl::OpenNIGrabber();
boost::function<void (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr&)> func =
boost::bind ( capture, _1);
interface->registerCallback ( func );
interface->start ();
while (!viewer.wasStopped())
{
sleep (1);
}
interface->stop ();
コールバック関数
void capture(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &cloud )
{
viewer.showCloud( cloud );
}
48
- 49. 無効値の除去
• Kinectからの入力には、NaNが含まれる
– NaNが存在すると、レジストレーションなど
の結果がおかしくなる
pcl::PassThrough<pcl::PointXYZRGB> pass;
pass.setInputCloud( input );
pass.filter( output );
pass.setFilterLimits( 0.0, 1.0 )とすることで、特定の範囲に制限することも可能
49
- 55. 平面フゖッテゖング
pcl::SACSegmentation< pcl::PointXYZ > seg;
seg.setInputCloud ( data );
seg.setOptimizeCoefficients ( true );
seg.setModelType ( pcl::SACMODEL_PLANE );
seg.setMethodType ( pcl::SAC_RANSAC );
seg.setDistanceThreshold ( 0.02 );
pcl::ModelCoefficients::Ptr coefficients ( new pcl::ModelCoefficients() );
pcl::PointIndices::Ptr inliers ( new pcl::PointIndices() );
seg.segment ( *inliers, *coefficients );
55
- 58. クラスタリング
pcl::PointCloud< pcl::PointXYZRGB >::Ptr tmp( new pcl::PointCloud< pcl::PointXYZRGB >() );
pcl::PointCloud< pcl::PointXYZRGB >::Ptr segmented( new pcl::PointCloud< pcl::PointXYZRGB >() );
removePlanar( cloud, tmp );
removePlanar( tmp, segmented );
pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>);
tree->setInputCloud (segmented);
std::vector< pcl::PointIndices > cluster_indices;
pcl::EuclideanClusterExtraction<pcl::PointXYZRGB> clustering;
clustering.setClusterTolerance( 0.03 );
clustering.setMinClusterSize( 1000 );
clustering.setMaxClusterSize( 300000 );
clustering.setSearchMethod( tree );
clustering.setInputCloud( segmented );
clustering.extract( cluster_indices );
58
- 59. 対象領域の抽出
pcl::ExtractIndices< pcl::PointXYZRGB > extract;
extract.setInputCloud( segmented );
pcl::IndicesPtr indices (new std::vector<int>);
*indices = cluster_indices[0].indices;
extract.setIndices( indices );
extract.setNegative( false );
extract.filter( *result );
59
- 63. 特徴点検出
• SIFT特徴点検出
pcl::SIFTKeypoint<pcl::PointXYZRGB, pcl::PointXYZI> sift3D;
sift3D.setScales( 0.01, 3, 2 );
sift3D.setMinimumContrast( 0.0 );
pcl::PointCloud<pcl::PointXYZI>::Ptr keypoints( new pcl::PointCloud<pcl::PointXYZI>() );
sift3D.setInputCloud( cloud );
sift3D.compute(*keypoints);
63
- 65. 特徴量抽出
• キーポント周辺からFPFHを算出
• FPFHを算出するためには、点の法線が必要
– 法線の算出法は、後のスラドで説明
pcl::Feature<pcl::PointXYZRGB, pcl::FPFHSignature33> feature_extractor ;
feature_extractor.setSearchMethod( pcl::search::Search<pcl::PointXYZRGB>::Ptr( new
pcl::search::KdTree<pcl::PointXYZRGB>() ) );
feature_extractor.setRadiusSearch( 0.05 );
pcl::PointCloud<pcl::PointXYZRGB>::Ptr kpts(new pcl::PointCloud<pcl::PointXYZRGB>);
kpts.points.resize(keypoints->points.size());
pcl::copyPointCloud(*keypoints, *kpts);
feature_from_normals->setInputNormals( normals );
pcl::PointCloud<pcl::FPFHSignature33>::Ptr features( new pcl::PointCloud<pcl::FPFHSignature33>() );
feature_extractor->compute (*features);
65
- 66. 初期対応付け
• 点群1 -> 点群2の対応付けを算出
• 点群2 -> 点群1の対応付けを算出
• 以上2つ対応付けのうち、共通する対応の
みを取得
66
- 67. 初期対応付け
• 点群1から点群2への対応を計算
– 反対も計算
correspondences.resize(source->size() );
pcl::KdTreeFLANN<FeatureType> descriptor_kdtree;
descriptor_kdtree.setInputCloud ( cloud2 );
const int k = 1;
std::vector<int> k_indices (k);
std::vector<float> k_squared_distances (k);
for (size_t i = 0; i < source->size (); ++i)
{
descriptor_kdtree.nearestKSearch (*cloud1, i, k, k_indices, k_squared_distances);
correspondences[i] = k_indices[0];
}
67
- 68. 初期対応付け
• 両方向に共通する対応のみを残す
– RANSACを行うことにより、一部の対応を除去
std::vector<std::pair<unsigned, unsigned> > c;
for (unsigned cIdx = 0; cIdx < c1.size (); ++cIdx)
{
if ( c2[c1[cIdx]] == cIdx)
{
c.push_back( std::make_pair( cIdx, c1[cIdx] ) );
}
}
correspondences->resize( c.size());
for (unsigned cIdx = 0; cIdx < c.size(); ++cIdx)
{
(*correspondences)[cIdx].index_query = c[cIdx].first;
(*correspondences)[cIdx].index_match = c[cIdx].second;
}
pcl::registration::CorrespondenceRejectorSampleConsensus<pcl::PointXYZI> rejector;
rejector.setInputCloud( keypoints1 );
rejector.setTargetCloud( keypoints2 );
rejector.setInputCorrespondences( correspondences );
rejector.getCorrespondences( *correspondences ); 68
- 69. 初期対応付け
• 2つの点群間の幾何関係を計算
pcl::registration::TransformationEstimation<pcl::PointXYZI, pcl::PointXYZI>::Ptr
transformation_estimation(new pcl::registration::TransformationEstimationSVD<pcl::PointXYZI,
pcl::PointXYZI>);
Eigen::Matrix4f initial_transformation_matrix_;
transformation_estimation->estimateRigidTransformation( *keypoints1, *keypoints2,
*correspondences, initial_transformation_matrix_);
pcl::transformPointCloud( *cloud1, *transformed1, initial_transformation_matrix_);
69
- 74. 点群の削減(ダウンサンプリング)
• VoxelGridによる削減手法
– 点間の距離が一定以上になるように削減
pcl::VoxelGrid< pcl::PointXYZ > vg;
vg.setInputCloud( cloud );
vg.setLeafSize( 0.01f, 0.01f, 0.01f );
vg.setDownsampleAllData(true);
vg.filter( *cloud_filtered );
他に、pcl::ApproximateVoxelGridがある
74
- 77. 法線計算
• 任意の点中心から一定の範囲の点群を用
いて法線方向を算出
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud (data);
pcl::search::KdTree<pcl::PointXYZ >::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ > ());
ne.setSearchMethod (tree);
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);
ne.setRadiusSearch (1.0);
ne.compute( *normals );
77
- 78. 法線の表示
• pcl::visualization::PCLVisualizerを利用
pcl::visualization::PCLVisualizer> viewer ("3D Viewer");
viewer.setBackgroundColor (0, 0, 0);
viewer.addPointCloud<pcl::PointXY> (cloud, "sample cloud");
viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");
viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal> (cloud, normals, 10, 0.05, "normals");
viewer.addCoordinateSystem (1.0);
viewer.initCameraParameters ();
78
- 79. 法線付き点群の計算
• 点群(位置)と点群(法線)をまとめて、
一つの点群(位置+法線)に変換
位置 法線 位置+法線
位置 法線 位置+法線
位置
+ 法線 位置+法線
位置 法線 位置+法線
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals (new pcl::PointCloud<pcl::PointNormal>);
pcl::concatenateFields (*cloud, *normals, *cloud_with_normals);
79