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

来源:互联网 发布:java判断date是否相等 编辑:程序博客网 时间:2024/05/19 14:51

1、单点选取程序:

cpp:

#include <pcl/io/pcd_io.h>#include <pcl/point_cloud.h>#include <pcl/point_types.h>#include <pcl/visualization/pcl_visualizer.h>typedef pcl::PointXYZRGBA PointT;typedef pcl::PointCloud<PointT> PointCloudT;// Mutex: //boost::mutex cloud_mutex;struct callback_args{// structure used to pass arguments to the callback functionPointCloudT::Ptr clicked_points_3d;pcl::visualization::PCLVisualizer::Ptr viewerPtr;};voidpp_callback(const pcl::visualization::PointPickingEvent& event, void* args){struct callback_args* data = (struct callback_args *)args;if (event.getPointIndex() == -1)return;PointT current_point;event.getPoint(current_point.x, current_point.y, current_point.z);data->clicked_points_3d->points.push_back(current_point);// Draw clicked points in red:pcl::visualization::PointCloudColorHandlerCustom<PointT> red(data->clicked_points_3d, 255, 0, 0);data->viewerPtr->removePointCloud("clicked_points");data->viewerPtr->addPointCloud(data->clicked_points_3d, red, "clicked_points");data->viewerPtr->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");std::cout << current_point.x << " " << current_point.y << " " << current_point.z << std::endl;}void main(){std::string filename("bunny.pcd");//visualizerpcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("viewer"));if (pcl::io::loadPCDFile(filename, *cloud)){std::cerr << "ERROR: Cannot open file " << filename << "! Aborting..." << std::endl;return;}std::cout << cloud->points.size() << std::endl;//viewer->addPointCloud(cloud, "bunny");cloud_mutex.lock();    // for not overwriting the point cloud// Display pointcloud:viewer->addPointCloud(cloud, "bunny");viewer->setCameraPosition(0, 0, -2, 0, -1, 0, 0);// Add point picking callback to viewer:struct callback_args cb_args;PointCloudT::Ptr clicked_points_3d(new PointCloudT);cb_args.clicked_points_3d = clicked_points_3d;cb_args.viewerPtr = pcl::visualization::PCLVisualizer::Ptr(viewer);viewer->registerPointPickingCallback(pp_callback, (void*)&cb_args);std::cout << "Shift+click on three floor points, then press 'Q'..." << std::endl;// Spin until 'Q' is pressed:viewer->spin();std::cout << "done." << std::endl;cloud_mutex.unlock();while (!viewer->wasStopped()){viewer->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}}

编译运行:


注:使用shift键配合鼠标选点。


2、区域选点

#include <pcl/io/pcd_io.h>#include <pcl/point_cloud.h>#include <pcl/point_types.h>#include <pcl/visualization/pcl_visualizer.h>#include <iostream>#include <vector>pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("viewer"));pcl::PointCloud<pcl::PointXYZ>::Ptr clicked_points_3d(new pcl::PointCloud<pcl::PointXYZ>);int num = 0;void pp_callback(const pcl::visualization::AreaPickingEvent& event, void* args){    std::vector< int > indices;    if (event.getPointsIndices(indices)==-1)        return;    for (int i = 0; i < indices.size(); ++i)    {        clicked_points_3d->points.push_back(cloud->points.at(indices[i]));    }    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> red(clicked_points_3d, 255, 0, 0);    std::stringstream ss;    std::string cloudName;    ss << num++;    ss >> cloudName;    cloudName += "_cloudName";    viewer->addPointCloud(clicked_points_3d, red, cloudName);    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, cloudName);}void main(){    if (pcl::io::loadPCDFile("bunny.pcd", *cloud))    {        std::cerr << "ERROR: Cannot open file " << std::endl;        return;    }    viewer->addPointCloud(cloud, "bunny");    viewer->setCameraPosition(0, 0, -2, 0, -1, 0, 0);    viewer->registerAreaPickingCallback(pp_callback, (void*)&cloud);    while (!viewer->wasStopped())    {        viewer->spinOnce(100);        boost::this_thread::sleep(boost::posix_time::microseconds(100000));    }}

编译运行:


