open3d PlanarPatchDetection

PointCloud::DetectPlanarPatches(
        double normal_similarity_deg,
        double coplanarity_deg,
        double outlier_ratio,
        double min_plane_edge_length,
        size_t min_num_points,
        const geometry::KDTreeSearchParam& search_param) const {
    if (!HasNormals()) {
        utility::LogError(
                "DetectPlanarPatches requires pre-computed normal vectors.");
        return {};
    }

    const Eigen::Vector3d min_bound = GetMinBound();
    const Eigen::Vector3d max_bound = GetMaxBound();
    if (min_plane_edge_length <= 0) {
        min_plane_edge_length = 0.01 * (max_bound - min_bound).maxCoeff();
    }

    if (min_num_points == 0) {
        min_num_points = std::max(static_cast<size_t>(10),
                                  static_cast<size_t>(points_.size() * 0.001));
    }

    // identify the neighbors of each point in point cloud
    geometry::KDTreeFlann kdtree;
    kdtree.SetGeometry(*this);
    std::vector<std::vector<int>> neighbors;
    neighbors.resize(points_.size());
#pragma omp parallel for schedule(static)
    for (int i = 0; i < static_cast<int>(points_.size()); i++) {
        std::vector<int> indices;
        std::vector<double> distance2;
        kdtree.Search(points_[i], search_param, neighbors[i], distance2);
    }

    const double normal_similarity_rad = normal_similarity_deg * M_PI / 180.0;
    const double coplanarity_rad = coplanarity_deg * M_PI / 180.0;

    // partition the point cloud and search for planar regions
    BoundaryVolumeHierarchyPtr root = std::make_shared<BoundaryVolumeHierarchy>(
            this, min_bound, max_bound);
    std::vector<PlaneDetectorPtr> planes;
    std::vector<PlaneDetectorPtr> plane_points(points_.size(), nullptr);
    SplitAndDetectPlanesRecursive(root, min_num_points,
                                  std::cos(normal_similarity_rad),
                                  std::cos(coplanarity_rad), outlier_ratio,
                                  min_plane_edge_length, planes, plane_points);

    // iteratively grow and merge planes until each is stable
    bool changed;
    do {
        Grow(planes, plane_points, neighbors);

        Merge(planes, plane_points, neighbors, *this);

        changed = Update(planes);

    } while (changed);

    // extract planar patches by calculating the bounds of each detected plane
    std::vector<std::shared_ptr<OrientedBoundingBox>> patches;
    ExtractPatchesFromPlanes(planes, patches);

    return patches;
}

min_plane_edge_length ,最小平面的长度
min_num_points ,最小平面的点数

通过kdtree 查找每个点云的邻居点 参数是通过设置,半径和最大数

    static constexpr double radius = 1;
    static constexpr int max_nn = 100;
    const geometry::KDTreeSearchParam &search_param =
            geometry::KDTreeSearchParamHybrid(radius, max_nn);

const double normal_similarity_rad = normal_similarity_deg * M_PI / 180.0;
const double coplanarity_rad = coplanarity_deg * M_PI / 180.0;

把输入的角度转为弧度
normal_similarity_deg 是以度表示的法线相似性阈值的角度。
normal_similarity_rad 存储了相同角度的弧度表示。
coplanarity_deg 是以度表示的共面性阈值的角度。
coplanarity_rad 存储了相同角度的弧度表示。

```cpp
    SplitAndDetectPlanesRecursive(root, min_num_points,
                                  std::cos(normal_similarity_rad),
                                  std::cos(coplanarity_rad), outlier_ratio,
                                  min_plane_edge_length, planes, plane_points);

这是关键,通过partition把点云数据分成8分,然后迭代在分,检测点云

bool SplitAndDetectPlanesRecursive(
        const BoundaryVolumeHierarchyPtr& node,
        size_t min_num_points,
        double normal_similarity,
        double coplanarity,
        double outlier_ratio,
        double plane_edge_length,
        std::vector<PlaneDetectorPtr>& planes,
        std::vector<PlaneDetectorPtr>& plane_points) {
    // if there aren't enough points to find a good plane, don't even try
    if (node->indices_.size() < min_num_points) return false;

    bool node_has_plane = false;
    bool child_has_plane = false;

    // partition into eight children and check each recursively for a plane
    node->Partition();

    for (const auto& child : node->children_) {
        if (child != nullptr &&
            SplitAndDetectPlanesRecursive(
                    child, min_num_points, normal_similarity, coplanarity,
                    outlier_ratio, plane_edge_length, planes, plane_points)) {
            child_has_plane = true;
        }
    }

    if (!child_has_plane && node->level_ > 2) {
        auto plane = std::make_shared<PlaneDetector>(normal_similarity,
                                                     coplanarity, outlier_ratio,
                                                     plane_edge_length);
        if (plane->DetectFromPointCloud(node->point_cloud_, node->indices_)) {
            node_has_plane = true;
            planes.push_back(plane);

            // assume ownership of these indices
            for (const size_t& idx : plane->indices_) {
                plane_points[idx] = plane;
            }
        }
    }

    return node_has_plane || child_has_plane;
}

通过partition把点云数据分成8分

    void Partition() {
        // Nothing to do if already partitioned
        if (!leaf_) return;

        // size of each child
        const double child_size = size_ / 2.;

        // Does this node have enough data to be able to partition further
        if (indices_.size() <= min_points_ || child_size < min_size_ ||
            indices_.size() < 2)
            return;

        // split points and create children
        for (const size_t& pidx : indices_) {
            // calculate child index comparing position to child center
            const size_t cidx =
                    CalculateChildIndex(point_cloud_->points_[pidx]);
            // if child does not yet exist, create and initialize
            if (children_[cidx] == nullptr) {
                const Eigen::Vector3d child_center =
                        CalculateChildCenter(cidx, child_size);
                children_[cidx].reset(new BoundaryVolumeHierarchy(
                        point_cloud_, level_ + 1, child_center, min_points_,
                        min_size_, child_size, cidx));
                children_[cidx]->indices_.reserve(indices_.size());
            }
            children_[cidx]->indices_.push_back(pidx);
        }

        // now that I have children, I am no longer a leaf node
        leaf_ = false;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值