18 基于欧式聚类的扫描点云前景-背景分离方法

0 引言

问题背景:项目涉及手持式激光扫描点云的前景与背景分离问题,手持扫描仪通过环形标志点以及人工交互实现精确配准,得到包含前景和背景的扫描点云数据。
我们的任务是将点云前景(foregroud)与背景(background)数据分离开来。手持式扫描点云的操作过程如图所示。
输入:带噪声的点云数据,CAD数模,扫描分辨率范围等参数
输出:去噪的前景数据

1 点云数据分析

 输入的点云以及CAD数模文件如图所示。

如图所示,图中有三组点云数据,扫描件的尺寸从50mm立方到200mm立方不等,扫描分辨率从0.6~0.8mm,前景与背景之间有放置物体.

2 基于欧式聚类的前景与背景分离算法

(1)点云下采样

目的是将不同扫描分辨率的点云做归一化处理,使得后续处理算法相关参数具备一定通用性。

pcl::VoxelGrid<pcl::PointXYZ> vg;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
vg.setInputCloud(cloud);
vg.setLeafSize(0.6f, 0.6f, 0.6f);
vg.filter(*cloud_filtered);

(2)欧式聚类分割

pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
tree->setInputCloud(cloud_filtered);
std::vector<pcl::PointIndices> cluster_indices;
pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;
ec.setClusterTolerance(3); //   聚类搜索半径 
ec.setMinClusterSize(10000);    
ec.setMaxClusterSize(1000000);
ec.setSearchMethod(tree);
ec.setInputCloud(cloud_filtered);
ec.extract(cluster_indices);

(3)识别前景点云

采用的方法是CAD数模外接矩形与点云外接矩形相似性度量方法。基本思路如下。

  1. 计算CAD模型的外轮廓尺寸,采用的是proe二次开发技术

// 获取零件的外包络长方体
void getOutLineOfSolid() {
    ProError status;
    //ProMdldata mdldata;
    ProMdl pSldMdl;
    status = ProMdlCurrentGet(&pSldMdl);
    if (status != PRO_TK_NO_ERROR)
    {
        AfxMessageBox(_T("打开模型失败!"));
        return;
    }
    Pro3dPnt r_outline_points[2];
    ProSolidOutlineGet((ProSolid)pSldMdl, r_outline_points);     // 求解基坐标方向的外形轮廓
    CStringW cstrOutLinePoints = L"外包络长方体的长宽高为: ";
    // 求边长并排序
    float edges[3];
    for (int i = 0; i < 3; i++) {
        edges[i] = r_outline_points[1][i] - r_outline_points[0][i];
    }
    // 插入排个序,从大到小
    for (int i = 1; i < 3;i++) {
        for (int j = i; j > 0; j--) {
            if (edges[j] > edges[j - 1]) {
                float temp = edges[j];
                edges[j] = edges[j - 1];
                edges[j - 1] = temp;
            }
        }
    }
    CStringW cstrEdgess;
    cstrEdgess.Format(L"长宽高1:(%.3f,%.3f,%.3f)"
        , edges[0], edges[1], edges[2]);
    cstrOutLinePoints += cstrEdgess;
    MessageBoxW(NULL, cstrOutLinePoints, L"手选曲面信息显示", MB_OK);
}

输出结果是一个三维向量,CAD_edges[3],从大到小排列.

  2. 计算点云的外轮廓尺寸,采用的是PCL中的技术

