基于PCL实现拾取屏幕三维点坐标(暂未解决,待更新)

该功能暂未实现,诚邀大神指点,感激不尽!

目录:

问题介绍

本人基于PCL1.8.0+Qt5.7.0+VS2013开发三维点云数据处理软件,其中一项功能是拾取屏幕三维点坐标,并将其三维坐标显示在一个子窗口对话框中。

功能流程描述

  1. 主窗口菜单栏点击拾取三维点按钮,弹出显示结果的非模态子窗口对话框
  2. 根据PCL点云库定义,按住Shift+鼠标左键选取可视化窗口的数据点;
  3. 设置该点size为10并红色显示,加以区分;
  4. 子窗口对话框中lineEdit控件显示该点三维坐标;
  5. 如果选择其他点,则刷新屏幕渲染,并刷新子窗口坐标显示。

现在进展

  1. 在控制台应用程序下,可以顺利实现该功能;
  2. 将代码整合到自己的应用程序中,回调函数执行阶段异常。

代码

官方示例源码

(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实现点云框选功能

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 24
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值