前言

本文针对csdn中,对于pcl库中基于对应分组的三维物体识别的代码过于冗长的现象,如https://blog.csdn.net/lizhengze1117/article/details/103230261这篇文章的代码真的长。本文对其代码中花里胡哨的部分进行删减。

提示:以下是本篇文章正文内容,下面案例可供参考

一、pcl基于对应分组的三维物体识别

与识别有关的知识请参考https://www.yuque.com/huangzhongqing/pcl/hpgc39#E10g9
该链接是某大佬写的pcl的教程代码虽然写得很长,但理论讲的还不错。

二、使用步骤

1.环境

vs2019+pcl1.11.1

2.代码

代码如下(:

// 对象识别.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <sstream>
#include <fstream>
#include<pcl\point_types.h>
#include<pcl\point_cloud.h>
#include <pcl/features/shot_omp.h>
#include<pcl\io\pcd_io.h>
#include <pcl/features/normal_3d_omp.h>
#include<pcl\visualization\pcl_visualizer.h>
#include <pcl/filters/uniform_sampling.h>//均匀采样 滤波
#include <pcl/recognition/cg/geometric_consistency.h> //几何一致性
#include <pcl/common/transforms.h>//点云转换 转换矩阵
using namespace std;
int main()
{
    /*模型、场景、局部特征描述子的数据结构*/
    pcl::PointCloud<pcl::PointXYZ>::Ptr model(new pcl::PointCloud<pcl::PointXYZ>());           //模型点云,模型的格式为PointXYZ
    pcl::PointCloud<pcl::PointXYZ>::Ptr model_keypoints(new pcl::PointCloud<pcl::PointXYZ>()); //降采样后的
    pcl::PointCloud<pcl::PointXYZRGBA>::Ptr scene(new pcl::PointCloud<pcl::PointXYZRGBA>());           //目标点云,场景的格式为PointXYZRGBA,也不知道那篇文章为什么将其和模型定义为相同格式,可能又想炫技?
    pcl::PointCloud<pcl::PointXYZRGBA>::Ptr scene_keypoints(new pcl::PointCloud<pcl::PointXYZRGBA>()); //关键点
    pcl::PointCloud<pcl::Normal>::Ptr model_normals(new pcl::PointCloud<pcl::Normal>()); //法线
    pcl::PointCloud<pcl::Normal>::Ptr scene_normals(new pcl::PointCloud<pcl::Normal>()); //
    pcl::PointCloud<pcl::SHOT352>::Ptr model_descriptors(new pcl::PointCloud<pcl::SHOT352>()); //描述子
    pcl::PointCloud<pcl::SHOT352>::Ptr scene_descriptors(new pcl::PointCloud<pcl::SHOT352>());
    /*模型、场景、局部特征描述子的数据结构*/

    /* pcd文件输入输出*/
    pcl::io::loadPCDFile("E:\\2345Downloads\\MVision-master\\MVision-master\\PCL_APP\\Recognition\\milk.pcd", *model);
    pcl::io::loadPCDFile("E:\\2345Downloads\\MVision-master\\MVision-master\\PCL_APP\\Recognition\\milk_cartoon_all_small_clorox.pcd", *scene);
    /* pcd文件输入输出*/

    /* 法线估计*/
    pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> norm_est;
    pcl::NormalEstimationOMP<pcl::PointXYZRGBA, pcl::Normal> norm_sen;
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree1(new pcl::search::KdTree<pcl::PointXYZ>());
    pcl::search::KdTree<pcl::PointXYZRGBA>::Ptr tree2(new pcl::search::KdTree<pcl::PointXYZRGBA>());
    norm_est.setSearchMethod(tree1);//设置搜索模式为kdtree,原文想炫技非用多线程
    norm_est.setKSearch(10);         //设置k邻域搜索阈值为10个点
    norm_est.setInputCloud(model);   //设置输入模型点云
    norm_est.compute(*model_normals);//计算点云法线
    norm_sen.setSearchMethod(tree2);   //设置搜索模式为kdtree,原文想炫技非用多线程
    norm_sen.setKSearch(10);         //设置k邻域搜索阈值为10个
    norm_sen.setInputCloud(scene);
    norm_sen.compute(*scene_normals);
    /* 法线估计*/
    /*降采样*/
    pcl::UniformSampling<pcl::PointXYZ> uniform_sampling1;//下采样滤波模型
    uniform_sampling1.setInputCloud(model);//模型点云
    uniform_sampling1.setRadiusSearch(0.01);//模型点云搜索半径
    uniform_sampling1.filter(*model_keypoints);//下采样得到的关键点
    pcl::UniformSampling<pcl::PointXYZRGBA> uniform_sampling2;//下采样滤波模型
    uniform_sampling2.setInputCloud(scene);//场景点云
    uniform_sampling2.setRadiusSearch(0.03);//场景点云搜索半径
    uniform_sampling2.filter(*scene_keypoints);//下采样得到的关键点,降得几乎看不出轮廓
    /*降采样*/
   /* 局部特征描述子*/
    pcl::SHOTEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::SHOT352> descr_est1;//shot描述子
    descr_est1.setRadiusSearch(0.02);
    descr_est1.setInputCloud(model_keypoints);
    descr_est1.setInputNormals(model_normals);
    descr_est1.setSearchSurface(model);
    descr_est1.compute(*model_descriptors);//模型点云描述子
    pcl::SHOTEstimationOMP<pcl::PointXYZRGBA, pcl::Normal, pcl::SHOT352> descr_est2;//shot描述子
    descr_est2.setRadiusSearch(0.04);//你上面都降采样到0.03了,这里在设置为0.02怎么可能找得到点
    descr_est2.setInputCloud(scene_keypoints);
    descr_est2.setInputNormals(scene_normals);
    descr_est2.setSearchSurface(scene);
    descr_est2.compute(*scene_descriptors);//场景点云描述子
    /*局部特征描述子*/
    /*匹配局部特征描述子,我也不知道为什么要匹配这个*/
    pcl::CorrespondencesPtr model_scene_corrs(new pcl::Correspondences());//最佳匹配点对组

    pcl::KdTreeFLANN<pcl::SHOT352> match_search;//匹配搜索
    match_search.setInputCloud(model_descriptors);//模型点云描述子
    // 在 场景点云中 为 模型点云的每一个关键点 匹配一个 描述子最相似的 点
    for (size_t i = 0; i < scene_descriptors->size(); ++i)//遍历场景点云
    {
        std::vector<int> neigh_indices(1);//索引
        std::vector<float> neigh_sqr_dists(1);//描述子距离
        if (!pcl_isfinite(scene_descriptors->at(i).descriptor[0])) //跳过NAN点
        {
            continue;
        }
        int found_neighs = match_search.nearestKSearch(scene_descriptors->at(i), 1, neigh_indices, neigh_sqr_dists);
        if (found_neighs == 1 && neigh_sqr_dists[0] < 0.25f) //在模型点云中 找 距离 场景点云点i shot描述子距离 <0.25 的点 ,很神奇,不清楚0.25怎么来的
        {
            pcl::Correspondence corr(neigh_indices[0], static_cast<int> (i), neigh_sqr_dists[0]);
            //   neigh_indices[0] 为模型点云中 和 场景点云 点   scene_descriptors->at (i) 最佳的匹配 距离为 neigh_sqr_dists[0]  
            model_scene_corrs->push_back(corr);
        }
    }
    /*匹配局部特征描述子,我也不知道为什么要匹配这个*/
    std::vector<Eigen::Matrix4f, Eigen::aligned_allocator<Eigen::Matrix4f> > rototranslations;//变换矩阵 旋转矩阵与平移矩阵
  // 对eigen中的固定大小的类使用STL容器的时候,如果直接使用就会出错 需要使用 Eigen::aligned_allocator 对齐技术
    std::vector<pcl::Correspondences> clustered_corrs;//匹配点 相互连线的索引
    pcl::GeometricConsistencyGrouping<pcl::PointXYZ, pcl::PointXYZRGBA> gc_clusterer;
    gc_clusterer.setGCSize(0.01);//设置几何一致性的大小
    gc_clusterer.setGCThreshold(5.0);//阀值

    gc_clusterer.setInputCloud(model_keypoints);
    gc_clusterer.setSceneCloud(scene_keypoints);
    gc_clusterer.setModelSceneCorrespondences(model_scene_corrs);

    //gc_clusterer.cluster (clustered_corrs);//辨认出聚类的对象
    gc_clusterer.recognize(rototranslations, clustered_corrs);

    /* 可视化*/
    pcl::visualization::PCLVisualizer viewer("111");
    viewer.addPointCloud(scene, "scene_cloud");//添加场景点云

    pcl::PointCloud<pcl::PointXYZ>::Ptr off_scene_model(new pcl::PointCloud<pcl::PointXYZ>());// 模型点云 变换后的点云
    pcl::PointCloud<pcl::PointXYZ>::Ptr off_scene_model_keypoints(new pcl::PointCloud<pcl::PointXYZ>());//关键点
    for (size_t i = 0; i < rototranslations.size(); ++i)//对于 模型在场景中 匹配的 点云
    {
        pcl::PointCloud<pcl::PointXYZ>::Ptr rotated_model(new pcl::PointCloud<pcl::PointXYZ>());//按匹配变换矩阵 模型点云
        pcl::transformPointCloud(*model, *rotated_model, rototranslations[i]);//将模型点云按匹配的变换矩阵旋转
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> rotated_model_color_handler(rotated_model, 255, 0, 0);
        viewer.addPointCloud(rotated_model, rotated_model_color_handler);//添加模型按识别 变换矩阵变换后 显示
        for (size_t j = 0; j < clustered_corrs[i].size(); ++j)
        {

            pcl::PointXYZ& model_point = model_keypoints->at(clustered_corrs[i][j].index_query);//模型点
            pcl::PointXYZRGBA& scene_point = scene_keypoints->at(clustered_corrs[i][j].index_match);//场景点

            //  显示点云匹配对中每一对匹配点对之间的连线
            viewer.addLine<pcl::PointXYZ, pcl::PointXYZRGBA>(model_point, scene_point, 0, 255, 0);
        }

           
        
    }

    while (!viewer.wasStopped())
    {
        viewer.spinOnce();
    }
 
}


该处使用的url网络请求的数据。


效果图

在这里插入图片描述

本文作者水平有限,因此对原文的代码一知半解,又由于对原文代码删减过多,从而导致识别结果出现了很大的问题,如只有一条绿色的线、红色点云是横着的等问题,但原文代码过长,笔者也不知道到底哪里出了问题。
下附参考文章的链接 https://www.yuque.com/huangzhongqing/pcl/hpgc39#E10g9

更多推荐