PCL的ICP配准示例

it2022-05-05  154

2019/07/18,转载请注明。

使用的PCL 1.8.0,VS2013。

我用的3D模型,是网上下载的obj模型,自己用代码转成ply文件,一开始读取失败,检查发现是ply的header不符合PCL的,

按照PCL的格式修改后就可以了。

一、PCL中ply格式

PCL库读取PLY文件,要注意文件的header是否符合要求的,在ply._io.h中有注明:

/** \brief Point Cloud Data (PLY) file format reader. 52 * 53 * The PLY data format is organized in the following way: 54 * lines beginning with "comment" are treated as comments 55 * - ply 56 * - format [ascii|binary_little_endian|binary_big_endian] 1.0 57 * - element vertex COUNT 58 * - property float x 59 * - property float y 60 * - [property float z] 61 * - [property float normal_x] 62 * - [property float normal_y] 63 * - [property float normal_z] 64 * - [property uchar red] 65 * - [property uchar green] 66 * - [property uchar blue] ... 67 * - ascii/binary point coordinates 68 * - [element camera 1] 69 * - [property float view_px] ... 70 * - [element range_grid COUNT] 71 * - [property list uchar int vertex_indices] 72 * - end header 73 * 74 * \author Nizar Sallem 75 * \ingroup io 76 */

二、ICP代码

