3次元点群データの表示、ダウンサンプリング、外れ値の除去、法線の推定、メッシュ化(Python と Open3D を使用)

概要

3次元の点が多数集まったデータです。Python と open3d を使い、色付き点群の表示、間引きと外れ値除去、法線の推定、メッシュ化を行います。

資料 [PDF], [ワードファイル]

目次

関連する外部ページ

サイト内の関連情報

3次元の点が多数記述されたデータのことです。1つ1つの点が空間中の位置を表し、それらが集まって物体の形や空間の様子を表現します。

それぞれの点は、次のような属性を持ちえます。

要点:1つのオブジェクトの表面を、多数の点の集まり(3次元点群データ)として扱います。

第1章 3次元点群データのファイル形式の例

代表的なファイル形式

3次元点群データには、用途に応じて複数の標準フォーマットが使われています。代表的なものは次のとおりです。

アスキー形式(XYZ / ASC)

1行で1つの点を表します。データは半角の空白文字で区切られています。行の中には x, y, z の値が並び、あわせて付加情報が付くことが多いです。前にも使ったファイル cloud_0.asc では、ラベル番号(「2」などの数値)が付いています。

第2章 インターネットで公開されている RGB-D データセットの例

このあとの実習では、次に紹介する Redwood データセットの点群を使います。

ワシントン大学の RGB-D データセット

https://rgbd-dataset.cs.washington.edu/

Redwood の 3D スキャンデータセット

http://redwood-data.org/3dscan/dataset.html

第3章 3次元点群データを Python で表示する

ここまでは cloud_0.asc(ラベル番号付きの ASC 形式)を例にファイル形式を見てきました。ここからは、色情報(RGB)を持つ点群を題材に、Python での可視化と基本的な処理を行います。使用するのは、先に紹介した Redwood データセットのリビングルームを撮影した、色付きの PLY 形式の点群データです。

このあとの演習のコードは、いずれも同じ点群データを、プログラム(スクリプト)自身が置かれているディレクトリにダウンロードして利用します。各コードは前のコードに依存せず、それぞれ単体で実行できます。

準備:必要なライブラリ

点群ファイルの読み込みと可視化には open3d を、数値計算には numpy を使います。あらかじめ次のコマンドでインストールしてください(Python 3.12 環境が対象です)。

pip install -U --no-user numpy open3d

第4章 演習1:色付き点群のダウンロードとインタラクティブ表示

テーマ名:色付き点群をダウンロードして、open3d のビューアで表示する。

手順:

ヒント:

考察ポイント:

import os
import urllib.request
import open3d as o3d

# このスクリプトが存在するディレクトリを取得(カレントディレクトリではない)
script_dir = os.path.dirname(os.path.abspath(__file__))

# 色情報(RGB)付きの PLY 形式の点群データ(Redwood リビングルーム)
url = "https://github.com/isl-org/open3d_downloads/releases/download/20220201-data/fragment.ply"

# ダウンロード先のフルパス(スクリプトと同じディレクトリ)
ply_path = os.path.join(script_dir, "fragment.ply")

# まだダウンロードされていなければ取得する
if not os.path.exists(ply_path):
    print("点群データをダウンロードしています ...")
    urllib.request.urlretrieve(url, ply_path)
    print("ダウンロード完了:", ply_path)

# PLY ファイルを読み込む
pcd = o3d.io.read_point_cloud(ply_path)
print(pcd)  # 点の数などの情報を表示

# インタラクティブに表示(マウスで回転・拡大縮小できる)
o3d.visualization.draw_geometries([pcd])

色付き点群のインタラクティブ表示

第5章 演習2:ダウンサンプリングと外れ値の除去

テーマ名:点群を間引き、外れ値(ノイズ)を除去してから表示する。

手順:

ヒント:

考察ポイント:

import os
import urllib.request
import open3d as o3d

# このスクリプトが存在するディレクトリを取得(カレントディレクトリではない)
script_dir = os.path.dirname(os.path.abspath(__file__))

# 色情報(RGB)付きの PLY 形式の点群データ(Redwood リビングルーム)
url = "https://github.com/isl-org/open3d_downloads/releases/download/20220201-data/fragment.ply"
ply_path = os.path.join(script_dir, "fragment.ply")

if not os.path.exists(ply_path):
    print("点群データをダウンロードしています ...")
    urllib.request.urlretrieve(url, ply_path)
    print("ダウンロード完了:", ply_path)

pcd = o3d.io.read_point_cloud(ply_path)
print("元の点の数:", len(pcd.points))