注:使用x键配合鼠标左键选择区域,同时再按下x取消框选。


3、单点选择:

程序中对所以的鼠标点都会罗列在控制台中,和第一个有点差异

cpp:

#include <pcl/io/pcd_io.h>  #include <pcl/point_cloud.h>  #include <pcl/point_types.h>  #include <pcl/visualization/pcl_visualizer.h>  typedef pcl::PointXYZRGBA PointT_XYZ;typedef pcl::PointCloud<PointT_XYZ> PointCloudT_XYZ;// Mutex: //  boost::mutex cloud_mutex;struct callback_args{// structure used to pass arguments to the callback function  PointCloudT_XYZ::Ptr clicked_points_3d;pcl::visualization::PCLVisualizer::Ptr viewerPtr;};voidpp_callback(const pcl::visualization::PointPickingEvent& event, void* args){struct callback_args* data = (struct callback_args *)args;std::cout << "Picking event active" << std::endl;PointT_XYZ current_point;if (event.getPointIndex() != -1){float x, y, z;event.getPoint(current_point.x, current_point.y, current_point.z);//std::cout << x << ";" << y << ";" << z << std::endl;data->clicked_points_3d->points.push_back(current_point);}// Draw clicked points in red:  pcl::visualization::PointCloudColorHandlerCustom<PointT_XYZ> red(data->clicked_points_3d, 255, 0, 0);data->viewerPtr->removePointCloud("clicked_points");data->viewerPtr->addPointCloud(data->clicked_points_3d, red, "clicked_points");data->viewerPtr->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");std::cout << current_point.x << " " << current_point.y << " " << current_point.z << std::endl;}void main(){//visualizer  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("viewer"));pcl::io::loadPCDFile("Bunny.pcd", *cloud);//viewer->addPointCloud(cloud, "bunny");  cloud_mutex.lock();    // for not overwriting the point cloud  // Display pointcloud:  viewer->addPointCloud(cloud, "bunny");// Add point picking callback to viewer:  struct callback_args cb_args;PointCloudT_XYZ::Ptr clicked_points_3d(new PointCloudT_XYZ);cb_args.clicked_points_3d = clicked_points_3d;cb_args.viewerPtr = pcl::visualization::PCLVisualizer::Ptr(viewer);viewer->registerPointPickingCallback(pp_callback, (void*)&cb_args);std::cout << "Shift+click on three floor points, then press 'Q'..." << std::endl;// Spin until 'Q' is pressed:  viewer->spin();std::cout << "done." << std::endl;cloud_mutex.unlock();while (!viewer->wasStopped()){viewer->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}}



*4、选点程序,没有标出点,注意,要输入三个数才能进行操作,如1 1 1,按C键可以显示信息

cpp:

#include <pcl/point_cloud.h>  #include <pcl/PCLPointCloud2.h>  #include <pcl/io/io.h>  #include <pcl/io/pcd_io.h>  #include <pcl/common/io.h>  #include <pcl/io/ply_io.h>  #include <pcl/io/vtk_lib_io.h>  #include <pcl/visualization/pcl_visualizer.h>  using namespace pcl;using namespace std;class pickPoints {public:pickPoints::pickPoints() {viewer.reset(new pcl::visualization::PCLVisualizer("Viewer", true));viewer->registerPointPickingCallback(&pickPoints::pickCallback, *this);}~pickPoints() {}void setInputCloud(PointCloud<PointXYZ>::Ptr cloud){cloudTemp = cloud;}vector<float> getpoints() {return p;}void simpleViewer(){// Visualizer  viewer->addPointCloud<pcl::PointXYZ>(cloudTemp, "Cloud");viewer->resetCameraViewpoint("Cloud");viewer->spin();}protected:void pickCallback(const pcl::visualization::PointPickingEvent& event, void*){if (event.getPointIndex() == -1)return;PointXYZ picked_point1, picked_point2;event.getPoints(picked_point1.x, picked_point1.y, picked_point1.z,picked_point2.x, picked_point2.y, picked_point2.z);p.push_back(picked_point1.x); // store points  p.push_back(picked_point1.y);p.push_back(picked_point1.z);p.push_back(picked_point2.x);p.push_back(picked_point2.y);p.push_back(picked_point2.z);//cout<<"first selected point: "<<p[0]<<" "<<p[1]<<" "<<p[2]<<endl;  //cout<<"second selected point: "<<p[3]<<" "<<p[4]<<" "<<p[5]<<endl;  ////pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> red(p->clicked_points_3d, 255, 0, 0);////data->viewerPtr->removePointCloud("clicked_points");////data->viewerPtr->addPointCloud(data->clicked_points_3d, red, "clicked_points");////data->viewerPtr->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");////std::cout << current_point.x << " " << current_point.y << " " << current_point.z << std::endl;}private:// Point cloud data   PointCloud<pcl::PointXYZ>::Ptr cloudTemp;// The visualizer   boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;// The picked point   vector<float> p;};int main(){//LOAD;  PointCloud<PointXYZ>::Ptr cloud(new PointCloud<PointXYZ>());pcl::PolygonMesh mesh;pcl::io::loadPCDFile("Bunny.pcd", *cloud);//pcl::fromPCLPointCloud2(mesh.cloud, *cloud);pickPoints pickViewer;pickViewer.setInputCloud(cloud); // A pointer to a cloud   pickViewer.simpleViewer();vector<float> pointSelected;pointSelected = pickViewer.getpoints();cout << pointSelected[0] << " " << pointSelected[1] << " " << pointSelected[2] << endl;cout << pointSelected[3] << " " << pointSelected[4] << " " << pointSelected[5] << endl;cin.get();return 0;}

