这个算法由两部分组成,第一部分是训练,第二部分是物体识别。它有以下6步:
1.先发现特征点。这只是一个训练点云的简化。在这个步骤里面所有的点云都将被简化,通过体元栅格这个途径。余下来的点就是特征点。
2.对特征点用FPFH进行预测。
3.通过k-means这个算法进行聚类。
4.计算每一个实例里面的对中心的方向。
5.对每一个视觉信息,数学权重将会被计算。
6.每一个特征点的权重将会被计算。
我们在训练的过程结束以后,接下来就是对象搜索的进程。
1.特征点检测。
2.每个点云特征点的特征检测。
3.对于每个特征搜索最近的视觉信息。
4.对于每一个特征:
对于每一个实例:
对相应的方向进行决策。
5.前面的步骤给了我们一个方向集用来预测中心与能量。
上面的步骤很多涉及机器学习之类的,大致明白那个过程即可
代码部分:
第一步我们需要点云的训练集。在下面是一些可以用的训练集.
Cat (train)
Horse (train)
Lioness (train)
Michael (train)
Wolf (train)
用来检测的点云:
Cat
Horse
Lioness
Michael
Wolf
下面是代码
#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d.h> #include <pcl/features/feature.h> #include <pcl/visualization/cloud_viewer.h> #include <pcl/features/fpfh.h> #include <pcl/features/impl/fpfh.hpp> #include <pcl/recognition/implicit_shape_model.h> #include <pcl/recognition/impl/implicit_shape_model.hpp> int main (int argc, char** argv) { if (argc == 0 || argc % 2 == 0) return (-1); unsigned int number_of_training_clouds = (argc - 3) / 2; pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator; normal_estimator.setRadiusSearch (25.0); std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> training_clouds; std::vector<pcl::PointCloud<pcl::Normal>::Ptr> training_normals; std::vector<unsigned int> training_classes; for (unsigned int i_cloud = 0; i_cloud < number_of_training_clouds - 1; i_cloud++) { pcl::PointCloud<pcl::PointXYZ>::Ptr tr_cloud(new pcl::PointCloud<pcl::PointXYZ> ()); if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[i_cloud * 2 + 1], *tr_cloud) == -1 ) return (-1); pcl::PointCloud<pcl::Normal>::Ptr tr_normals = (new pcl::PointCloud<pcl::Normal>)->makeShared (); normal_estimator.setInputCloud (tr_cloud); normal_estimator.compute (*tr_normals); unsigned int tr_class = static_cast<unsigned int> (strtol (argv[i_cloud * 2 + 2], 0, 10)); training_clouds.push_back (tr_cloud); training_normals.push_back (tr_normals); training_classes.push_back (tr_class); } pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::Histogram<153> >::Ptr fpfh (new pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::Histogram<153> >); fpfh->setRadiusSearch (30.0); pcl::Feature< pcl::PointXYZ, pcl::Histogram<153> >::Ptr feature_estimator(fpfh); pcl::ism::ImplicitShapeModelEstimation<153, pcl::PointXYZ, pcl::Normal> ism; ism.setFeatureEstimator(feature_estimator); ism.setTrainingClouds (training_clouds); ism.setTrainingNormals (training_normals); ism.setTrainingClasses (training_classes); ism.setSamplingSize (2.0f); pcl::ism::ImplicitShapeModelEstimation<153, pcl::PointXYZ, pcl::Normal>::ISMModelPtr model = boost::shared_ptr<pcl::features::ISMModel> (new pcl::features::ISMModel); ism.trainISM (model); std::string file ("trained_ism_model.txt"); model->saveModelToFile (file); model->loadModelFromfile (file); unsigned int testing_class = static_cast<unsigned int> (strtol (argv[argc - 1], 0, 10)); pcl::PointCloud<pcl::PointXYZ>::Ptr testing_cloud (new pcl::PointCloud<pcl::PointXYZ> ()); if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[argc - 2], *testing_cloud) == -1 ) return (-1); pcl::PointCloud<pcl::Normal>::Ptr testing_normals = (new pcl::PointCloud<pcl::Normal>)->makeShared (); normal_estimator.setInputCloud (testing_cloud); normal_estimator.compute (*testing_normals); boost::shared_ptr<pcl::features::ISMVoteList<pcl::PointXYZ> > vote_list = ism.findObjects ( model, testing_cloud, testing_normals, testing_class); double radius = model->sigmas_[testing_class] * 10.0; double sigma = model->sigmas_[testing_class]; std::vector<pcl::ISMPeak, Eigen::aligned_allocator<pcl::ISMPeak> > strongest_peaks; vote_list->findStrongestPeaks (strongest_peaks, testing_class, radius, sigma); pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = (new pcl::PointCloud<pcl::PointXYZRGB>)->makeShared (); colored_cloud->height = 0; colored_cloud->width = 1; pcl::PointXYZRGB point; point.r = 255; point.g = 255; point.b = 255; for (size_t i_point = 0; i_point < testing_cloud->points.size (); i_point++) { point.x = testing_cloud->points[i_point].x; point.y = testing_cloud->points[i_point].y; point.z = testing_cloud->points[i_point].z; colored_cloud->points.push_back (point); } colored_cloud->height += testing_cloud->points.size (); point.r = 255; point.g = 0; point.b = 0; for (size_t i_vote = 0; i_vote < strongest_peaks.size (); i_vote++) { point.x = strongest_peaks[i_vote].x; point.y = strongest_peaks[i_vote].y; point.z = strongest_peaks[i_vote].z; colored_cloud->points.push_back (point); } colored_cloud->height += strongest_peaks.size (); pcl::visualization::CloudViewer viewer ("Result viewer"); viewer.showCloud (colored_cloud); while (!viewer.wasStopped ()) { } return (0); }
1.首先加载用于训练的点云
for (unsigned int i_cloud = 0; i_cloud < number_of_training_clouds - 1; i_cloud++) { pcl::PointCloud<pcl::PointXYZ>::Ptr tr_cloud(new pcl::PointCloud<pcl::PointXYZ> ()); if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[i_cloud * 2 + 1], *tr_cloud) == -1 ) return (-1); pcl::PointCloud<pcl::Normal>::Ptr tr_normals = (new pcl::PointCloud<pcl::Normal>)->makeShared (); normal_estimator.setInputCloud (tr_cloud); normal_estimator.compute (*tr_normals); unsigned int tr_class = static_cast<unsigned int> (strtol (argv[i_cloud * 2 + 2], 0, 10)); training_clouds.push_back (tr_cloud); training_normals.push_back (tr_normals); training_classes.push_back (tr_class); }
2.创建特征评估器的实例。
pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::Histogram<153> >::Ptr fpfh (new pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::Histogram<153> >); fpfh->setRadiusSearch (30.0); pcl::Feature< pcl::PointXYZ, pcl::Histogram<153> >::Ptr feature_estimator(fpfh);
3.创建pcl::ism::ImplicitShapeModeEstimation的实例。
ism.setFeatureEstimator(feature_estimator); ism.setTrainingClouds (training_clouds); ism.setTrainingNormals (training_normals); ism.setTrainingClasses (training_classes); ism.setSamplingSize (2.0f);
4.这个实例将输入训练集和特征预估器
pcl::ism::ImplicitShapeModelEstimation<153, pcl::PointXYZ, pcl::Normal>::ISMModelPtr model = boost::shared_ptr<pcl::features::ISMModel> (new pcl::features::ISMModel); ism.trainISM (model);
上面这些将简化训练过程的启动
5.把训练模型存到文件里面为了使代码复用
std::string file ("trained_ism_model.txt"); model->saveModelToFile (file);
6.从文件里面加载模型。
model->loadModelFromfile (file);
7.分类操作的点云和法线也需要训练的过程。
unsigned int testing_class = static_cast<unsigned int> (strtol (argv[argc - 1], 0, 10)); pcl::PointCloud<pcl::PointXYZ>::Ptr testing_cloud (new pcl::PointCloud<pcl::PointXYZ> ()); if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[argc - 2], *testing_cloud) == -1 ) return (-1); pcl::PointCloud<pcl::Normal>::Ptr testing_normals = (new pcl::PointCloud<pcl::Normal>)->makeShared (); normal_estimator.setInputCloud (testing_cloud); normal_estimator.compute (*testing_normals);
8.启动分类的进程。代码将会告诉算法去找testing_class类型的物体,在给定的testing_cloud这个点云里面。注意算法将会使用任何你放进去进行训练的模型。在分类操作以后,一列的决策将会以pcl::ism::ISMVoteList这个形式返回。
double radius = model->sigmas_[testing_class] * 10.0; double sigma = model->sigmas_[testing_class]; std::vector<pcl::ISMPeak, Eigen::aligned_allocator<pcl::ISMPeak> > strongest_peaks; vote_list->findStrongestPeaks (strongest_peaks, testing_class, radius, sigma);
上面的代码将会找到决策里面的最好的峰值。
运行下面的代码
./implicit_shape_model ism_train_cat.pcd 0 ism_train_horse.pcd 1 ism_train_lioness.pcd 2 ism_train_michael.pcd 3 ism_train_wolf.pcd 4 ism_test_cat.pcd 0
最后的参数是你要检测的点云和你感兴趣的类别。(比如猫)
~接下去你会看到
红点表示物体的中心。
如果你想要可视化决策的过程,你就会看到如下的东西。蓝色是决策点