当前位置:   article > 正文

PCL可视化-点选、框选(封装为类)_viewer->removepointcloud

viewer->removepointcloud

Pcl开发的应用中,当需要用户对点云做一些操作的时候,需要从屏幕拾取点云中某点的三维坐标。关于如何运用PCL实现这部分功能,很多介绍都是基于控制台程序的,调用写在main函数里,但是大部分时候,我们需要把这些事情封装在类中,这时候有一些小小的差别。

这次学习主要是记录了对回调机制的理解,封装pcl的选点的回调函数为类的成员函数,完成拾取屏幕坐标点的功能,也记录下完整的类和调用部分的代码。   

 

一、关键函数(中间函数)

在理解代码之前,要先明确三个概念:中间函数、回调函数、起始函数。

回调函数最好理解,是作为参数被传入的、后又被调用的函数。中间函数,是需要回调函数作为参数的那个函数,在第三方库中应用回调,通常是库函数去担任中间函数的角色。在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为,因此程序变得灵活。最后是起始函数,起始函数和回调函数是属于同一层级的函数,是中间函数的调用者,虽然这个函数可能就一两行,但是理解起始函数的作用对理解回调机制也很重要。

这三个部分共同作用,实现回调,有了高层(起始函数)调用底层(中间函数),底层再回过头来调用高层(回调函数)的过程,应该就是"回调"的含义。

 

(一)点云的点选功能

A.中间函数:registerPointPickingCallback

 函数第二个参数涉及的类:pcl::visualization::PointPickingEvent,是我们写回调函数的时候第一个参数的类类型。

(二)点云的框选功能:

A.中间函数:registerAreaPickingCallback()

 函数第二个参数涉及的类:pcl::visualization::AreaPickingEvent:,是我们写回调函数的时候第一个参数的类类型。

B.bool pcl::visualization::AreaPickingEvent::getPointsIndices ( std::vector< int > & indices ) const

利用此函数可以获取视窗中选择的点云数据的索引,根据索引又可以获得确定的离散点数据。

二、封装在类中

差别主要是registerKeyboardCallback函数的调用。在大部分的例子中,都是在控制台程序的main函数中直接调用,只有两个参数,非类中调用的函数原型;

  1. registerKeyboardCallback (
  2. void (*callback) (const pcl::visualization::KeyboardEvent&, void*),
  3. void* cookie = NULL)

其中,KeyboardEvent是我们自定义的函数,在这里它是一个回调函数。也就是是一个通过函数指针来调用的函数。需要把函数的指针(地址)作为参数传递给另一个函数,用这个指针被用来调用其所指向的函数时。KeyboardEvent在里面包含了我们在点击、框选等动作时的处理声明。

当keyboard_callback函数是类的一部分时,需要指定类的实例,以便编译器能够确定要使用keyboard_callback函数的实例。这里调用的函数的参数传递有了差别,多了第二个参数 T& instance:调用这个中间函数的类的实例,可以传this指针。

  1. registerKeyboardCallback (
  2. void (T::*callback) (const pcl::visualization::KeyboardEvent&, void*),
  3. T& instance,
  4. void* cookie = NULL)

 

三、完整代码 

