Open3D 4データ構造KdtreeとOctreeに基づく点群処理

Kdtree

Kdtreeはk次元のデータ空間を分割したデータ構造で、本質的には二分木ですが、各ノードのデータはk次元であり、k=1の場合は通常の二分木となります。

Kdtree の確立は、実際には連続的な分割のプロセスであり、まず、最も疎な次元を選択し (通常、各次元のデータの分散を計算し、分散が最も大きいものを今回の分割次元として選択します)、次を求めます。この次元の垂直方向の中点。次元が初めて分割されます。このとき、k 次元の超平面を 2 つに分割し、その 2 つの部分平面で最も疎な次元を見つける、というように最後の点まで分割すると、連続的に二分化された木が形成されます。
2 次元 Kdtree の構築プロセスを次の図に示します. まず、データの x 方向と y 方向の分散をそれぞれ計算し、x 方向の分散が最も大きいことがわかっているため、分割ドメインの値をは最初に x 軸方向にあり、次に x 軸方向の値 2 に従って、5、9、4、8、7 がソートされて中央値 7 が選択されるため、Node-data = (7, 2) )。このように、このノードの分割超平面は、(7,2) を通り、split = 0 (x 軸) に垂直な直線 x = 7 になります。

KD ツリーを使用すると、K 最近傍検索や K 半径検索などのアルゴリズムを点群に実装できます。

テストケース: 背景の点群と比較して、移動ターゲットを見つけます

  • まず最大 d を決定します
  • 探索する点群を横断し、最も近い点を見つけます。
  • 最近傍点からの距離 d が dmax 未満の場合は同じ領域内の点とみなされその点は削除され、dmax より大きい場合は別の点とみなされ、ポイントは保持されます。
import open3d as o3d
import numpy as np
pc1 = o3d.io.read_point_cloud("./data/1.ply",remove_nan_points=True,remove_infinite_points=True)#原始点云
pc2 = o3d.io.read_point_cloud("./data/2.ply",remove_nan_points=True,remove_infinite_points=True)#求异点云
#建立原始数据点云的k-d树结构
k_dTree = o3d.geometry.KDTreeFlann(pc1)
#ptsIdx是指灵片点云中相同部分的索引
ptsIdx=[]
#k是指K-NN搜索的参数,也就是说搜索另外一片点云中距离它的最近点
k=1
#将距离阈值设置为0.1
dist_max=0.1
#得到点个数
points = np.array(pc2.points)
pointNum=points.shape[0]
#遍历点云
for i in range(0, pointNum):
    # k返回点个数
    # idx 返回点索引
    # dist 返回点距离
    [k, idx, dist] = k_dTree.search_knn_vector_3d(pc2.points[i],k)#通过k-d Tree进行搜索最近点
    if dist[0] < dist_max:#如果另外一片点云中能够找到距离小于给定距离阈值的点,则判定为点云中相同的部分
        ptsIdx.append(i)

#最后将点云中相同的部分和不同的部分分别取出来进行显示
same_part=pc2.select_by_index(ptsIdx)
diff_part=pc2.select_by_index(ptsIdx,invert=True)
same_part.paint_uniform_color([0,0,1])
diff_part.paint_uniform_color([1,0,0])
o3d.visualization.draw_geometries([same_part,diff_part])

ここに画像の説明を挿入

オクツリー

Octree は、3 次元空間を記述するために使用されるツリー状のデータ構造です。オクツリーの各ノードは立方体の体積要素を表し、各ノードには 8 つの子ノードがあり、8 つの子ノードで表される体積要素は親ノードの体積と等しくなるように加算されます。点群を適切に圧縮してストレージスペースを節約できます。3 次元空間の幾何学的エンティティをボクセルに分割することにより、各ボクセルは同じ時間および空間の複雑さを持ち、(2n*2n*2n) のサイズを持つ 3 次元空間の幾何学的オブジェクトは周期的な周期で分割されます。再帰的分割法により、ルート ノードを持つ方向グラフを形成します。オクツリー構造では、分割されたボクセルが同じ属性を持つ場合、そのボクセルはリーフ ノードを構成します。そうでない場合は、ボクセルを 8 つのサブキューブに分割し続け、それらを (2n∗2n∗2n ) サイズの空間オブジェクトに対して順次分割します。 、以下の図に示すように、最大​​ n 回まで細分化できます。
ここに画像の説明を挿入

オクツリーの作成:

  1. 再帰の最大深さを設定します。
  2. シーンの最大サイズを見つけて、このサイズで最初の立方体を構築します。
  3. ID 要素を、含めることができ、子を持たないキューブに連続してドロップします。
  4. 再帰の最大深さに達していない場合は、8 つの等しい部分に分割し、キューブに含まれるすべての単位要素を 8 つのサブキューブに共有します。
  5. サブ立方体に割り当てられた単位要素の数がゼロではなく、親立方体と同じであることが判明した場合、空間分割理論によれば、細分化された空間を割り当てる必要があるため、サブ立方体は細分化を停止します。 less, if 数値が同じ場合、どのようにカットしても数値は同じであり、無限カットが発生します。-
  6. 最大再帰深さに達するまで 3 を繰り返します。

オクツリー構造により、ブロック機能、近傍探索、小K近傍の取得などの機能が実現できます。

  • 備考: KD ツリーとオクツリーの違い
    1. オクツリーのノードは均等に分割されますが、kd ツリーのノードは毎回異なる次元で不均等に分割され、2 つの子ノードが形成されます; 2. kd ツリーは適用可能
    です異なる次元のデータに適していますが、オクツリーは 3 次元データにのみ適しています。

テストケース: ビジュアルオクツリー

import open3d as o3d

pcd = o3d.io.read_point_cloud("./data/people.ply")
# 设置颜色
pcd.paint_uniform_color([1.0, 0.0, 0.0])
# 建立八叉树
octree = o3d.geometry.Octree(max_depth=10)#设置最大深度
octree.convert_from_point_cloud(pcd, size_expand=0.1)#size_expand叶子节点大小
# 可视化
o3d.visualization.draw_geometries([octree], window_name="八叉树",
                                  width=800,
                                  height=600)

ここに画像の説明を挿入

Supongo que te gusta

Origin blog.csdn.net/zfjBIT/article/details/130913340
Recomendado
Clasificación