# ボクセルダウンサンプリング(voxel_size を大きくするほど点が減る)
voxel_size = 0.02
down = pcd.voxel_down_sample(voxel_size=voxel_size)
print("間引き後の点の数:", len(down.points))

# 統計的外れ値除去(周囲の点から見て離れた点を取り除く)
clean, _ = down.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0)
print("外れ値除去後の点の数:", len(clean.points))

# 前処理後の点群を表示
o3d.visualization.draw_geometries([clean])

ダウンサンプリングと外れ値除去の結果

第6章 演習3:法線の推定と面の向きで色分け表示

テーマ名:各点の法線を推定し、法線の向きを色に変換して面の構造を表示する。

法線(ほうせん)とは、各点における「面が向いている向き」を表すベクトルです。法線は、面の向きの計算、陰影付け(ライティング)、メッシュ化などに使う情報です。この演習では法線を推定したうえで、法線ベクトルの向きを色に変換して表示します。こうすると、同じ向きを向いた面(たとえば床・壁・天井)が異なる色で塗り分けられます。面の向きを見やすくするため、点が本来持っている色(RGB)を、法線から作った色で塗り替えます。

手順:

ヒント:

考察ポイント:

import os
import urllib.request
import numpy as np
import open3d as o3d

# このスクリプトが存在するディレクトリを取得(カレントディレクトリではない)
script_dir = os.path.dirname(os.path.abspath(__file__))

# 色情報(RGB)付きの PLY 形式の点群データ(Redwood リビングルーム)
url = "https://github.com/isl-org/open3d_downloads/releases/download/20220201-data/fragment.ply"
ply_path = os.path.join(script_dir, "fragment.ply")

if not os.path.exists(ply_path):
    print("点群データをダウンロードしています ...")
    urllib.request.urlretrieve(url, ply_path)
    print("ダウンロード完了:", ply_path)

pcd = o3d.io.read_point_cloud(ply_path)

# 各点の法線を推定する
# radius: 法線推定に使う近傍の半径, max_nn: 使う近傍点の最大数
pcd.estimate_normals(
    search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30)
)

# 法線の向きをそろえる(向きの反転を減らす)
pcd.orient_normals_consistent_tangent_plane(k=30)

# 【活用例】法線ベクトル (x, y, z) を色 (R, G, B) に変換して塗り分ける
# (面の向きを見やすくするため、元の色はここで上書きする)
# 成分は -1〜1 の範囲なので、0〜1 に変換して色として使う
normals = np.asarray(pcd.normals)
colors = (normals + 1.0) / 2.0
pcd.colors = o3d.utility.Vector3dVector(colors)

# 面の向きごとに色分けされた点群を表示する
o3d.visualization.draw_geometries([pcd])

法線の向きで色分けした点群

第7章 演習4:色付き点群をメッシュ化する

テーマ名:色を保ったまま点群をメッシュ化し、立体モデルとして表示する。

メッシュ化とは、点の集まりである点群から、三角形の面をつないだ立体モデル(メッシュ)を復元することです。点だけでは面や表面が示されませんが、メッシュにすると連続した表面として扱えます。この演習では、点が本来持っている色(RGB)を保ったままメッシュ化するボールピボット法を使います。この方法は入力点をそのままメッシュの頂点として使うため、点群の色がそのまま頂点の色になります。メッシュ化には各点の法線が必要なので、法線を推定してから実行します。

手順:

ヒント:

考察ポイント:

import os
import urllib.request
import open3d as o3d

# このスクリプトが存在するディレクトリを取得(カレントディレクトリではない)
script_dir = os.path.dirname(os.path.abspath(__file__))

# 色情報(RGB)付きの PLY 形式の点群データ(Redwood リビングルーム)
url = "https://github.com/isl-org/open3d_downloads/releases/download/20220201-data/fragment.ply"
ply_path = os.path.join(script_dir, "fragment.ply")

if not os.path.exists(ply_path):
    print("点群データをダウンロードしています ...")
    urllib.request.urlretrieve(url, ply_path)
    print("ダウンロード完了:", ply_path)

pcd = o3d.io.read_point_cloud(ply_path)

# メッシュ化には法線が必要なので、各点の法線を推定する
pcd.estimate_normals(
    search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30)
)
pcd.orient_normals_consistent_tangent_plane(k=30)

# ボールピボット法でメッシュ化する(点の色はそのまま頂点色になる)
# radii: 点群の上を転がすボールの半径のリスト(複数指定できる)
radii = [0.01, 0.02, 0.04]
mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(
    pcd, o3d.utility.DoubleVector(radii)
)
print(mesh)  # 頂点数・三角形数などの情報を表示

# 復元した色付きメッシュを表示する
o3d.visualization.draw_geometries([mesh])