3次元点群データの表示、ダウンサンプリング、外れ値の除去、法線の推定、メッシュ化(Python と Open3D を使用)
【概要】
3次元の点が多数集まったデータを扱います。Python と open3d を使い、色付き点群の表示、間引きと外れ値除去、法線の推定、メッシュ化を行います。
【目次】
- 3次元点群データのファイル形式の例
- インターネットで公開されている RGB-D データセットの例
- 3次元点群データを Python で表示する
- 演習1:色付き点群のダウンロードとインタラクティブ表示
- 演習2:ダウンサンプリングと外れ値の除去
- 演習3:法線の推定と面の向きで色分け表示
- 演習4:色付き点群をメッシュ化する
【関連する外部ページ】
【サイト内の関連情報】
3次元点群データとは、3次元の点が多数記述されたデータです。1つ1つの点が空間中の位置を表し、それらが集まって物体の形や空間の様子を表します。
それぞれの点は、次のような属性を持ちます。
- 座標 (x, y, z) と色情報 (R, G, B)
- 座標 (x, y, z) とラベル番号
要点:1つのオブジェクトの表面を、多数の点の集まり(3次元点群データ)として扱います。
第1章 3次元点群データのファイル形式の例
代表的なファイル形式
3次元点群データには、用途に応じて複数の標準フォーマットが使われます。代表的なものは次のとおりです。
- PLY(Polygon File Format):スタンフォード大学が開発した、頂点の座標・色・法線を扱えるフォーマット。アスキー形式とバイナリ形式があります。
- PCD(Point Cloud Data):Point Cloud Library (PCL) 由来のフォーマット。
- LAS / LAZ:測量やレーザースキャン(LiDAR)分野の標準フォーマット。LAZ は LAS を圧縮したものです。
- E57:スキャナー間のデータ交換に使われるフォーマット。
- XYZ / ASC:アスキー(テキスト)形式。
アスキー形式(XYZ / ASC)
1行で1つの点を表します。データは半角の空白文字で区切られています。行の中には x, y, z の値が並び、あわせて付加情報が付くことが多いです。ファイル cloud_0.asc では、ラベル番号(「2」などの数値)が付いています。
第2章 インターネットで公開されている RGB-D データセットの例
このあとの実習では、次に紹介する Redwood データセットの点群を使います。

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

http://redwood-data.org/3dscan/dataset.html
第3章 3次元点群データを Python で表示する
ここからは、色情報(RGB)を持つ点群を題材に、Python での可視化と基本的な処理を行います。使用するのは、Redwood データセットのリビングルームを撮影した、色付きの PLY 形式の点群データです。
4つの演習のコードは、いずれも同じ点群データを、プログラム(スクリプト)自身が置かれているディレクトリにダウンロードして利用します。各コードは他のコードに依存せず、それぞれ単体で実行できます。
準備:必要なライブラリ
点群ファイルの読み込みと可視化には open3d を、数値計算には numpy を使います。あらかじめ次のコマンドでインストールしてください(Python 3.12 環境が対象です)。
python -m pip install -U --no-user numpy open3d
第4章 演習1:色付き点群のダウンロードとインタラクティブ表示
テーマ名:色付き点群をダウンロードして、open3d のビューアで表示する。
手順:
- 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。実行すると、点群データがスクリプトと同じディレクトリにダウンロードされる。
- 別ウインドウが開いたら、マウスのドラッグで回転、ホイールで拡大縮小して点群を観察する。
ヒント:
- ダウンロード先は、カレントディレクトリではなく、スクリプトが置かれているディレクトリである。
print(pcd)の出力に、点の数が表示される。
考察ポイント:
- 点群が何個の点でできているかを、出力から読み取る。
- 色情報が付いていることが、表示された点群の見え方からわかるかを確かめる。
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:ダウンサンプリングと外れ値の除去
テーマ名:点群を間引き、外れ値(ノイズ)を除去してから表示する。
手順:
- 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。
- 表示される「元の点の数」「間引き後の点の数」「外れ値除去後の点の数」を確認する。
- 別ウインドウで、前処理後の点群を観察する。
ヒント:
- ボクセルダウンサンプリングは、空間を立方体(ボクセル)で区切り、その中の点を1つにまとめる処理である。
- 外れ値除去は、指定した近傍点数から見て統計的に離れている点を取り除く処理である。
考察ポイント:
- 3つの点の数を比べ、各処理で点がどれだけ減ったかを読み取る。
- 前処理の前後で、点群の見た目がどう変わったかを確かめる。
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)を、法線から作った色で塗り替えます。
手順:
- 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。
- 別ウインドウで、面の向きごとに色分けされた点群を観察する。
ヒント:
- 法線の成分は -1〜1 の範囲なので、0〜1 に変換して色として使う。
- 床・壁・天井は面の向きが異なるので、別の色で表示される。
考察ポイント:
- どの領域が同じ色になっているかを見て、面の向きと色の対応を読み取る。
- 色の切り替わる境目が、物体のどの部分に当たるかを確かめる。
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)を保ったままメッシュ化するボールピボット法を使います。この方法は入力点をそのままメッシュの頂点として使うため、点群の色がそのまま頂点の色になります。メッシュ化には各点の法線が必要なので、法線を推定してから実行します。
手順:
- 次のコードを実行(メモ帳を用いる場合は a.py のようなファイル名で保存して実行)する。
- 別ウインドウで、点の色を保ったまま三角形の面でつながったメッシュを観察する。
ヒント:
- radii は、点群の上を転がすボールの半径のリストで、複数の値を指定できる。
print(mesh)の出力に、頂点数と三角形数が表示される。
考察ポイント:
- 点群の表示(演習1)とメッシュの表示を比べ、面がつながることで見え方がどう変わるかを読み取る。
- radii の値と、面のつながり方や穴の増減の関係を確かめる。半径が小さいと穴が増え、大きいと細部がつぶれる。
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])
