공간에 존재 하는 물체들은 특정한 형태를 가지고 있습니다. 사람과 같이 복잡한 형태도 있지만 바닥(평면), 전봇대(원통), 간판(사각형), 전선(선) 등 간단한 형태도 있습니다. 본문에서는 점군속에 포함된 포형을 탐지 하는 법을 살펴 보겠습니다. 탐지 결과는 후에 배우는 세그멘테이션과 연계 하여 불필요한 부분을 제거하거나, 필요한 부분만 추출 할 때 사용 됩니다.
3.1.1. Sample Consensus
Sample Consensus는 포인트 클라우드 샘플(Sample)이 사전에 정의된 모형(=모델)과 일치(Consensus)하는지를 판악하여 모델의 파라미터를 추정하는 알고리즘 입니다. 간단한 형태의 도형들은 수학적으로 모델링이 가능합니다. 예를 들어 선의 경우 y=ax+b로 표현 가능합니다. 원의 경우 xxxx로 표현 가능합니다. 수학적 모델을 통해서 점군상에 존재 하는 모형을 찾는데는 허프만 변환과 sample_consensus 방법이 적용 가능합니다. 허프만 변환은 알고리즘이 간단하여 속도가 빠른 장점이 있지만, 잡음이 섞여 있는 데이터에는 적합 하지 않아 sample_consensus 방법을 많이 사용합니다.
PCL에서 구현되어 있는 sample consensus estimators 은 아래와 같습니다.
SAC_RANSAC - RANdom SAmple Consensus
SAC_LMEDS - Least Median of Squares
SAC_MSAC - M-Estimator SAmple Consensus
SAC_RRANSAC - Randomized RANSAC
SAC_RMSAC - Randomized MSAC
SAC_MLESAC - Maximum LikeLihood Estimation SAmple Consensus
SAC_PROSAC - PROgressive SAmple Consensus
PCL에서 제공하는 모형을 표로 정리 하면 아래와 같습니다.
모델 중에서 면을 이용하여 바닥과 벽을 탐지 할 수 있으며, 원통을 이용하여 컵, 기둥, 배관 등을 탐지 할 수 있습니다.
3.1.2 RANSAC(RANdom SAmple Consensus)
RANSAC은 속도는 느리지만 잡음에 강건한 성질을 가지고 있습니다.
#include<iostream>#include<pcl/io/pcd_io.h>#include<pcl/point_types.h>#include<pcl/filters/model_outlier_removal.h>// Filtering a PointCloud using ModelOutlierRemoval// http://pointclouds.org/documentation/tutorials/model_outlier_removal.php#model-outlier-removalintmain (){ // *.PCD 파일 읽기 // https://github.com/adioshun/gitBook_Tutorial_PCL/blob/master/Intermediate/sample/sphere_pointcloud_with_noise.pcd pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile <pcl::PointXYZ> ("sphere_pointcloud_with_noise.pcd",*cloud); // 포인트수 출력 std::cout <<"Loaded :"<<cloud->width *cloud->height << std::endl; std::cerr <<"Cloud before filtering: "<< std::endl;for (std::size_t i =0; i <cloud->points.size (); ++i) std::cout <<" "<<cloud->points[i].x <<" "<<cloud->points[i].y <<" "<<cloud->points[i].z << std::endl; // 2. filter sphere: // 2.1 generate model: // modelparameter for this sphere: // position.x: 0, position.y: 0, position.z:0, radius: 1 pcl::ModelCoefficients sphere_coeff;sphere_coeff.values.resize (4);sphere_coeff.values[0] =0;sphere_coeff.values[1] =0;sphere_coeff.values[2] =0;sphere_coeff.values[3] =1; pcl::ModelOutlierRemoval<pcl::PointXYZ> sphere_filter;sphere_filter.setModelCoefficients (sphere_coeff);sphere_filter.setThreshold (0.05);sphere_filter.setModelType (pcl::SACMODEL_SPHERE);sphere_filter.setInputCloud (cloud); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_sphere_filtered (new pcl::PointCloud<pcl::PointXYZ>);sphere_filter.filter (*cloud_sphere_filtered); std::cerr <<"Sphere after filtering: "<< std::endl;for (std::size_t i =0; i <cloud_sphere_filtered->points.size (); ++i) std::cout <<" "<<cloud_sphere_filtered->points[i].x <<" "<<cloud_sphere_filtered->points[i].y <<" "<<cloud_sphere_filtered->points[i].z<< std::endl;return (0);}