PCL:交互式ICP可视化

该程序将加载点云并对其进行刚性变换。之后,使用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);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值