void minBox()
{
   // 确认点云已经读入
if (!MycloudFlag) { AfxMessageBox(_T("请先读入点云! ")); return; }
   // pcl中的惯性矩拟合方法 pcl::MomentOfInertiaEstimation
<pcl::PointXYZ> feature_extractor; feature_extractor.setInputCloud(mycloud); feature_extractor.compute(); std::vector <float> moment_of_inertia; std::vector <float> eccentricity; pcl::PointXYZ min_point_AABB; pcl::PointXYZ max_point_AABB; pcl::PointXYZ min_point_OBB; pcl::PointXYZ max_point_OBB; pcl::PointXYZ position_OBB; Eigen::Matrix3f rotational_matrix_OBB; float major_value, middle_value, minor_value; Eigen::Vector3f major_vector, middle_vector, minor_vector; Eigen::Vector3f mass_center; feature_extractor.getMomentOfInertia(moment_of_inertia); feature_extractor.getEccentricity(eccentricity); feature_extractor.getAABB(min_point_AABB, max_point_AABB); feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB); feature_extractor.getEigenValues(major_value, middle_value, minor_value); feature_extractor.getEigenVectors(major_vector, middle_vector, minor_vector); feature_extractor.getMassCenter(mass_center); boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer")); viewer->setBackgroundColor(0, 0, 0); viewer->addCoordinateSystem(1.0); viewer->initCameraParameters(); viewer->addPointCloud<pcl::PointXYZ>(mycloud); Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z); Eigen::Quaternionf quat(rotational_matrix_OBB); Eigen::Vector3f p1(min_point_OBB.x, min_point_OBB.y, min_point_OBB.z); Eigen::Vector3f p2(min_point_OBB.x, min_point_OBB.y, max_point_OBB.z); Eigen::Vector3f p3(max_point_OBB.x, min_point_OBB.y, max_point_OBB.z); Eigen::Vector3f p4(max_point_OBB.x, min_point_OBB.y, min_point_OBB.z); Eigen::Vector3f p5(min_point_OBB.x, max_point_OBB.y, min_point_OBB.z); Eigen::Vector3f p6(min_point_OBB.x, max_point_OBB.y, max_point_OBB.z); Eigen::Vector3f p7(max_point_OBB.x, max_point_OBB.y, max_point_OBB.z); Eigen::Vector3f p8(max_point_OBB.x, max_point_OBB.y, min_point_OBB.z); p1 = rotational_matrix_OBB * p1 + position; p2 = rotational_matrix_OBB * p2 + position; p3 = rotational_matrix_OBB * p3 + position; p4 = rotational_matrix_OBB * p4 + position; p5 = rotational_matrix_OBB * p5 + position; p6 = rotational_matrix_OBB * p6 + position; p7 = rotational_matrix_OBB * p7 + position; p8 = rotational_matrix_OBB * p8 + position; // 求解包络立方体边长 float edges[3]; edges[0] = pow(pow(pt1.x - pt2.x, 2.0) + pow(pt1.y - pt2.y, 2.0) + pow(pt1.z - pt2.z, 2.0), 0.5); edges[1] = pow(pow(pt2.x - pt3.x, 2.0) + pow(pt2.y - pt3.y, 2.0) + pow(pt2.z - pt3.z, 2.0), 0.5); edges[2] = pow(pow(pt2.x - pt6.x, 2.0) + pow(pt2.y - pt6.y, 2.0) + pow(pt2.z - pt6.z, 2.0), 0.5); for (size_t i = 1; i < 3; i++) { for (size_t j = i; j >= 1; j--) { if (edges[j]>edges[j - 1]) { float temp = edges[j]; edges[j] = edges[j - 1]; edges[j - 1] = temp; } } } char mybox[200]; *mybox = ''; sprintf(mybox, "(%.2f, %.2f, %.2f)", edges[0], edges[1], edges[2]); AfxMessageBox(_T("长宽高分别为: ") + (CString)CA2T(mybox)); }

输出结果也是一个三维向量,pts_edges[3],从小到大排列.

  3. 相似性度量

采用的公式是欧式相对距离法,公式如下。

利用该公式寻找相似度最高的点云,将点云文件存储到对应目录下,完成前景分割工作。

3 效果展示

分割效果如下图所示。

原文地址:https://www.cnblogs.com/ghjnwk/p/10100588.html