Open3D ML の利用
【関連する外部ページ】
- GitHub の Open3D の Web ページ: https://github.com/isl-org/Open3D
- Open3D の Web ページ: https://www.open3d.org/
- Open3D の公式ドキュメント: https://www.open3d.org/docs/release/
【サイト内の関連情報】
1. Open3D フルビルドスクリプト (コマンドプロンプト用)
nvcc --version && set BUILD_CUDA=ON || set BUILD_CUDA=OFF
set PT_URL=https://download.pytorch.org/whl/cu118
echo [1/5] Installing PyTorch...
pip install torch torchvision torchaudio --index-url %PT_URL%
echo [2/5] Cloning Open3D repository...
rmdir /s /q Open3D
git clone --recursive https://github.com/isl-org/Open3D
cd Open3D
git submodule update --init --recursive
echo [3/5] Configuring CMake...
mkdir build
cd build
cmake -G "Visual Studio 16 2019" -A x64 -T host=x64 -DCMAKE_C_FLAGS="/W0" -DCMAKE_CXX_FLAGS="/W0" -DCMAKE_INSTALL_PREFIX="c:/open3d" -DUSE_SYSTEM_EIGEN3=TRUE -DEigen3_DIR="c:/eigen" -DBUILD_PYTHON_MODULE=ON -DBUILD_CUDA_MODULE=%BUILD_CUDA% -DBUILD_GUI=ON -DBUILD_WEBRTC=ON -DBUILD_ISPC_MODULE=ON -DBUILD_PYTORCH_OPS=ON -DBUNDLE_OPEN3D_ML=ON ..
echo [4/5] Building and Installing...
cmake --build . --config Release --target ALL_BUILD
cmake --build . --config Release --target INSTALL
cmake --build . --config Release --target install-pip-package
echo [5/5] Verifying Installation...
python -c "import open3d; import torch; import open3d.ml.torch as ml3d; print('Open3D & Open3D-ML Ready!')"
2. 必須機能 7つの検証コード
テスト1: 色付き点群の表示
import open3d as o3d
import urllib.request
import os
if not os.path.exists("fragment.ply"):
urllib.request.urlretrieve("https://raw.githubusercontent.com/isl-org/Open3D/master/examples/test_data/fragment.ply", "fragment.ply")
pcd = o3d.io.read_point_cloud("fragment.ply")
# 結果確認: 読み込んだ点群の基本情報をコンソールに出力
print(f"Loaded Point Cloud: {pcd}")
axes = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5)
o3d.visualization.draw_geometries([pcd, axes], window_name="1: Original Colored Point Cloud")
テスト2: ボクセルダウンサンプリング
import open3d as o3d
import urllib.request
import os
if not os.path.exists("fragment.ply"):
urllib.request.urlretrieve("https://raw.githubusercontent.com/isl-org/Open3D/master/examples/test_data/fragment.ply", "fragment.ply")
pcd = o3d.io.read_point_cloud("fragment.ply")
downpcd = pcd.voxel_down_sample(voxel_size=0.05)
# 結果確認: データ軽量化の効果を数値で出力
print(f"Original points : {len(pcd.points)}")
print(f"Downsampled points : {len(downpcd.points)}")
# 結果確認: 視覚的な比較のため、元の点群を右にずらして両方表示
pcd.translate([3, 0, 0])
axes = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5)
o3d.visualization.draw_geometries([downpcd, pcd, axes], window_name="2: Downsampled (Left) vs Original (Right)")
テスト3: 法線計算
import open3d as o3d
import numpy as np
import urllib.request
import os
if not os.path.exists("fragment.ply"):
urllib.request.urlretrieve("https://raw.githubusercontent.com/isl-org/Open3D/master/examples/test_data/fragment.ply", "fragment.ply")
pcd = o3d.io.read_point_cloud("fragment.ply")
downpcd = pcd.voxel_down_sample(voxel_size=0.05)
downpcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
downpcd.orient_normals_towards_camera_location(camera_location=[0, 0, 0])
# 結果確認: 法線が実際に計算・付与されたか検証して出力
print(f"Has Normals: {downpcd.has_normals()}")
print(f"Sample Normal Vector [0]: {np.asarray(downpcd.normals)[0]}")
axes = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5)
o3d.visualization.draw_geometries([downpcd, axes], window_name="3: Normal Estimation", point_show_normal=True)
テスト4: メッシュ化
import open3d as o3d
import urllib.request
import os
if not os.path.exists("fragment.ply"):
urllib.request.urlretrieve("https://raw.githubusercontent.com/isl-org/Open3D/master/examples/test_data/fragment.ply", "fragment.ply")
pcd = o3d.io.read_point_cloud("fragment.ply")
downpcd = pcd.voxel_down_sample(voxel_size=0.02)
downpcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
downpcd.orient_normals_towards_camera_location(camera_location=[0, 0, 0])
mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(downpcd, depth=9)
mesh.compute_vertex_normals()
mesh.paint_uniform_color([0.7, 0.7, 0.7])
# 結果確認: 生成されたポリゴン(頂点と三角形)の数を出力
print(f"Generated Mesh: {len(mesh.vertices)} vertices, {len(mesh.triangles)} triangles")
axes = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5)
o3d.visualization.draw_geometries([mesh, axes], window_name="4: Meshing (Poisson)")
テスト5: ICPレジストレーション
import open3d as o3d
import copy
import numpy as np
import urllib.request
import os
if not os.path.exists("fragment.ply"):
urllib.request.urlretrieve("https://raw.githubusercontent.com/isl-org/Open3D/master/examples/test_data/fragment.ply", "fragment.ply")
source = o3d.io.read_point_cloud("fragment.ply").voxel_down_sample(voxel_size=0.05)
source.paint_uniform_color([1, 0, 0])
target = copy.deepcopy(source)
target.translate([0.5, 0.5, 0.5])
target.paint_uniform_color([0, 0, 1])
trans_init = np.identity(4)
reg_p2p = o3d.pipelines.registration.registration_icp(
source, target, 1.0, trans_init,
o3d.pipelines.registration.TransformationEstimationPointToPoint()
)
source.transform(reg_p2p.transformation)
# 結果確認: 位置合わせの精度スコアと、最終的に適用された変換行列を出力
print("--- ICP Registration Results ---")
print(f"Fitness (Overlap ratio) : {reg_p2p.fitness:.4f}")
print(f"Inlier RMSE : {reg_p2p.inlier_rmse:.4f}")
print("Transformation Matrix:")
print(reg_p2p.transformation)
axes = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5)
o3d.visualization.draw_geometries([source, target, axes], window_name="5: ICP Registration (Merged Data)")
テスト6: 【Open3D-ML】セマンティックラベルの視覚化
import open3d as o3d
import open3d.ml.torch as ml3d
import numpy as np
import urllib.request
import os
if not os.path.exists("fragment.ply"):
urllib.request.urlretrieve("https://raw.githubusercontent.com/isl-org/Open3D/master/examples/test_data/fragment.ply", "fragment.ply")
pcd = o3d.io.read_point_cloud("fragment.ply")
points = np.asarray(pcd.points)
median_z = np.median(points[:, 2])
labels = (points[:, 2] > median_z).astype(np.int32)
# 結果確認: 生成されたセマンティックラベルの分布比率を出力
print(f"Total Points : {len(points)}")
print(f"Floor Points : {np.sum(labels == 0)}")
print(f"Obstacle Points : {np.sum(labels == 1)}")
data = [{
"name": "ML_Segmented_Data",
"points": points,
"point_labels": labels,
}]
lut = ml3d.vis.LabelLUT()
lut.add_label("Floor", 0, [0.5, 0.5, 0.5])
lut.add_label("Obstacle", 1, [0.8, 0.2, 0.2])
vis = ml3d.vis.Visualizer()
vis.visualize(data, lut=lut)
テスト7: 【Open3D-ML】Voxel Pooling
import open3d as o3d
import open3d.ml.torch as ml3d
import torch
import numpy as np
import urllib.request
import os
if not os.path.exists("fragment.ply"):
urllib.request.urlretrieve("https://raw.githubusercontent.com/isl-org/Open3D/master/examples/test_data/fragment.ply", "fragment.ply")
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
pcd = o3d.io.read_point_cloud("fragment.ply")
positions = torch.tensor(np.asarray(pcd.points), dtype=torch.float32, device=device)
features = positions[:, 2:3]
voxel_size = 0.1
pooled_positions, pooled_features = ml3d.ops.voxel_pooling(
positions,
features,
torch.tensor([voxel_size, voxel_size, voxel_size], dtype=torch.float32, device=device),
position_fn="average",
feature_fn="max"
)
# 結果確認: 座標と特徴量それぞれのテンソル形状の変換を出力
print(f"[{device}] Open3D-ML Tensor Operations Completed.")
print(f"Original Points : {positions.shape[0]}, Features Shape: {features.shape}")
print(f"Pooled Voxels : {pooled_positions.shape[0]}, Features Shape: {pooled_features.shape}")