Open3D ML の利用
【概要】
Open3D-ML は,3次元点群に対する機械学習のためのモデル,データセット,演算子(オペレータ)を提供する Open3D の拡張である。PyTorch 向けの演算子は open3d.ml.torch から利用する。
PyPI で配布される Open3D のホイールには,PyTorch 向け演算子が含まれない。open3d.ml.torch を使うには,BUILD_PYTORCH_OPS を有効にして Open3D をソースからビルドする。
【関連する外部ページ】
- GitHub の Open3D の Web ページ: https://github.com/isl-org/Open3D
- GitHub の Open3D-ML の Web ページ: https://github.com/isl-org/Open3D-ML
- Open3D の Web ページ: https://www.open3d.org/
- Open3D の公式ドキュメント: https://www.open3d.org/docs/release/
- Open3D のビルド手順: https://www.open3d.org/docs/latest/compilation.html
【サイト内の関連情報】
1. 前準備
ビルドには,次のソフトウェアが必要である。
- Build Tools for Visual Studio 2026(C++17 対応のコンパイラ)
- CMake 3.24 以上
- Git
- Python 3.12
- NVIDIA CUDA ツールキット(GPU を使う場合。使わない場合は不要)
これらのインストール手順は Open3D のインストール(Windows 上)のページで説明している。
2. Open3D のビルドスクリプト(コマンドプロンプト用)
管理者権限でコマンドプロンプトを起動する
(手順:Windowsキーまたはスタートメニュー → cmd と入力 → 右クリック → 「管理者として実行」)。
次のコマンドを実行する。nvcc が使える環境では CUDA 版,そうでない環境では CPU 版としてビルドされる。BUNDLE_OPEN3D_ML と OPEN3D_ML_ROOT の指定により,Open3D-ML のモデルとパイプラインが Python パッケージに同梱される。
nvcc --version && set BUILD_CUDA=ON || set BUILD_CUDA=OFF
set PT_URL=https://download.pytorch.org/whl/cu128
echo [1/5] PyTorch のインストール
python -m pip install -U --no-user torch torchvision torchaudio --index-url %PT_URL%
echo [2/5] ソースコードの取得
cd /d c:%HOMEPATH%
rmdir /s /q Open3D
git clone --recursive https://github.com/isl-org/Open3D
cd Open3D
git submodule update --init --recursive
echo [3/5] CMake による構成
mkdir build
cd build
cmake -G "Visual Studio 18 2026" -A x64 -T host=x64 ^
-DCMAKE_C_FLAGS="/W0 /utf-8" ^
-DCMAKE_CXX_FLAGS="/W0 /utf-8" ^
-DCMAKE_INSTALL_PREFIX="c:/open3d" ^
-DBUILD_PYTHON_MODULE=ON ^
-DBUILD_CUDA_MODULE=%BUILD_CUDA% ^
-DBUILD_GUI=ON ^
-DBUILD_ISPC_MODULE=ON ^
-DBUILD_PYTORCH_OPS=ON ^
-DBUNDLE_OPEN3D_ML=ON ^
-DOPEN3D_ML_ROOT=https://github.com/isl-org/Open3D-ML.git ..
echo [4/5] ビルドとインストール
cmake --build . --config Release --target ALL_BUILD -- /m
cmake --build . --config Release --target INSTALL -- /m
cmake --build . --config Release --target install-pip-package
echo [5/5] 動作確認
python -c "import open3d; import torch; import open3d.ml.torch as ml3d; print(open3d.__version__)"
主なビルドオプションの意味は次のとおりである。
- BUILD_PYTHON_MODULE:Python 用モジュールを作る。
- BUILD_CUDA_MODULE:CUDA による GPU 実行を有効にする。
- BUILD_GUI:3次元表示用のウィンドウ機能を作る。Open3D-ML の Visualizer はこの機能を使う。
- BUILD_PYTORCH_OPS:
open3d.ml.torch.opsの演算子を作る。 - BUNDLE_OPEN3D_ML,OPEN3D_ML_ROOT:Open3D-ML のモデルとパイプラインを同梱する。
3. 機能の検証コード
以下の7つのコードは,それぞれ単体で実行できる。テスト1からテスト5は Open3D の基本機能,テスト6とテスト7は Open3D-ML の機能を確認する。点群データには,Open3D に同梱のデータ取得機能(o3d.data)が返す Redwood リビングルームの点群(fragment.ply)を使う。データは初回実行時に自動でダウンロードされる。
テスト1: 色付き点群の表示
import open3d as o3d
pcd = o3d.io.read_point_cloud(o3d.data.PLYPointCloud().path)
# 結果確認: 読み込んだ点群の基本情報をコンソールに出力
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
pcd = o3d.io.read_point_cloud(o3d.data.PLYPointCloud().path)
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
pcd = o3d.io.read_point_cloud(o3d.data.PLYPointCloud().path)
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
pcd = o3d.io.read_point_cloud(o3d.data.PLYPointCloud().path)
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
source = o3d.io.read_point_cloud(o3d.data.PLYPointCloud().path).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】セマンティックラベルの視覚化
Open3D-ML の Visualizer は,点ごとのラベルを色分けして表示する。ラベル番号と色の対応は LabelLUT で指定し,set_lut で属性名 labels に結び付ける。ここでは,高さ(z 座標)の中央値を境にした2クラスのラベルを作り,表示する。
import open3d as o3d
import open3d.ml.torch as ml3d
import numpy as np
pcd = o3d.io.read_point_cloud(o3d.data.PLYPointCloud().path)
points = np.asarray(pcd.points, dtype=np.float32)
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,
"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.set_lut("labels", lut)
vis.visualize(data)
表示されたウィンドウの Properties で Data に labels,Shader に Label Colormap を選ぶと,指定した色で表示される。
テスト7: 【Open3D-ML】Voxel Pooling
voxel_pooling は,同じボクセルに入る点をまとめる演算子である。座標のまとめ方を position_fn,特徴量のまとめ方を feature_fn で指定する。この演算子は BUILD_PYTORCH_OPS=ON でビルドしたときに利用できる。
import open3d as o3d
import open3d.ml.torch as ml3d
import torch
import numpy as np
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
pcd = o3d.io.read_point_cloud(o3d.data.PLYPointCloud().path)
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,
voxel_size,
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}")