5、整合到Qt+VTK的界面中的技巧:

参看博文

http://blog.csdn.net/hopedengxiwang/article/details/6940719,

http://stackoverflow.com/questions/14267895/error-with-callback-function?answertab=active#tab-top,

http://stackoverflow.com/questions/9596276/how-to-explain-callbacks-in-plain-english-how-are-they-different-from-calling-o:

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

如何在类中封装回调函数(第一个链接)

我们知道回调函数只能是全局的或是静态的。
全局函数会破坏类的封装性,故不予采用。
而静态函数只能访问类的静态成员,不能访问类中非静态成员。

那么如何让静态函数访问类的非静态成员呢?
1).声明一静态函数a(),将类实例对象指针做为参数传入。如:
class A()
{
static void a(A *); //静态函数
void b(); //非静态函数
}
void A::a(A * pThis)
{
pThis->b(); //静态函数中调用非静态函数
}

2).回调函数中访问非静态成员
由于回调函数往往有固定定义,并不接受 A * pThis 参数
如:CALLBACK MyTimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);

【解决方案1】:本方案当遇到有多个类实例对象时会有问题。原因是pThis指针只能指向一个对象。
class A()
{
static void a(); //静态回调函数
void b(); //非静态函数
static A * pThis; //静态对象指针
}

A * A::pThis=NULL;
A::A() //构造函数中将this指针赋给pThis,使得回调函数能通过pThis指针访问本对象
{
pThis=this;
}
void A::a()
{
if (pThis==NULL) return;
pThis->b(); //回调函数中调用非静态函数
}

【解决方案2】:本方案解决多个类实例对象时方案1的问题。用映射表存所有对象地址,每个对象保存自己的ID号。
typedef CMap<UINT,UINT,A*,A*> CAMap;
class A()
{
static void a(); //静态回调函数
void b(); //非静态函数
int m_ID; //本对象在列表中的ID号
static int m_SID; //静态当前对象ID (需要时,将m_ID赋值给m_SID以起到调用本对象函数的功能)
static CAMap m_Map; //静态对象映射表
}

CAMap A::m_Map;
int A::m_SID=0;

A::A() //构造函数中将this指针赋给pThis,使得回调函数能通过pThis指针访问本对象
{
if(m_Map.IsEmpty())
{
m_ID=1;
}
else
{
m_ID=m_Map.GetCount()+1;
}
m_Map.SetAt( m_ID, this );
}
void A::a()
{
if (m_Map.IsEmpty()) return;
A * pThis=NULL;
if(m_Map.Lookup(m_SID,pThis))
{
pThis->b(); //回调函数中调用非静态函数
};
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

参考下,仔细琢磨一下,可以实现在Qt中的选点功能。