1、.h

  1. #pragma once
  2. #include "stdafx.h"
  3. #include "utility.h"
  4. #include <fstream>
  5. #include <pcl/io/pcd_io.h>
  6. #include <pcl/point_cloud.h>
  7. #include <pcl/point_types.h>
  8. #include <pcl/visualization/cloud_viewer.h>
  9. #include <iostream>
  10. #include <pcl/io/io.h>
  11. #include <pcl/io/ply_io.h>
  12. #include <iostream>
  13. #include <pcl/console/parse.h>
  14. using namespace pcl;
  15. typedef pcl::PointXYZ PointT;
  16. typedef pcl::PointCloud<PointT> PointCloudT;
  17. class PtPicking
  18. {
  19. public:
  20. PtPicking(std::string filename);
  21. void reset();
  22. ~PtPicking();
  23. void keyboardEventOccurred(const visualization::KeyboardEvent &event, void* junk);
  24. void areaPicking(); //框选点云、
  25. void pointPicking(); //单点选取
  26. void ptActicPicking(); //屏幕选点
  27. pcl::PointXYZ randomPoint();
  28. void spin();
  29. protected:
  30. boost::mutex cloud_mutex;
  31. int num = 0;
  32. boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;
  33. pcl::PointCloud<pcl::PointXYZ>::Ptr baseCloud; //加载的原始点云
  34. pcl::PointCloud<pcl::PointXYZ>::Ptr clicked_points_3d; //被选中的点云,可以用reset充值
  35. void areaPicking_callback(const pcl::visualization::AreaPickingEvent & event, void * args);
  36. void pointPicking_callback(const pcl::visualization::PointPickingEvent & event, void * args);
  37. void PtActivePick_callback(const pcl::visualization::PointPickingEvent & event, void * args);
  38. };