#include <iostream> #include <string> #include <conio.h> #include <vector> #include <pcl/keypoints/uniform_sampling.h> #include <pcl/filters/voxel_grid.h> #include <pcl/io/ply_io.h> #include <pcl/point_types.h> #include <pcl/registration/icp.h> #include <pcl/visualization/pcl_visualizer.h>//可视化头文件 #include <pcl/console/time.h> // TicToc using namespace std; typedef pcl::PointXYZRGB PointT; typedef pcl::PointCloud<PointT> PointCloudT; bool next_iteration = false; bool end_iteration = false; void print4x4Matrix(const Eigen::Matrix4d & matrix) //打印旋转矩阵和平移矩阵 { printf("Rotation matrix :\r\n"); printf(" | %6.6f %6.6f %6.6f | \n", matrix(0, 0), matrix(0, 1), matrix(0, 2)); printf("R = | %6.6f %6.6f %6.6f | \n", matrix(1, 0), matrix(1, 1), matrix(1, 2)); printf(" | %6.6f %6.6f %6.6f | \n", matrix(2, 0), matrix(2, 1), matrix(2, 2)); printf("Translation vector :\n"); printf("t = < %6.6f, %6.6f, %6.6f >\n\n", matrix(0, 3), matrix(1, 3), matrix(2, 3)); } void keyboardEventOccurred(const pcl::visualization::KeyboardEvent& event, void* nothing) { if (event.getKeySym() == "space" && event.keyDown())//使用空格键来增加迭代次数,并更新显示 next_iteration = true; if (event.getKeySym() == "c" && event.keyDown())//使用c键来结束迭代过程,并退出循环 end_iteration = true; } int main(int argc, char* argv[]) { //创建点云指针 PointCloudT::Ptr cloud_in(new PointCloudT); // Original point cloud//输入点云指针 PointCloudT::Ptr cloud_tr(new PointCloudT); // Transformed point cloud//目标点云指针 PointCloudT::Ptr cloud_icp(new PointCloudT); // ICP output point cloud//ICP点云指针 pcl::PLYWriter plywriter; //创建计时器 pcl::console::TicToc time; time.tic(); //载入输入点云 if (pcl::io::loadPLYFile<PointT>("02_sfm.ply", *cloud_in) == -1) { PCL_ERROR("Couldn't read file1 \n"); return (-1); } std::cout << "Loaded " << cloud_in->size() << " data points from file1" << std::endl; //载入目标点云 if (pcl::io::loadPLYFile<PointT>("02_gray.ply", *cloud_tr) == -1) { PCL_ERROR("Couldn't read file2 \n"); return (-1); } int iterations = 1; // Default number of ICP iterations//默认的ICP迭代次数 //定义旋转矩阵和平移矩阵向量Matrix4d是为4*4的矩阵 Eigen::Matrix4d transformation_matrix = Eigen::Matrix4d::Identity(); /* Reminder: how transformation matrices work : |-------> This column is the translation | 1 0 0 x | \ | 0 1 0 y | }-> The identity 3x3 matrix (no rotation) on the left | 0 0 1 z | / | 0 0 0 1 | -> We do not use this line (and it has to stay 0,0,0,1) METHOD #1: Using a Matrix4f This is the "manual" method, perfect to understand but error prone ! */ //初始化一个接近的位置 double theta = M_PI; // The angle of rotation in radians transformation_matrix(0, 0) = cos(theta); transformation_matrix(0, 2) = -sin(theta); transformation_matrix(2, 0) = sin(theta); transformation_matrix(2, 2) = cos(theta); pcl::transformPointCloud(*cloud_in, *cloud_in, transformation_matrix); //点太多 降采样加速 pcl::VoxelGrid<PointT> sor2;// 创建采样对象 PointCloudT::Ptr down_cloud_in(new PointCloudT); // 降采样输入点云指针 PointCloudT::Ptr down_cloud_tr(new PointCloudT); // 降采样目标点云指针 sor2.setLeafSize(1.2f, 1.2f, 1.2f);//设置滤波时创建的体素体积为1.2的立方体 sor2.setInputCloud(cloud_in);//设置需要过滤的点云 sor2.filter(*down_cloud_in);//执行滤波处理 std::cout << "down_cloud_in point num " << down_cloud_in->size()<< std::endl; sor2.setInputCloud(cloud_tr);//设置需要过滤的点云 sor2.filter(*down_cloud_tr);//执行滤波处理 std::cout << "down_cloud_tr point num " << down_cloud_tr->size() << std::endl; *cloud_icp = *down_cloud_in; //计时器开始 time.tic(); //创建ICP迭代器 pcl::IterativeClosestPoint<PointT, PointT> icp; icp.setMaximumIterations(iterations);//每次align最大迭代次数 icp.setInputSource(cloud_icp);//这里的icp源数据必定是在不停迭代的变量cloud_icp,与align()中的输出一致 icp.setInputTarget(down_cloud_tr);//配准目标 icp.align(*cloud_icp);//一定要与setInputSource中的输入一致,确保下次在本次结果上迭代 std::cout << "Applied " << iterations << " ICP iteration(s) in " << time.toc() << " ms" << std::endl; if (icp.hasConverged()) { std::cout << "\nICP has converged, score is " << icp.getFitnessScore() << std::endl; std::cout << "\nICP transformation " << iterations << " : cloud_icp -> cloud_tr" << std::endl; transformation_matrix = icp.getFinalTransformation().cast<double>(); print4x4Matrix(transformation_matrix); } else { PCL_ERROR("\nICP has not converged.\n"); return (-1); } //创建可视化窗口 pcl::visualization::PCLVisualizer viewer("ICP demo"); //创建两个水平的可视化组件 int v1(0); int v2(1); viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1); viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2); //背景色和字体色 float bckgr_gray_level = 0.0; // Black float txt_gray_lvl = 1.0 - bckgr_gray_level; // 目标点云是白色 pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_tr_color_h(down_cloud_tr, (int)255 * txt_gray_lvl, (int)255 * txt_gray_lvl, (int)255 * txt_gray_lvl); viewer.addPointCloud(down_cloud_tr, cloud_tr_color_h, "cloud_tr_v1", v1); viewer.addPointCloud(down_cloud_tr, cloud_tr_color_h, "cloud_tr_v2", v2); // 源点云是绿色 pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_in_color_h(down_cloud_in, 20, 180, 20); viewer.addPointCloud(down_cloud_in, cloud_in_color_h, "cloud_in_v1", v1); // ICP点云是红色 pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_icp_color_h(cloud_icp, 180, 20, 20); viewer.addPointCloud(cloud_icp, cloud_icp_color_h, "cloud_icp_v2", v2); // 添加文字 viewer.addText("White: pcd no colour\nGreen: Ori colour pcd ", 10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_1", v1); viewer.addText("White: pcd no colour\nRed: ICP colour pcd", 10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_2", v2); std::stringstream ss; ss << iterations; std::string iterations_cnt = "ICP iterations = " + ss.str(); viewer.addText(iterations_cnt, 10, 60, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "iterations_cnt", v2); // 设置组件背景色 viewer.setBackgroundColor(bckgr_gray_level, bckgr_gray_level, bckgr_gray_level, v1); viewer.setBackgroundColor(bckgr_gray_level, bckgr_gray_level, bckgr_gray_level, v2); // 设置虚拟相机位置和方向 viewer.setCameraPosition(-3.68332, 2.94092, 5.71266, 0.289847, 0.921947, -0.256907, 0); viewer.setSize(1280, 1024); // 窗口大小 // 注册按键事件响应 viewer.registerKeyboardCallback(&keyboardEventOccurred, (void*)NULL); // 在窗口中展示可视化内容(点云、文字) while (!viewer.wasStopped()) { viewer.spinOnce(); // 按下空格,next_iteration会被赋值true,执行一次ICP if (next_iteration) //if (c!=27) { // The Iterative Closest Point algorithm time.tic(); icp.align(*cloud_icp); std::cout << "Applied 1 ICP iteration in " << time.toc() << " ms" << std::endl; if (icp.hasConverged()) { printf("\033[11A"); // Go up 11 lines in terminal output. printf("\nICP has converged, score is %+.0e\n", icp.getFitnessScore()); std::cout << "\nICP transformation " << ++iterations << " : cloud_icp -> cloud_tr" << std::endl; transformation_matrix = icp.getFinalTransformation().cast<double>()*transformation_matrix; print4x4Matrix(transformation_matrix); ss.str(""); ss << iterations; std::string iterations_cnt = "ICP iterations = " + ss.str(); //更新可视化窗口 viewer.updateText(iterations_cnt, 10, 60, 16, txt_gray_lvl, txt_gray_lvl,txt_gray_lvl,"iterations_cnt"); viewer.updatePointCloud(cloud_icp, cloud_icp_color_h, "cloud_icp_v2"); } else { PCL_ERROR("\nICP has not converged.\n"); return (-1); } } next_iteration = false; //键盘按c,则ICP配准结束,退出循环 if (end_iteration == true) { viewer.close(); break; } } printf("ICP over!\n"); // plywriter.write("add_colour.ply", *down_cloud_tr); system("pause"); return (0); }

 


最新回复(0)