0


PCL交互选择ROI区域

PCL的配置和如何配准点云可见博主之前的博客

win10环境下PCL安装和配置回顾(一)_竹叶青lvye的博客-CSDN博客_pcl win10

win10环境下PCL安装和配置回顾(二)_竹叶青lvye的博客-CSDN博客_win10 安装pcl

PCL - 3D点云配准(registration)介绍_竹叶青lvye的博客-CSDN博客

其它的PCL方面常用的一些点云算法,可自己花时间去研读,这边想去简单实现下ROI区域交互式的选择,接下还是延续前面几篇博客所用的PCL的配置。

一. 生成测试点云

这边点云选择

mirrors / pointcloudlibrary / data · GitCode

里面的learn5.pcd点云

这里自定义了一个旋转平移矩阵(将点云通过这个变换为另外一个点云),详细见如下代码:

#include <pcl/memory.h>  // for pcl::make_shared
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/point_representation.h>
#include <pcl/io/pcd_io.h>

#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/filter.h>

#include <pcl/features/normal_3d.h>

#include <pcl/registration/icp.h>
#include <pcl/registration/icp_nl.h>
#include <pcl/registration/transforms.h>

#include <pcl/visualization/pcl_visualizer.h>

#include <boost/thread/thread.hpp>

using pcl::visualization::PointCloudColorHandlerGenericField;
using pcl::visualization::PointCloudColorHandlerCustom;

//convenient typedefs
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloud;
typedef pcl::PointNormal PointNormalT;
typedef pcl::PointCloud<PointNormalT> PointCloudWithNormals;

int main()
{
    PointCloud::Ptr cloud_src(new PointCloud);
    PointCloud::Ptr cloud_tgt(new PointCloud);

    pcl::io::loadPCDFile("D:\\PCL\\data-master\\segmentation\\mOSD\\learn\\learn5.pcd", *cloud_src);

    Eigen::Matrix4f transform_1 = Eigen::Matrix4f::Identity();//定义绕X轴的旋转矩阵,并初始化为单位阵

    float theta = M_PI / 4; // The angle of rotation in radians
    transform_1(0, 0) = std::cos(theta);
    transform_1(0, 1) = -sin(theta);
    transform_1(1, 0) = sin(theta);
    transform_1(1, 1) = std::cos(theta);

    transform_1(0, 3) = 0.7f;
    transform_1(1, 3) = 0.6f;
    transform_1(2, 3) = 1.2f;

    pcl::transformPointCloud(*cloud_src, *cloud_tgt, transform_1);

    std::cout << "cloud_src size: " << cloud_src->size() << std::endl;
    std::cout << "cloud_target size: " << cloud_tgt->size() << std::endl;

    pcl::visualization::PCLVisualizer* p;
    int vp_1, vp_2;

    p = new pcl::visualization::PCLVisualizer("view");

    PointCloudColorHandlerCustom<PointT> src_h(cloud_src, 255, 0, 0);
    PointCloudColorHandlerCustom<PointT> tgt_h(cloud_tgt, 0, 255, 0);

    p->addPointCloud(cloud_src, src_h, "vp1_src");
    p->addPointCloud(cloud_tgt, tgt_h, "vp1_target");

    p->spin();

    return (0);
}

运行结果如下:

二. 交互点选

接下来在变换前的点云数据上点选一个ROI区域,代码如下:

#include <pcl/memory.h>  // for pcl::make_shared
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/point_representation.h>
#include <pcl/io/pcd_io.h>

#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/filter.h>

#include <pcl/features/normal_3d.h>

#include <pcl/registration/icp.h>
#include <pcl/registration/icp_nl.h>
#include <pcl/registration/transforms.h>

#include <pcl/visualization/pcl_visualizer.h>

#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>

#include <boost/thread/thread.hpp>

using pcl::visualization::PointCloudColorHandlerGenericField;
using pcl::visualization::PointCloudColorHandlerCustom;

//convenient typedefs
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloud;
typedef pcl::PointNormal PointNormalT;
typedef pcl::PointCloud<PointNormalT> PointCloudWithNormals;

//Mutex 
boost::mutex cloud_mutex;

struct callback_args
{
    PointCloud::Ptr clicked_points_3d;
    pcl::visualization::PCLVisualizer::Ptr viewerPtr;
};

//点选函数
void pointPick_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);

    //显示当前点
    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");
    cout << current_point << endl;
}