2、.cpp

  1. #pragma once
  2. #include "stdafx.h"
  3. #include "PtPicking.h"
  4. PtPicking::~PtPicking()
  5. {
  6. }
  7. PtPicking::PtPicking(std::string filename) {
  8. clicked_points_3d.reset(new pcl::PointCloud<PointT>);
  9. baseCloud.reset(new pcl::PointCloud<PointT>());
  10. if (pcl::io::loadPCDFile(filename, *baseCloud))
  11. {
  12. std::cerr << "ERROR: Cannot open file " << filename << "! Aborting..." << std::endl;
  13. return;
  14. }
  15. reset();
  16. };
  17. void PtPicking:: reset()
  18. {
  19. // Create cloud
  20. clicked_points_3d.reset(new pcl::PointCloud<PointT>);
  21. // Create viewer
  22. viewer.reset(new pcl::visualization::PCLVisualizer("viewer"));
  23. viewer->addCoordinateSystem(1);
  24. viewer->addPointCloud(baseCloud, "cloud");
  25. viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud");
  26. }
  27. void PtPicking::keyboardEventOccurred(const visualization::KeyboardEvent &event, void* junk) {
  28. if (event.getKeySym() == "r" && event.keyDown()) {
  29. baseCloud->push_back(randomPoint());
  30. viewer->updatePointCloud(baseCloud, "cloud");
  31. }
  32. };
  33. //框选事件的调用
  34. void PtPicking::areaPicking()
  35. {
  36. // Register Keyboard Event
  37. //viewer->registerKeyboardCallback(&dummyClass::keyboardEventOccurred, *this);
  38. viewer->registerAreaPickingCallback(&PtPicking::areaPicking_callback, *this);//由于点云数据写成了成员变量,所以这里第三个参数不用传
  39. std::cout << "press X to strat or ending picking, then press 'Q'..." << std::endl;
  40. }
  41. //点选的调用
  42. void PtPicking::pointPicking()
  43. {
  44. cloud_mutex.lock(); // for not overwriting the point cloud
  45. viewer->registerPointPickingCallback(&PtPicking::pointPicking_callback, *this);
  46. std::cout << "Shift+click on three floor points, then press 'Q'..." << std::endl;
  47. cloud_mutex.unlock();
  48. }
  49. //点选的调用(这个比较灵活,可选屏幕任意位置)
  50. void PtPicking::ptActicPicking()
  51. {
  52. cloud_mutex.lock(); // for not overwriting the point cloud
  53. viewer->registerPointPickingCallback(&PtPicking::PtActivePick_callback, *this);
  54. std::cout << "Shift+click on three floor points, then press 'Q'..." << std::endl;
  55. cloud_mutex.unlock();
  56. }
  57. //框选事件的回调函数,
  58. //款选屏幕上的一部分点云
  59. //选择方式:输入一个x表示开始或者结束。两次x输入期间用鼠标左键框选点云,可以多次框选。输入q则腿粗选择
  60. void PtPicking::areaPicking_callback(const pcl::visualization::AreaPickingEvent& event, void *args)
  61. {
  62. struct callback_args * data = (struct callback_args *)args;//点云数据 & 可视化窗口
  63. std::vector<int > indices;
  64. if (event.getPointsIndices(indices) == false)
  65. return;
  66. for (size_t i = 0; i < indices.size(); i++)
  67. {
  68. clicked_points_3d->points.push_back(baseCloud->points.at(indices[i]));
  69. }
  70. pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> red(clicked_points_3d, 255, 0, 0);
  71. viewer->removePointCloud("clicked_points");
  72. viewer->addPointCloud(clicked_points_3d, red, "clicked_points");
  73. viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");
  74. for (int i = 0; i < clicked_points_3d->points.size(); i++)
  75. std::cout << clicked_points_3d->points[i].x << std::endl;
  76. std::cout << "clicked_points_3d->points.size()" << clicked_points_3d->points.size() << std::endl;
  77. }
  78. //点选事件的回调函数
  79. //点选屏幕上的点云
  80. //选择方式:按住shift,鼠标左键点选
  81. void PtPicking::pointPicking_callback(const pcl::visualization::PointPickingEvent& event, void *args)
  82. {
  83. struct callback_args * data = (struct callback_args *)args;//点云数据 & 可视化窗口
  84. if (event.getPointIndex() == -1)
  85. return;
  86. PointT current_point;
  87. event.getPoint(current_point.x, current_point.y, current_point.z);
  88. clicked_points_3d->points.push_back(current_point);
  89. //Draw clicked points in red:
  90. pcl::visualization::PointCloudColorHandlerCustom<PointT> red(clicked_points_3d, 255, 0, 0);
  91. viewer->removePointCloud("clicked_points");
  92. viewer->addPointCloud(clicked_points_3d, red, "clicked_points");
  93. viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");
  94. std::cout << current_point.x << " " << current_point.y << " " << current_point.z << std::endl;
  95. }
  96. //点选事件的回调函数
  97. //点选事件——点击屏幕上的任一点(pointPicking_callback()是一定要点击点云数据上的点)
  98. //选择方式:按住shift,鼠标左键选择。键盘输入 Q 则退出选择
  99. void PtPicking::PtActivePick_callback(const pcl::visualization::PointPickingEvent& event, void *args)
  100. {
  101. std::cout << "Picking event active" << std::endl;
  102. PointT current_point;
  103. if (event.getPointIndex() != -1)
  104. {
  105. float x, y, z;
  106. event.getPoint(current_point.x, current_point.y, current_point.z);
  107. //std::cout << x << ";" << y << ";" << z << std::endl;
  108. clicked_points_3d->points.push_back(current_point);
  109. }
  110. // Draw clicked points in red:
  111. pcl::visualization::PointCloudColorHandlerCustom<PointT> red(clicked_points_3d, 255, 0, 0);
  112. viewer->removePointCloud("clicked_points");
  113. viewer->addPointCloud(clicked_points_3d, red, "clicked_points");
  114. viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");
  115. std::cout << current_point.x << " " << current_point.y << " " << current_point.z << std::endl;
  116. }
  117. pcl::PointXYZ PtPicking::randomPoint() {
  118. pcl::PointXYZ pt;
  119. pt.x = (double)rand() / RAND_MAX * 10 - 5;
  120. pt.y = (double)rand() / RAND_MAX * 10 - 5;
  121. pt.z = (double)rand() / RAND_MAX * 10 - 5;
  122. return pt;
  123. };
  124. void PtPicking::spin() {
  125. viewer->spin();
  126. };

3、调用的方法

调用时需要输入pcd文件路径

  1. char filePCD[32];
  2. printf("请输入pcd文件路径");
  3. scanf("%s", filePCD);/*输入文件名*/
  4. PtPicking dc(filePCD);
  5. //dc.pointPicking();
  6. //dc.ptActicPicking();
  7. dc.areaPicking();
  8. dc.spin();

参考链接

基于PCL的屏幕选点、框选点云、单点选取等c++实现 

封装在类中的例子 

回调机制的理解 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/394216
推荐阅读
  

闽ICP备14008679号