open3d-octree

open3d提供了一个专门用于八叉树的数据结构 Octree

class Octree(Geometry3D):
    max_depth
    origin
    root_node
    size
    def convert_from_point_cloud(self, point_cloud, size_expand=0.01): 
    def create_from_voxel_grid(self):
    def insert_point(self, point, f_init, f_update, fi_init=None, fi_update=None):
    def is_point_in_bound(self, point, origin, size):
    # 当前节点的子节点
    def locate_leaf_node(self, point):
    def to_voxel_grid(self):
    def traverse(self, f, *args, **kwargs):
class OctreeInternalPointNode(OctreeInternalNode):
    children  # 子节点
    indices   # 下标
    def __init__(self, *args, **kwargs):
        """
        __init__(*args, **kwargs)
        Overloaded function.
        1. __init__(self)
            Default constructor
        2. __init__(self, arg0)
            Copy constructor
        Args:
            arg0 (open3d.geometry.OctreeInternalPointNode)
        """
    def get_init_function(self):
    def get_update_function(self, arg0):
    def __copy__(self):
    def __deepcopy__(self, arg0):
class OctreeNodeInfo(__pybind11_builtins.pybind11_object):
    child_index
    depth
    origin
    size
    def __init__(self, origin, size, depth, child_index):
        """
        __init__(self, origin, size, depth, child_index)

        Args:
            origin (numpy.ndarray[float64[3, 1]])
            size (float)
            depth (int)
            child_index (int)
        """
import open3d as o3d
import numpy as np
from open3d.web_visualizer import draw
from open3d.visualization import draw_geometries
pcd = o3d.io.read_point_cloud('datas/sphere.ply')
print(pcd)
-> PointCloud with 642 points.
draw(pcd)

1. 从点云构建八叉树

oct = o3d.geometry.Octree(max_depth=4)
oct.convert_from_point_cloud(pcd)
print(oct)
-> Octree with origin: [-1, -1, -1], size: 2.02, max_depth: 4
draw(oct)
print(oct.root_node)
-> OctreeInternalPointNode with 8 non-empty child nodes and 642 points
print(oct.root_node.children[0])
-> OctreeInternalPointNode with 7 non-empty child nodes and 93 points

2. 八叉树索引

# 取八叉树第一层的第四部分中的点云,涂成红色
oct_4 = pcd.select_by_index(oct.root_node.children[4].indices)
oct_4.paint_uniform_color([1,0,0])
oct_e = pcd.select_by_index(oct.root_node.children[4].indices, True)
oct_e.paint_uniform_color([0,0,0])
draw([oct_4, oct_e])
# 返回指定点在八叉树中的叶节点 以及该点所在的内部节点信息
leafnode, nodeinfo = oct.locate_leaf_node(pcd.points[0])
print(leafnode)
-> OctreePointColorLeafNode with color [0, 0, 0] containing 1 points.
print(nodeinfo) # 
-> OctreeNodeInfo with origin [0.38875, 0.89375, 0.01], size 0.12625, depth 4, child_index 3
print(pcd.points[0]) # 第一个点的坐标
-> [0.39960703 0.91298246 0.08232358]
print(oct.origin) # 八叉树坐标轴最小值
-> [-1. -1. -1.]
print(oct.size)  # 八叉树
-> 2.02

2. 八叉树回调

def callback(node, node_info):
    if isinstance(node, o3d.geometry.OctreeInternalNode): # 内部节点
        if isinstance(node, o3d.geometry.OctreeInternalPointNode):
            # for child in node.children:
            depth = node_info.depth
            child_num = len([child for child in node.children if child is not None])
            point_num = len(node.indices)
            print('{} depth: {} | index: {} | child num: {} | point num: {}'.format('- '*depth, depth, node_info.child_index, child_num, point_num))
    if isinstance(node, o3d.geometry.OctreeLeafNode): # 叶节点
        if isinstance(node, o3d.geometry.OctreePointColorLeafNode):
            pass
oct.traverse(callback)
 depth: 0 | index: 0 | child num: 8 | point num: 642
-  depth: 1 | index: 0 | child num: 7 | point num: 93
- -  depth: 2 | index: 0 | child num: 1 | point num: 3
- - -  depth: 3 | index: 7 | child num: 3 | point num: 3
- -  depth: 2 | index: 1 | child num: 6 | point num: 14
- - -  depth: 3 | index: 2 | child num: 1 | point num: 1
- - -  depth: 3 | index: 3 | child num: 2 | point num: 4
- - -  depth: 3 | index: 4 | child num: 1 | point num: 1
- - -  depth: 3 | index: 5 | child num: 2 | point num: 3
- - -  depth: 3 | index: 6 | child num: 3 | point num: 3
- - -  depth: 3 | index: 7 | child num: 2 | point num: 2
- -  depth: 2 | index: 2 | child num: 6 | point num: 14
......