int main()
{
    PointCloud::Ptr cloud_src(new PointCloud);
    PointCloud::Ptr cloud_tgt(new PointCloud);

    pcl::io::loadPCDFile("D:\\PCL\\data-master\\segmentation\\mOSD\\learn\\learn5.pcd", *cloud_src);

    Eigen::Matrix4f transform_1 = Eigen::Matrix4f::Identity();//定义绕X轴的旋转矩阵,并初始化为单位阵

    float theta = M_PI / 4; // The angle of rotation in radians
    transform_1(0, 0) = std::cos(theta);
    transform_1(0, 1) = -sin(theta);
    transform_1(1, 0) = sin(theta);
    transform_1(1, 1) = std::cos(theta);

    transform_1(0, 3) = 0.7f;
    transform_1(1, 3) = 0.6f;
    transform_1(2, 3) = 1.2f;

    pcl::transformPointCloud(*cloud_src, *cloud_tgt, transform_1);

    std::cout << "cloud_src size: " << cloud_src->size() << std::endl;
    std::cout << "cloud_target size: " << cloud_tgt->size() << std::endl;

    

    pcl::visualization::PCLVisualizer* p;

    p = new pcl::visualization::PCLVisualizer("view");

    cloud_mutex.lock();    // for not overwriting the point cloud

    PointCloudColorHandlerCustom<PointT> src_h(cloud_src, 0, 0, 255);
    PointCloudColorHandlerCustom<PointT> tgt_h(cloud_tgt, 0, 255, 0);

    p->setBackgroundColor(0.5, 0.5, 0.1, 0); // 设置背景为深灰

    p->addPointCloud(cloud_src, src_h, "vp1_src");
    p->addPointCloud(cloud_tgt, tgt_h, "vp1_target");

    struct callback_args cb_args;
    PointCloud::Ptr clicked_points_3d(new PointCloud);

    cb_args.clicked_points_3d = clicked_points_3d;
    cb_args.viewerPtr = pcl::visualization::PCLVisualizer::Ptr(p);
    p->registerPointPickingCallback(pointPick_callback, (void*)&cb_args);

    cout << "->Shift + 鼠标左键选点,按 ‘Q’结束选点" << endl;

    p->spin();

    cout << "->选点结束" << endl;

    Eigen::Affine3f affine(transform_1);

    PointT conver_point = pcl::transformPoint(cb_args.clicked_points_3d->points[0], affine);
    std::cout << "use the affine to covert the point: " << std::endl;
    std::cout << conver_point << std::endl;

    cloud_mutex.unlock();

    while (!p->wasStopped())
    {
        p->spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }

    return (0);
}

运行程序,可看到如下先点选了蓝色点云上的一个角点,又鼠标点选了绿色点云上对应位置处的一角点。这个两个点云的点同时也在点云上show出来了。

按了Q退出点选模式后,程序会将点云的绿色处的点去由变换矩阵变化下,算出来的值,可看到和上面鼠标点选的绿色点云的角点坐标是近似的。

三. 将点云上的ROI区域跟随目标的变换而变化,并在其变换后的点云数据上画出立体框

代码如下,在第一个点云上可以通过鼠标点选ROI区域,完毕后会在第二个点云上会产生一个ROI区域,可看到是跟随目标变化的。

#include <pcl/memory.h>  // for pcl::make_shared
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/point_representation.h>
#include <pcl/io/pcd_io.h>

#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/filter.h>

#include <pcl/features/normal_3d.h>

#include <pcl/registration/icp.h>
#include <pcl/registration/icp_nl.h>
#include <pcl/registration/transforms.h>

#include <pcl/visualization/pcl_visualizer.h>

#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>

#include <pcl/features/moment_of_inertia_estimation.h>

#include <boost/thread/thread.hpp>

using pcl::visualization::PointCloudColorHandlerGenericField;
using pcl::visualization::PointCloudColorHandlerCustom;

//convenient typedefs
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloud;
typedef pcl::PointNormal PointNormalT;
typedef pcl::PointCloud<PointNormalT> PointCloudWithNormals;

pcl::PointCloud<PointT>::Ptr points;

//Mutex 
boost::mutex cloud_mutex;
int count = 0;

struct callback_args
{
    PointCloud::Ptr clicked_points_3d;
    PointCloud::Ptr clicked_points_3d_convert;
    pcl::visualization::PCLVisualizer::Ptr viewerPtr;
    Eigen::Affine3f affine;
};

//点选函数
void pointPick_callback(const pcl::visualization::PointPickingEvent& event, void* args)
{
    count++;

    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);

    //显示当前点
    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");

    //添加点索引号
    PointT position(current_point.x, current_point.y + 0.01, current_point.z);
    data->viewerPtr->addText3D(std::to_string(count), position, 0.1, 1,0,0);

    data->viewerPtr->resetCameraViewpoint();

    
    cout << current_point << endl;
    PointT convert_point = pcl::transformPoint(current_point, data->affine);
    data->clicked_points_3d_convert->points.push_back(convert_point);

    if (count == 6)
    {
        //方向包围盒OBB
        pcl::MomentOfInertiaEstimation <pcl::PointXYZ> feature_extractor;
        feature_extractor.setInputCloud(data->clicked_points_3d);
        feature_extractor.compute();

        pcl::PointXYZ min_point_OBB;
        pcl::PointXYZ max_point_OBB;
        pcl::PointXYZ position_OBB;
        Eigen::Matrix3f rotational_matrix_OBB;
        feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);

        Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z);
        Eigen::Quaternionf quat(rotational_matrix_OBB);
        data->viewerPtr->addCube(position, quat, max_point_OBB.x - min_point_OBB.x, max_point_OBB.y - min_point_OBB.y, max_point_OBB.z - min_point_OBB.z, "OBB");
        data->viewerPtr->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBB");

        
        feature_extractor.setInputCloud(data->clicked_points_3d_convert);
        feature_extractor.compute();

        feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);

        Eigen::Vector3f positionConvert(position_OBB.x, position_OBB.y, position_OBB.z);
        Eigen::Quaternionf quatConvert(rotational_matrix_OBB);

        data->viewerPtr->addCube(positionConvert, quatConvert, max_point_OBB.x - min_point_OBB.x, max_point_OBB.y - min_point_OBB.y, max_point_OBB.z - min_point_OBB.z, "OBBConvert");
        data->viewerPtr->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBBConvert");
    }
}

