该功能暂未实现,诚邀大神指点,感激不尽!
目录:
问题介绍
本人基于PCL1.8.0+Qt5.7.0+VS2013开发三维点云数据处理软件,其中一项功能是拾取屏幕三维点坐标,并将其三维坐标显示在一个子窗口对话框中。
功能流程描述
- 主窗口菜单栏点击拾取三维点按钮,弹出显示结果的非模态子窗口对话框;
- 根据PCL点云库定义,按住Shift+鼠标左键选取可视化窗口的数据点;
- 设置该点size为10并红色显示,加以区分;
- 子窗口对话框中lineEdit控件显示该点三维坐标;
- 如果选择其他点,则刷新屏幕渲染,并刷新子窗口坐标显示。
现在进展
- 在控制台应用程序下,可以顺利实现该功能;
- 将代码整合到自己的应用程序中,回调函数执行阶段异常。
代码
官方示例源码
(http://www.pointclouds.org/documentation/tutorials/ground_based_rgbd_people_detection.php)
控制台应用程序代码
可顺利实现。
#include <iostream>
#include <vector>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <boost/concept_check.hpp>
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
boost::mutex cloud_mutex;//进程锁
// 用于传给回调函数的结构体定义
struct callback_args
{
PointCloudT::Ptr clicked_points_3d;
pcl::visualization::PCLVisualizer::Ptr viewerPtr;
};
//回调函数
void pp_callback(const pcl::visualization::PointPickingEvent& event, void* args)
//void pp_callback(const pcl::visualization::PointPickingEvent& event, struct callback_args* 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->clear();//将上次选的点清空
data->clicked_points_3d->points.push_back(current_point);//添加新选择的点
// 设置屏幕渲染属性,红色显示选择的点
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 pointpicking()
{
std::string filename("E:\\Date\\12.pcd");
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
//定义可视化窗口viewer
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;
cloud_mutex.lock(); // 获得互斥体,期间不能修改点云
// 显示点云
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);
//Shift+鼠标左键选择点,按Q结束
std::cout << "Shift+click on points, end by pressing '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));
}
}
int main()
{
pointpicking();
std::cout << "程序结束"<<std::endl ;
return 0;
}
结果如下:
集成到Qt应用程序中
还未顺利实现,此处涉及到不少C++的知识,本人也是基础薄弱,所以问题百出,下面的代码中也有诸多不规范甚至错误之处,欢迎大神指点。
qtapplication.h
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
class QtApplication : public QMainWindow
{
Q_OBJECT
public:
QtApplication(QWidget *parent = 0);
~QtApplication();
//声明静态回调函数
static void SelectPoint_callback(const pcl::visualization::PointPickingEvent& event, void* args);
//静态对象指针
static QtApplication *pThis;
//一个传递函数,获取回调函数中得到的点,然后访问QtApplication中的私有成员加以显示
void PointPickingShow(pcl::PointXYZRGBA current_point);
//互斥锁
boost::mutex cloud_mutex;
// 用于将参数传递给回调函数的结构
struct callback_args
{
PointCloudT::Ptr clicked_points_3d;
pcl::visualization::PCLVisualizer::Ptr viewerPtr;
};
private:
Ui::QtApplicationClass ui;
//。。。。。略
private slots:
//选择点的槽函数定义
void SelectPoint();
}
qtapplication.cpp
//静态对象指针初始化
QtApplication * QtApplication::pThis = NULL;
//构造函数
QtApplication::QtApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
pThis = this;//构造函数中将this指针赋给pThis,使得回调函数能通过pThis指针访问本对象
//初始化
initial();
//。。。略
//菜单栏信号和槽函数连接
QObject::connect(ui.action_SelectPoint, &QAction::triggered, this, &QtApplication::SelectPoint);
//。。。略
}
//拾取屏幕三维点坐标 暂未实现
void QtApplication::SelectPoint_callback(const pcl::visualization::PointPickingEvent& event, void* args)
{
if (pThis == NULL) return;
struct callback_args* data = (struct callback_args *)args;//报错位置,data无法读取内存
if (event.getPointIndex() == -1) return;
PointT current_point;
event.getPoint(current_point.x, current_point.y, current_point.z);
data->clicked_points_3d->push_back(current_point);
// 设置渲染属性,暂时想法是下面几句注释掉,将渲染放在下面的函数中实现,这里只把获取到的current_point传过去
//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");
//将获取到的点传给成员函数,访问QtApplication成员显示坐标
pThis->PointPickingShow(current_point);
}
void QtApplication::PointPickingShow(pcl::PointXYZRGBA current_point)
{
//接收获取到的点,刷新渲染,子窗口中显示其三维坐标
pcl::PointCloud<PointT>::Ptr cloud_temp;
cloud_temp->push_back(current_point);
pcl::visualization::PointCloudColorHandlerCustom<PointT> red(cloud_temp, 255, 0, 0);
viewer->removePointCloud("clicked_points");
viewer->addPointCloud(cloud_temp,red,"clicked_points");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");
ui.qvtkWidget->update();
//当前点三维坐标传给子窗口
pointselected->setLineEdit(current_point.x, current_point.y, current_point.z);
}
void QtApplication::SelectPoint()
{
//pointselected是子窗口对象,设为非模态,显示子窗口
pointselected->setModal(false);
pointselected->show();
cloud_mutex.lock();// 锁住,不允许此段时间内,点云数据被修改
viewer->addPointCloud(cloud);//cloud是当前加载的点云指针
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(SelectPoint_callback,(void*)&cb_args);
cloud_mutex.unlock();
}
运行结果如下:
错误信息
程序断点错误信息如下:
如上图所示,在回调函数处设置断点,data结构体无法读取内存,继续执行就会报错。
后记
目前问题定位在这里,本人卡在这里已经多时,毫无头绪,欢迎各位大神指点迷津,多谢多谢!
另外,在此感谢下列参考博客的各位博主!
参考博客
[1] : 基于PCL拾取屏幕上三维点坐标
[2] : 基于PCL的屏幕选点、框选点云、单点选取等c++实现
[3] : 基于PCL实现点云框选功能