• 点云模板匹配


            点云模板匹配是一种在点云数据中寻找特定形状或模式的方法。它通常用于计算机视觉和三维图像处理中,可以应用于物体识别、姿态估计、场景分析等任务。点云模板匹配的基本思想是将一个称为模板的小点云形状与输入的大点云进行匹配,以找到最佳的对应关系。通常,模板是由已知的目标对象或感兴趣的形状提取得到的。

    以下是一般的点云模板匹配流程:

    1. 提取模板:从点云中选择一个目标对象或形状,提取出其特征或描述子作为模板。
    2. 预处理:对输入的大点云进行预处理,例如滤波、重采样、去噪等操作,以减少噪声和优化数据质量。
    3. 特征提取:为输入点云和模板点云提取特征或描述子。这些特征可以包括形状特征、几何属性、法线方向、表面曲率等。
    4. 匹配:使用匹配算法(如最近邻搜索、迭代最近点、ICP等)通过比较特征或描述子来寻找最佳的匹配。
    5. 评估与筛选:根据匹配得分或距离,对匹配结果进行评估并筛选出最佳的匹配结果。
    6. 可视化和应用(可选):可以将匹配结果可视化或应用于其他任务,如目标识别、姿态估计等。

            需要注意的是,点云模板匹配的性能受到许多因素的影响,如点云质量、噪声、特征选择、算法选择等。在实际应用中,可能需要尝试不同的方法和参数来获得最佳的匹配结果。

    代码实现

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. typedef pcl::visualization::PointCloudColorHandlerCustom PCLHandler;
    17. class FeatureCloud {
    18. public:
    19. typedef pcl::PointCloud PointCloud;
    20. typedef pcl::PointCloud SurfaceNormals;
    21. typedef pcl::PointCloud LocalFeatures;
    22. typedef pcl::search::KdTree SearchMethod;
    23. FeatureCloud() :search_method_xyz_(new SearchMethod),normal_radius_(0.02f),feature_radius_(0.02f) {}
    24. ~FeatureCloud() {}
    25. // 处理给定的点云
    26. void
    27. setInputCloud(PointCloud::Ptr xyz) {
    28. xyz_ = xyz;
    29. processInput();
    30. }
    31. // 加载并处理给定PCD文件中的点云
    32. void
    33. loadInputCloud(const std::string& pcd_file) {
    34. xyz_ = PointCloud::Ptr(new PointCloud);
    35. pcl::io::loadPCDFile(pcd_file, *xyz_);
    36. processInput();
    37. }
    38. // 获取指向点云的指针
    39. PointCloud::Ptr
    40. getPointCloud() const {
    41. return (xyz_);
    42. }
    43. // 获取指向三维曲面法线的点云的指针
    44. SurfaceNormals::Ptr
    45. getSurfaceNormals() const {
    46. return (normals_);
    47. }
    48. // 获取指向特征描述点云的指针
    49. LocalFeatures::Ptr
    50. getLocalFeatures() const {
    51. return (features_);
    52. }
    53. protected:
    54. // 计算表面法线和局部特征
    55. void
    56. processInput() {
    57. computeSurfaceNormals();
    58. computeLocalFeatures();
    59. }
    60. // 计算表面法线
    61. void
    62. computeSurfaceNormals() {
    63. // 创建表面法向量
    64. normals_ = SurfaceNormals::Ptr(new SurfaceNormals);
    65. // 计算表面法向量
    66. pcl::NormalEstimation norm_est;
    67. norm_est.setInputCloud(xyz_);
    68. norm_est.setSearchMethod(search_method_xyz_);
    69. norm_est.setRadiusSearch(normal_radius_);
    70. norm_est.compute(*normals_);
    71. }
    72. // 计算局部特征描述子
    73. /**
    74. * 根据表面法向量 计算本地特征描述
    75. */
    76. void
    77. computeLocalFeatures() {
    78. features_ = LocalFeatures::Ptr(new LocalFeatures);
    79. pcl::FPFHEstimation fpfh_est;
    80. fpfh_est.setInputCloud(xyz_);
    81. fpfh_est.setInputNormals(normals_);
    82. fpfh_est.setSearchMethod(search_method_xyz_);
    83. fpfh_est.setRadiusSearch(feature_radius_);
    84. fpfh_est.compute(*features_);
    85. }
    86. private:
    87. // 点云数据
    88. PointCloud::Ptr xyz_;
    89. SurfaceNormals::Ptr normals_;
    90. LocalFeatures::Ptr features_; // 快速点特征直方图 Fast Point Feature Histogram
    91. SearchMethod::Ptr search_method_xyz_; // KDTree方法查找邻域
    92. // 参数
    93. float normal_radius_;
    94. float feature_radius_;
    95. };
    96. class TemplateAlignment {
    97. public:
    98. // 用于存储对齐结果的结构
    99. struct Result {
    100. // 匹配分数
    101. float fitness_score;
    102. // 转换矩阵
    103. Eigen::Matrix4f final_transformation;
    104. EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    105. };
    106. TemplateAlignment() :
    107. min_sample_distance_(0.05f),
    108. max_correspondence_distance_(0.01f * 0.01f),
    109. nr_iterations_(500) {
    110. // 初始化随机采样一致性(SAC-IA)算法中的参数
    111. sac_ia_.setMinSampleDistance(min_sample_distance_);
    112. sac_ia_.setMaxCorrespondenceDistance(max_correspondence_distance_);
    113. sac_ia_.setMaximumIterations(nr_iterations_);
    114. }
    115. ~TemplateAlignment() {}
    116. // 将给定的点云设置为模板将与之对齐的目标
    117. void setTargetCloud(FeatureCloud& target_cloud) {
    118. target_ = target_cloud;
    119. // 设置输入target点云
    120. sac_ia_.setInputTarget(target_cloud.getPointCloud());
    121. // 设置特征target
    122. sac_ia_.setTargetFeatures(target_cloud.getLocalFeatures());
    123. }
    124. // 将给定点云添加到模板点云列表中
    125. void addTemplateCloud(FeatureCloud& template_cloud) {
    126. templates_.push_back(template_cloud);
    127. }
    128. // 将给定的模板点云与setTargetCloud()指定的目标对齐
    129. // 对齐的核心代码
    130. void align(FeatureCloud& template_cloud, TemplateAlignment::Result& result) {
    131. // 设置输入源
    132. sac_ia_.setInputSource(template_cloud.getPointCloud());
    133. // 设置特征源
    134. sac_ia_.setSourceFeatures(template_cloud.getLocalFeatures());
    135. pcl::PointCloud registration_output;
    136. sac_ia_.align(registration_output);
    137. // 根据最远相应距离计算匹配分数
    138. result.fitness_score = (float)sac_ia_.getFitnessScore(max_correspondence_distance_);
    139. // 获取最终转换矩阵
    140. result.final_transformation = sac_ia_.getFinalTransformation();
    141. }
    142. // 将addTemplateCloud设置的所有模板点云与setTargetCloud()指定的目标对齐
    143. void alignAll(std::vector >& results) {
    144. results.resize(templates_.size());
    145. for (size_t i = 0; i < templates_.size(); ++i) {
    146. align(templates_[i], results[i]);
    147. }
    148. }
    149. // 将所有模板点云与目标点云对齐,以找到具有最佳对齐分数的模板云
    150. int findBestAlignment(TemplateAlignment::Result& result) {
    151. // 将所有模板与目标点云对齐
    152. std::vector > results;
    153. alignAll(results);
    154. // 找到最合适的模板
    155. float lowest_score = std::numeric_limits<float>::infinity();
    156. int best_template = 0;
    157. for (size_t i = 0; i < results.size(); ++i) {
    158. const Result& r = results[i];
    159. if (r.fitness_score < lowest_score) {
    160. lowest_score = r.fitness_score;
    161. best_template = (int)i;
    162. }
    163. }
    164. // 输出最佳匹配
    165. result = results[best_template];
    166. return (best_template);
    167. }
    168. private:
    169. // 模板云及其将要对齐的目标的列表
    170. std::vector templates_;
    171. FeatureCloud target_;
    172. // 随机采样一致性(SAC-IA)算法注册例程及其参数
    173. pcl::SampleConsensusInitialAlignment sac_ia_;
    174. float min_sample_distance_;
    175. float max_correspondence_distance_;
    176. int nr_iterations_;
    177. };
    178. /**
    179. * 对齐对象模板集合到一个示例点云
    180. * 通过直通滤波框定范围(得到感兴趣区域)
    181. * 将感兴趣区域进行降采样(提高模板匹配效率)
    182. */
    183. int main(int argc, char** argv)
    184. {
    185. // 加载对象模板
    186. std::vector object_templates;
    187. object_templates.resize(0);
    188. // 加载特征云
    189. FeatureCloud template_cloud;
    190. template_cloud.loadInputCloud("G:/vsdata/PCLlearn/PCDdata/bun0.pcd");
    191. object_templates.push_back(template_cloud);
    192. // 加载目标点云
    193. pcl::PointCloud::Ptr cloud(new pcl::PointCloud);
    194. pcl::PCDReader reader;
    195. reader.read("G:/vsdata/PCLlearn/PCDdata/bun0.pcd", *cloud);
    196. // 移除离群点
    197. const float depth_limit = 1.0;
    198. pcl::PassThrough pass;
    199. pass.setInputCloud(cloud);
    200. pass.setFilterFieldName("z");
    201. pass.setFilterLimits(0, depth_limit);
    202. pass.filter(*cloud);
    203. // 降采样点云, 减少计算量
    204. // 定义体素大小 5mm
    205. const float voxel_grid_size = 0.005f;
    206. pcl::VoxelGrid vox_grid;
    207. vox_grid.setInputCloud(cloud);
    208. // 设置叶子节点的大小lx, ly, lz
    209. vox_grid.setLeafSize(voxel_grid_size, voxel_grid_size, voxel_grid_size);
    210. //vox_grid.filter (*cloud); // Please see this http://www.pcl-developers.org/Possible-problem-in-new-VoxelGrid-implementation-from-PCL-1-5-0-td5490361.html
    211. pcl::PointCloud::Ptr tempCloud(new pcl::PointCloud);
    212. vox_grid.filter(*tempCloud);
    213. cloud = tempCloud;
    214. // 保存滤波&降采样后的点云图
    215. pcl::io::savePCDFileBinary("pass_through_voxel.pcd", *tempCloud);
    216. std::cout << "pass_through_voxel.pcd saved" << std::endl;
    217. // 对齐到目标特征点云
    218. FeatureCloud target_cloud;
    219. target_cloud.setInputCloud(cloud);
    220. // 设置TemplateAlignment输入
    221. TemplateAlignment template_align;
    222. for (size_t i = 0; i < object_templates.size(); i++) {
    223. FeatureCloud& object_template = object_templates[i];
    224. // 添加模板点云
    225. template_align.addTemplateCloud(object_template);
    226. }
    227. // 设置目标点云
    228. template_align.setTargetCloud(target_cloud);
    229. std::cout << "findBestAlignment" << std::endl;
    230. // 查找最佳模板对齐方式
    231. // 核心代码
    232. TemplateAlignment::Result best_alignment;
    233. int best_index = template_align.findBestAlignment(best_alignment);
    234. const FeatureCloud& best_template = object_templates[best_index];
    235. // 打印匹配度分数(小于0.00002的值是好的)
    236. printf("Best fitness score: %f\n", best_alignment.fitness_score);
    237. printf("Best fitness best_index: %d\n", best_index);
    238. // 打印旋转矩阵和平移向量
    239. Eigen::Matrix3f rotation = best_alignment.final_transformation.block<3, 3>(0, 0);
    240. Eigen::Vector3f translation = best_alignment.final_transformation.block<3, 1>(0, 3);
    241. Eigen::Vector3f euler_angles = rotation.eulerAngles(2, 1, 0) * 180 / M_PI;
    242. printf("\n");
    243. printf(" | %6.3f %6.3f %6.3f | \n", rotation(0, 0), rotation(0, 1), rotation(0, 2));
    244. printf("R = | %6.3f %6.3f %6.3f | \n", rotation(1, 0), rotation(1, 1), rotation(1, 2));
    245. printf(" | %6.3f %6.3f %6.3f | \n", rotation(2, 0), rotation(2, 1), rotation(2, 2));
    246. printf("\n");
    247. cout << "yaw(z) pitch(y) roll(x) = " << euler_angles.transpose() << endl;
    248. printf("\n");
    249. printf("t = < %0.3f, %0.3f, %0.3f >\n", translation(0), translation(1), translation(2));
    250. // 保存对齐的模板以进行可视化
    251. pcl::PointCloud transformed_cloud;
    252. // 将模板中保存的点云图进行旋转矩阵变换,把变换结果保存到transformed_cloud
    253. pcl::transformPointCloud(*best_template.getPointCloud(), transformed_cloud, best_alignment.final_transformation);
    254. //pcl::io::savePCDFileBinary("output.pcd", transformed_cloud);
    255. pcl::visualization::PCLVisualizer viewer("example");
    256. // 设置坐标系系统
    257. viewer.addCoordinateSystem(0.5, "cloud", 0);
    258. // 设置背景色
    259. viewer.setBackgroundColor(0.05, 0.05, 0.05, 0); // Setting background to a dark grey
    260. // 旋转后的点云rotated --------------------------------
    261. pcl::PointCloud::Ptr t_cloud(&transformed_cloud);
    262. PCLHandler transformed_cloud_handler(t_cloud, 255, 255, 255);
    263. viewer.addPointCloud(t_cloud, transformed_cloud_handler, "transformed_cloud");
    264. // 设置渲染属性(点大小)
    265. viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "transformed_cloud");
    266. // 目标点云target --------------------------------
    267. PCLHandler target_cloud_handler(cloud, 255, 100, 100);
    268. viewer.addPointCloud(cloud, target_cloud_handler, "target_cloud");
    269. // 设置渲染属性(点大小)
    270. viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "target_cloud");
    271. // 模板点云template --------------------------------
    272. PCLHandler template_cloud_handler(cloud, 100, 255, 255);
    273. viewer.addPointCloud(best_template.getPointCloud(), template_cloud_handler, "template_cloud");
    274. // 设置渲染属性(点大小)
    275. viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "template_cloud");
    276. while (!viewer.wasStopped()) {
    277. viewer.spinOnce();
    278. }
    279. return (0);
    280. }

    结果输出 

    1. pass_through_voxel.pcd saved
    2. findBestAlignment
    3. Best fitness score: 0.000008
    4. Best fitness best_index: 0
    5. | 1.000 -0.020 -0.007 |
    6. R = | 0.020 0.999 0.026 |
    7. | 0.007 -0.027 1.000 |
    8. yaw(z) pitch(y) roll(x) = 1.17069 -0.385805 -1.52169
    9. t = < 0.000, 0.000, 0.002 >

    实现效果 

  • 相关阅读:
    学习笔记-.net安全越权
    【微服务】Day08
    NVIDIA TensorRT 简介及使用
    2.23怎么在OrCAD原理图中显示与隐藏元器件的Value值?【OrCAD原理图封装库50问解析】
    Python基础-1-环境搭建(初体验)
    resultMap结果映射
    【PyTorch】PyTorch基础知识——张量
    基于ssm+vue的 法律咨询系统
    MySQL---索引+事务
    FlinkSQL系列02-Table表对象和SQL表视图
  • 原文地址:https://blog.csdn.net/mjmald/article/details/133752827