int main()
{
    PointCloud::Ptr cloud_src(new PointCloud);
    PointCloud::Ptr cloud_tgt(new PointCloud);

    pcl::io::loadPCDFile("D:\\PCL\\data-master\\segmentation\\mOSD\\learn\\learn5.pcd", *cloud_src);

    Eigen::Matrix4f transform_1 = Eigen::Matrix4f::Identity();//定义绕X轴的旋转矩阵,并初始化为单位阵

    float theta = M_PI / 4; // The angle of rotation in radians
    transform_1(0, 0) = std::cos(theta);
    transform_1(0, 1) = -sin(theta);
    transform_1(1, 0) = sin(theta);
    transform_1(1, 1) = std::cos(theta);

    transform_1(0, 3) = 0.7f;
    transform_1(1, 3) = 0.6f;
    transform_1(2, 3) = 1.2f;

    pcl::transformPointCloud(*cloud_src, *cloud_tgt, transform_1);

    std::cout << "cloud_src size: " << cloud_src->size() << std::endl;
    std::cout << "cloud_target size: " << cloud_tgt->size() << std::endl;

    

    pcl::visualization::PCLVisualizer* p;

    p = new pcl::visualization::PCLVisualizer("view");

    cloud_mutex.lock();    // for not overwriting the point cloud

    PointCloudColorHandlerCustom<PointT> src_h(cloud_src, 0, 0, 255);
    PointCloudColorHandlerCustom<PointT> tgt_h(cloud_tgt, 0, 255, 0);

    p->setBackgroundColor(0.5, 0.5, 0.1, 0); // 设置背景为深灰

    p->addPointCloud(cloud_src, src_h, "vp1_src");
    p->addPointCloud(cloud_tgt, tgt_h, "vp1_target");

    struct callback_args cb_args;
    PointCloud::Ptr clicked_points_3d(new PointCloud);
    PointCloud::Ptr clicked_points_3d_convert(new PointCloud);

    cb_args.clicked_points_3d = clicked_points_3d;
    cb_args.clicked_points_3d_convert = clicked_points_3d_convert;

    cb_args.viewerPtr = pcl::visualization::PCLVisualizer::Ptr(p);
    //cb_args.viewerPtr->addCoordinateSystem(0.5);
    PointT position(0, 0, 0);
    PointT positionx(1, 0, 0);
    PointT positiony(0, 1, 0);
    PointT positionz(0, 0, 1);
    cb_args.viewerPtr->addArrow<PointT,PointT>(positionx, position,0,0,1,false, "x");
    cb_args.viewerPtr->addArrow<PointT, PointT>(positiony, position, 0,1, 0,false, "y");
    cb_args.viewerPtr->addArrow<PointT, PointT>(positionz, position, 1, 0, 0,false, "z");

    cb_args.viewerPtr->addText3D("x", positionx, 0.2, 0, 0, 1,"x1");
    cb_args.viewerPtr->addText3D("y", positiony, 0.2, 0, 1, 0,"y1");
    

    Eigen::Affine3f affine(transform_1);
    cb_args.affine = affine;

    p->registerPointPickingCallback(pointPick_callback, (void*)&cb_args);

    cout << "->Shift + 鼠标左键选点,按 ‘Q’结束选点" << endl;

    p->spin();

    cout << "->选点结束" << endl;

    

    PointT conver_point = pcl::transformPoint(cb_args.clicked_points_3d->points[0], affine);
    std::cout << "use the affine to covert the point: " << std::endl;
    std::cout << conver_point << std::endl;

    cloud_mutex.unlock();

    while (!p->wasStopped())
    {
        p->spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(100000));
    }

    return (0);
}

执行效果如下:

可看到,此段代码实现了ROI区域跟随点云变化的功能。

标签: c++ 开发语言

本文转载自: https://blog.csdn.net/jiugeshao/article/details/127835172
版权归原作者 竹叶青lvye 所有, 如有侵权,请联系我们删除。

“PCL交互选择ROI区域”的评论:

还没有评论