该程序将加载点云并对其进行刚性变换。之后,使用ICP算法将变换后的点云与原来的点云对齐。每次用户按下“空格”,进行ICP迭代,刷新可视化界面。
#include <iostream> #include <string> #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 #pragma comment(lib,"User32.lib") #pragma comment(lib, "gdi32.lib") typedef pcl::PointXYZ PointT; typedef pcl::PointCloud<PointT> PointCloudT; bool next_iteration = false; void print4x4Matrix(const Eigen::Matrix4d & matrix) { printf("Rotation matrix :\n"); printf(" | %6.3f %6.3f %6.3f | \n", matrix(0, 0), matrix(0, 1), matrix(0, 2)); printf("R = | %6.3f %6.3f %6.3f | \n", matrix(1, 0), matrix(1, 1), matrix(1, 2)); printf(" | %6.3f %6.3f %6.3f | \n", matrix(2, 0), matrix(2, 1), matrix(2, 2)); printf("Translation vector :\n"); printf("t = < %6.3f, %6.3f, %6.3f >\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; } int main(int argc, char* argv[]) { // 我们要使用的点云 PointCloudT::Ptr cloud_in(new PointCloudT); // 初始点云 PointCloudT::Ptr cloud_tr(new PointCloudT); // 转换点云 PointCloudT::Ptr cloud_icp(new PointCloudT); // 输出点云 // 检查输入参数 // if (argc < 2) // { // printf("Usage :\n"); // printf("\t\t%s file.ply number_of_ICP_iterations\n", argv[0]); // PCL_ERROR("Provide one ply file.\n"); // return (-1); // } int iterations = 1; // 默认ICP配准的迭代次数 // if (argc > 2) // { // iterations = atoi(argv[2]);//将字符串变量转换为整数变量 // if (iterations < 1) // { // PCL_ERROR("Number of initial iterations must be >= 1\n"); // return (-1); // } // } pcl::console::TicToc time; time.tic(); if (pcl::io::loadPLYFile("monkey.ply", *cloud_in) < 0) { PCL_ERROR("Error loading cloud %s.\n", argv[1]); return (-1); } std::cout << "\nLoaded file " <<"monkey.ply"<< " (" << cloud_in->size() << " points) in " << time.toc() << " ms\n" << std::endl; // 定义旋转矩阵和平移矩阵 Eigen::Matrix4d transformation_matrix = Eigen::Matrix4d::Identity(); // 旋转矩阵的具体定义 (请参考 https://en.wikipedia.org/wiki/Rotation_matrix) double theta = M_PI / 20; // 设置旋转弧度的角度 transformation_matrix(0, 0) = cos(theta); transformation_matrix(0, 1) = -sin(theta); transformation_matrix(1, 0) = sin(theta); transformation_matrix(1, 1) = cos(theta); // 设置平移矩阵 transformation_matrix(0, 3) = 0.0; transformation_matrix(1, 3) = 0.0; transformation_matrix(2, 3) = 0.0; // 在终端输出转换矩阵 std::cout << "Applying this rigid transformation to: cloud_in -> cloud_icp" << std::endl; print4x4Matrix(transformation_matrix); // 执行初始变换 pcl::transformPointCloud(*cloud_in, *cloud_icp, transformation_matrix);//绕z轴旋转theta,无平移变换 *cloud_tr = *cloud_icp; // 将cloud_icp变量备份 // 设置ICP配准算法输入参数 time.tic(); pcl::IterativeClosestPoint<PointT, PointT> icp; icp.setMaximumIterations(iterations);//设置迭代次数 icp.setInputSource(cloud_icp); icp.setInputTarget(cloud_in); icp.align(*cloud_icp); icp.setMaximumIterations(1); // 当再次调用.align ()函数时,我们设置该变量为1。 std::cout << "Applied " << iterations << " ICP iteration(s) in " << time.toc() << " ms" << std::endl; //检查icp算法是否收敛,如果不收敛,退出程序 if (icp.hasConverged()) { std::cout << "\nICP has converged, score is " << icp.getFitnessScore() << std::endl; std::cout << "\nICP transformation " << iterations << " : cloud_icp -> cloud_in" << 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; // 黑色 float txt_gray_lvl = 1.0 - bckgr_gray_level; // 设置初始点云为白色 pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_in_color_h(cloud_in, (int)255 * txt_gray_lvl, (int)255 * txt_gray_lvl, (int)255 * txt_gray_lvl);//赋予显示点云的颜色 viewer.addPointCloud(cloud_in, cloud_in_color_h, "cloud_in_v1", v1); viewer.addPointCloud(cloud_in, cloud_in_color_h, "cloud_in_v2", v2); // 设置初始转换后的点云为绿色 pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_tr_color_h(cloud_tr, 20, 180, 20); viewer.addPointCloud(cloud_tr, cloud_tr_color_h, "cloud_tr_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: Original point cloud\nGreen: Matrix transformed point cloud", 10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_1", v1); viewer.addText("White: Original point cloud\nRed: ICP aligned point cloud", 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(); //用户按下空格键 if (next_iteration) { // 配准算法开始迭代 time.tic(); icp.align(*cloud_icp); std::cout << "Applied 1 ICP iteration in " << time.toc() << " ms" << std::endl; if (icp.hasConverged()) { printf("\033[11A"); printf("\nICP has converged, score is %+.0e\n", icp.getFitnessScore()); std::cout << "\nICP transformation " << ++iterations << " : cloud_icp -> cloud_in" << std::endl; transformation_matrix *= icp.getFinalTransformation().cast<double>(); // 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; } system("pause"); return (0); } #include <iostream> #include <string> #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 typedef pcl::PointXYZ PointT; typedef pcl::PointCloud<PointT> PointCloudT; bool next_iteration = false; void print4x4Matrix (const Eigen::Matrix4d & matrix) { printf ("Rotation matrix :\n"); printf (" | %6.3f %6.3f %6.3f | \n", matrix (0, 0), matrix (0, 1), matrix (0, 2)); printf ("R = | %6.3f %6.3f %6.3f | \n", matrix (1, 0), matrix (1, 1), matrix (1, 2)); printf (" | %6.3f %6.3f %6.3f | \n", matrix (2, 0), matrix (2, 1), matrix (2, 2)); printf ("Translation vector :\n"); printf ("t = < %6.3f, %6.3f, %6.3f >\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; } int main (int argc, char* argv[]) { // 我们要使用的点云 PointCloudT::Ptr cloud_in (new PointCloudT); // 初始点云 PointCloudT::Ptr cloud_tr (new PointCloudT); // 转换点云 PointCloudT::Ptr cloud_icp (new PointCloudT); // 输出点云 // 检查输入参数 if (argc < 2) { printf ("Usage :\n"); printf ("\t\t%s file.ply number_of_ICP_iterations\n", argv[0]); PCL_ERROR ("Provide one ply file.\n"); return (-1); } int iterations = 1; // 默认ICP配准的迭代次数 if (argc > 2) { iterations = atoi (argv[2]);//将字符串变量转换为整数变量 if (iterations < 1) { PCL_ERROR ("Number of initial iterations must be >= 1\n"); return (-1); } } pcl::console::TicToc time; time.tic (); if (pcl::io::loadPLYFile (argv[1], *cloud_in) < 0) { PCL_ERROR ("Error loading cloud %s.\n", argv[1]); return (-1); } std::cout << "\nLoaded file " << argv[1] << " (" << cloud_in->size () << " points) in " << time.toc () << " ms\n" << std::endl; // 定义旋转矩阵和平移矩阵 Eigen::Matrix4d transformation_matrix = Eigen::Matrix4d::Identity (); // 旋转矩阵的具体定义 (请参考 https://en.wikipedia.org/wiki/Rotation_matrix) double theta = M_PI / 20; // 设置旋转弧度的角度 transformation_matrix (0, 0) = cos (theta); transformation_matrix (0, 1) = -sin (theta); transformation_matrix (1, 0) = sin (theta); transformation_matrix (1, 1) = cos (theta); // 设置平移矩阵 transformation_matrix (0, 3) = 0.0; transformation_matrix (1, 3) = 0.0; transformation_matrix (2, 3) = 0.0; // 在终端输出转换矩阵 std::cout << "Applying this rigid transformation to: cloud_in -> cloud_icp" << std::endl; print4x4Matrix (transformation_matrix); // 执行初始变换 pcl::transformPointCloud (*cloud_in, *cloud_icp, transformation_matrix);//绕z轴旋转theta,无平移变换 *cloud_tr = *cloud_icp; // 将cloud_icp变量备份 // 设置ICP配准算法输入参数 time.tic (); pcl::IterativeClosestPoint<PointT, PointT> icp; icp.setMaximumIterations (iterations);//设置迭代次数 icp.setInputSource (cloud_icp); icp.setInputTarget (cloud_in); icp.align (*cloud_icp); icp.setMaximumIterations (1); // 当再次调用.align ()函数时,我们设置该变量为1。 std::cout << "Applied " << iterations << " ICP iteration(s) in " << time.toc () << " ms" << std::endl; //检查icp算法是否收敛,如果不收敛,退出程序 if (icp.hasConverged ()) { std::cout << "\nICP has converged, score is " << icp.getFitnessScore () << std::endl; std::cout << "\nICP transformation " << iterations << " : cloud_icp -> cloud_in" << 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; // 黑色 float txt_gray_lvl = 1.0 - bckgr_gray_level; // 设置初始点云为白色 pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_in_color_h (cloud_in, (int) 255 * txt_gray_lvl, (int) 255 * txt_gray_lvl, (int) 255 * txt_gray_lvl);//赋予显示点云的颜色 viewer.addPointCloud (cloud_in, cloud_in_color_h, "cloud_in_v1", v1); viewer.addPointCloud (cloud_in, cloud_in_color_h, "cloud_in_v2", v2); // 设置初始转换后的点云为绿色 pcl::visualization::PointCloudColorHandlerCustom<PointT> cloud_tr_color_h (cloud_tr, 20, 180, 20); viewer.addPointCloud (cloud_tr, cloud_tr_color_h, "cloud_tr_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: Original point cloud\nGreen: Matrix transformed point cloud", 10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_1", v1); viewer.addText ("White: Original point cloud\nRed: ICP aligned point cloud", 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 (); // 用户按下空格键 if (next_iteration) { // 配准算法开始迭代 time.tic (); icp.align (*cloud_icp); std::cout << "Applied 1 ICP iteration in " << time.toc () << " ms" << std::endl; if (icp.hasConverged ()) { printf ("\033[11A"); printf ("\nICP has converged, score is %+.0e\n", icp.getFitnessScore ()); std::cout << "\nICP transformation " << ++iterations << " : cloud_icp -> cloud_in" << std::endl; transformation_matrix *= icp.getFinalTransformation ().cast<double>(); // 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; } return (0); }