[PointCloud] GICP
泛化的ICP算法,通过协方差矩阵起到类似于权重的作用,消除某些不好的对应点在求解过程中的作用。不过可以囊括Point to Point,Point to Plane的ICP算法,真正的是泛化的ICP。牛!
CC中的GICP插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | void qLxPluginPCL::doSpraseRegistration() { assert (m_app); if (!m_app) return ; const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); size_t selNum = selectedEntities.size(); if (selNum!=2) { m_app->dispToConsole( "Please select two cloud!" ,ccMainAppInterface::ERR_CONSOLE_MESSAGE); return ; } ccHObject* ent = selectedEntities[0]; assert (ent); if (!ent || !ent->isA(CC_TYPES::POINT_CLOUD)) { m_app->dispToConsole( "Select a real point cloud!" ,ccMainAppInterface::ERR_CONSOLE_MESSAGE); return ; } ccHObject* ent2 = selectedEntities[1]; assert (ent2); if (!ent2 || !ent2->isA(CC_TYPES::POINT_CLOUD)) { m_app->dispToConsole( "Select a real point cloud!" ,ccMainAppInterface::ERR_CONSOLE_MESSAGE); return ; } ccPointCloud* m_target_cloud = static_cast <ccPointCloud*>(ent); ccPointCloud* m_Source_cloud = static_cast <ccPointCloud*>(ent2); //input cloud unsigned count = m_target_cloud->size(); bool hasNorms = m_target_cloud->hasNormals(); CCVector3 bbMin, bbMax; m_target_cloud->getBoundingBox(bbMin,bbMax); const CCVector3d& globalShift = m_target_cloud->getGlobalShift(); double globalScale = m_target_cloud->getGlobalScale(); cc3DNdtdlg dlg; if (!dlg.exec()) return ; double maxCorrDis =1; maxCorrDis= dlg.getVoxelGridsize(); pcl::PointCloud<PointXYZ>::Ptr pcl_t_cloud ( new pcl::PointCloud<PointXYZ>); pcl::PointCloud<PointXYZ>::Ptr pcl_s_cloud ( new pcl::PointCloud<PointXYZ>); try { // unsigned pointCount = m_target_cloud->size(); pcl_t_cloud->resize(pointCount); for (unsigned i = 0; i < pointCount; ++i) { const CCVector3* P = m_target_cloud->getPoint(i); pcl_t_cloud->at(i).x = static_cast < float >(P->x); pcl_t_cloud->at(i).y = static_cast < float >(P->y); pcl_t_cloud->at(i).z = static_cast < float >(P->z); } // pointCount = m_Source_cloud->size(); pcl_s_cloud->resize(pointCount); for (unsigned i = 0; i < pointCount; ++i) { const CCVector3* P = m_Source_cloud->getPoint(i); pcl_s_cloud->at(i).x = static_cast < float >(P->x); pcl_s_cloud->at(i).y = static_cast < float >(P->y); pcl_s_cloud->at(i).z = static_cast < float >(P->z); } } catch (...) { //any error (memory, etc.) pcl_t_cloud.reset(); pcl_s_cloud.reset(); } pcl::search::KdTree<pcl::PointXYZ>::Ptr tree1 ( new pcl::search::KdTree<pcl::PointXYZ>); tree1->setInputCloud (pcl_t_cloud); pcl::search::KdTree<pcl::PointXYZ>::Ptr tree2 ( new pcl::search::KdTree<pcl::PointXYZ>); tree2->setInputCloud (pcl_s_cloud); pcl::PolygonMesh::Ptr mesh( new pcl::PolygonMesh); // reconstruct meshes for source and target pcl::OrganizedFastMesh<pcl::PointXYZ> fast_mesh; fast_mesh.setInputCloud(pcl_t_cloud); //设置输入点云 /* ofm.setIndices(cloudInd);*/ //设置输入点云索引 fast_mesh.setMaxEdgeLength(0.1); //设置多边形网格最大边长 fast_mesh.setTriangulationType(pcl::OrganizedFastMesh<pcl::PointXYZ>::TRIANGLE_ADAPTIVE_CUT); //设置网格类型 fast_mesh.setTrianglePixelSize(1); //设置三角形边长 1表示链接相邻点作为边长 //fast_mesh.storeShadowedFaces(false); //设置是否存储阴影面 fast_mesh.setSearchMethod(tree1); fast_mesh.reconstruct(*mesh); // compute normals and covariances for source and target pcl::PointCloud<pcl::Normal>::Ptr normals( new pcl::PointCloud<pcl::Normal>); boost::shared_ptr<std::vector<Eigen::Matrix3d, Eigen::aligned_allocator<Eigen::Matrix3d> >> target_covariances( new std::vector<Eigen::Matrix3d, Eigen::aligned_allocator<Eigen::Matrix3d> >); pcl::features::computeApproximateNormals(*pcl_t_cloud, mesh->polygons, *normals); pcl::features::computeApproximateCovariances(*pcl_t_cloud, *normals, *target_covariances); fast_mesh.setInputCloud(pcl_s_cloud); /* ofm.setIndices(cloudInd);*/ //设置输入点云索引 fast_mesh.setMaxEdgeLength(1.0); //设置多边形网格最大边长 fast_mesh.setTriangulationType(pcl::OrganizedFastMesh<pcl::PointXYZ>::TRIANGLE_ADAPTIVE_CUT); //设置网格类型 fast_mesh.setTrianglePixelSize(1); //设置三角形边长 1表示链接相邻点作为边长 fast_mesh.storeShadowedFaces( false ); //设置是否存储阴影面 fast_mesh.setSearchMethod(tree2); fast_mesh.reconstruct(*mesh); // compute normals and covariances for source and target pcl::PointCloud<pcl::Normal>::Ptr normalst( new pcl::PointCloud<pcl::Normal>); boost::shared_ptr<std::vector<Eigen::Matrix3d, Eigen::aligned_allocator<Eigen::Matrix3d>>> source_covariances( new std::vector<Eigen::Matrix3d, Eigen::aligned_allocator<Eigen::Matrix3d> >); pcl::features::computeApproximateNormals(*pcl_s_cloud, mesh->polygons, *normalst); pcl::features::computeApproximateCovariances(*pcl_s_cloud, *normalst, *source_covariances); // setup Generalized-ICP pcl::GeneralizedIterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> gicp; gicp.setMaxCorrespondenceDistance(maxCorrDis); gicp.setInputSource(pcl_s_cloud); gicp.setInputTarget(pcl_t_cloud); /*gicp.setSourceCovariances(source_covariances); gicp.setTargetCovariances(target_covariances);*/ // run registration and get transformation pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out ( new pcl::PointCloud<pcl::PointXYZ>); gicp.align(*cloud_out); Eigen::Matrix4f transform = gicp.getFinalTransformation(); int pointCount = cloud_out->size(); //static_cast<size_t>(sm_cloud ? sm_cloud->width * sm_cloud->height : 0); ccPointCloud* ccCloud = new ccPointCloud(); if (!ccCloud->reserve( static_cast <unsigned>(pointCount))) return ; for ( size_t i = 0; i < pointCount; ++i) { CCVector3 P(cloud_out->at(i).x,cloud_out->at(i).y,cloud_out->at(i).z); ccCloud->addPoint(P); } ccCloud->setName(QString( "GICP" )); ccColor::Rgb col = ccColor::Generator::Random(); ccCloud->setRGBColor(col); ccCloud->showColors( true ); ccCloud->setPointSize(1); ccHObject* group = 0; if (!group) group = new ccHObject(QString( "GICP(%1)" ).arg(ent2->getName())); group->addChild(ccCloud); group->setVisible( true ); m_app->addToDB(group); } |
近似特征值计算
这个的原理被想复杂了,就是特征值分解的逆步骤,形成了三个正交的向量,epsilon是最小的特征值,法向量是最小的特征向量。
本来求法向量的过程就是根据近邻的k个点,利用主成分分析PCA进行计算得到特征值最小的那个特征向量作为法向量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /** \brief Compute GICP-style covariance matrices given a point cloud and * the corresponding surface normals. * \param[in] cloud Point cloud containing the XYZ coordinates, * \param[in] normals Point cloud containing the corresponding surface normals. * \param[out] covariances Vector of computed covariances. * \param[in] Optional: Epsilon for the expected noise along the surface normal (default: 0.001) */ template < typename PointT, typename PointNT> inline void computeApproximateCovariances( const pcl::PointCloud<PointT>& cloud, const pcl::PointCloud<PointNT>& normals, std::vector<Eigen::Matrix3d, Eigen::aligned_allocator<Eigen::Matrix3d> >& covariances, double epsilon = 0.001) { assert (cloud.points.size() == normals.points.size()); int nr_points = static_cast < int >(cloud.points.size()); covariances.resize(nr_points); for ( int i = 0; i < nr_points; ++i) { Eigen::Vector3d normal(normals.points[i].normal_x, normals.points[i].normal_y, normals.points[i].normal_z); // compute rotation matrix Eigen::Matrix3d rot; Eigen::Vector3d y; y << 0, 1, 0; rot.row(2) = normal; y = y - normal(1) * normal; y.normalize(); rot.row(1) = y; rot.row(0) = normal.cross(rot.row(1)); // comnpute approximate covariance Eigen::Matrix3d cov; cov << 1, 0, 0, 0, 1, 0, 0, 0, epsilon; covariances[i] = rot.transpose()*cov*rot; } } } |
作者:太一吾鱼水
文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。
欢迎大家留言交流,转载请注明出处。
分类:
PointCloud
标签:
Point Cloud
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
2013-07-26 DIY自己的GIS程序(1)——起航
2012-07-26 ArcEngine唯一值着色再开发!