Show HN: 3Dから2Dへ、点群の平坦化(ジオメトリイメージ)
Show HN: 3D to 2D, point clouds flattening (geometry images) (github.com)
要約
この記事は、3D点群データを平坦な2D画像に変換するPythonライブラリ`flatpoints`を紹介しています。これにより、CNNなどの2D画像処理技術を3Dデータに適用できるようになり、リサンプリングや圧縮などの応用が可能になります。点群データを、隣接するピクセルが表面上の隣接する点を表すグリッド形式に変換します。
全文翻訳
3D点群を平坦なものに変換します。
| 入力: 生の点群 | 出力: 平坦な変換 |
|---|---|
| [画像: バニーの点群] | [画像: バニーの平坦化] |
flatpointsは、生の点群 (N, 3) をピクセルの正方形 (n, n) グリッドに配置します。
- 1ピクセルにつき1点: 各点に独自のピクセルが割り当てられます。
インデックス → (行, 列) - 隣接ピクセルに隣接点: 2つの隣接ピクセルは表面上で近い2つの点を保持するため、画像は表面の連続した表現となります。
点に付随する任意のデータ (N, *C) は、画像 (n, n, *C) になります。XYZ座標、法線、色、特徴量など…そして、畳み込みやCNN、SVD、グリッド補間など、2Dツールのすべてが点群に適用できます。
これは、表面を完全に規則的なグリッドに再メッシュするGu, Gortler & Hoppe (2002)のジオメトリイメージのアイデアです。flatpointsはこれを点群に直接適用します。仕組みについては、Method.mdを参照してください。
インストール
pip install flatpoints # コア: numpy, scipy, gridpoints, open3d
pip install "flatpoints[viz]" # + matplotlib, Pillow (プロット、アニメーション)
pip install "flatpoints[compress]" # + PyWavelets, Pillow (圧縮)
# または pip install "flatpoints[all]" # (すべて)
クイックスタート
生の3D点群 (N, 3) を取得し、画像に変換します。利用可能なモデル: バニー、ドラゴン、象、飛行機、牛、エベレスト… (fp.datasets())
import flatpoints as fp
fp.exemple_flat("bunny") # シェイプを表示し、表面とその画像をプロットします
fp.exemple_flat("bunny", save="plots", animate=True) # + plots/bunny.png と plots/animation/bunny.webp を保存します
使用法
import numpy as np
import flatpoints as fp
xyz = fp.load("bunny") # 生の (N, 3) 点、潜在的な(未知の)表面上
z = xyz[:, -1] #(N, *C) 点群に関連する任意のデータ、例えばz座標
# ==== Flat オブジェクトの構築 ============
flat = fp.Flat(xyz) # 表面の平坦化処理を適用します
# flat = fp.Flat(xyz, mesh=(vertices, triangles)) # メッシュを追加入力として提供します(オプション)。
# ==== 使用法: ピクセルと画像 ========
i = 42 # インデックス42の点 (xyz[42])
face, row, col = flat.pixels[i] # face: 0 または 1 (カットのセクションを参照)
image_z = flat.to_image(z) # 完全なピクセル画像、 (N, *C) から (1, n, n, *C) または (2, n, n, *C) へ
fig = flat.plot() # 3Dでの表面とその画像
fig = flat.imshow(z) # 画像上に任意のデータをプロットします
anim = flat.imshow(z, animate="z.webp") # アニメーションバージョン
カット
表面を正方形に正しくマッピングするために、flatpointsは必要に応じてまず表面を2つの半球にカットする必要があります。半球カットは、一部(すべてではない)の位相的な閉包性を除去します。残りの閉包性(例: トーラス、単一のカットでは開けないもの)も、各半球で表面をさらにせん断することによって自動的にカットされます。
- 開いた表面(例: 地形)を単一の画像に平坦化するには、
fp.Flat(points, single_face=True)を使用します。 - 閉じた表面(例: ドラゴン)を左右の半球で独立して2つの画像に平坦化するには、
fp.Flat(points, single_face=False)を使用します。
normal_axis (fp.Flat(points, single_face=..., normal_axis = "x")) を指定して、表面がどの軸に沿って表示されるかを制御できます。single_face = False(2つの半球)の場合、表面はその中心で大まかにカットされます。任意の法線軸は正常に機能しますが、異なるカット結果になります。single_face = True(開いた表面)の場合、法線軸は画像の向き(上方向、コーナーの配置)のみに使用されます。
fp.exemple_flat(examples.py)を参照してください。
アプリケーション: 点群のリサンプリング
fp.exemple_sampler("bunny", save="plots") # plots/resampling/bunny_resampled.png
メッシュからのサンプリングは簡単です。各三角形上で一様にサンプリングします。点群からのリサンプリングは、サンプリング対象の表面がなく、点しかないため、より困難です。
画像は、その失われた表面を提供します。to_image(xyz)は単位正方形を点群上にマッピングします。したがって、単位正方形内に点をサンプリングし、XYZ画像の双一次補間(行、列)→ XYZによって表面に転送できます。
デフォルトでは、flat.resampleはハイパーユニフォームな2Dシード(ブルーノイズ)を使用するため、新しい点は表面全体にかなり均一に分散されます。method = "ot"が使用される場合、初期リサンプリングは最適輸送を使用してさらに最適化されます。
sampler = flat.resample(n_points=512, method="ot") # 合計512個の新しい点
new = sampler.points # (512, 3)
sampler.plot() # 前 / 後
正直に言うと: 入力点のサブセットのみが必要な場合、最遠点サンプリング(FPS)はflatpointsとほぼ同等に均一です(FPSはわずかに小さい最悪ケースの穴を持ち、flatpoints.resampleはわずかに低いOT損失を持ちます)。これは主に、画像を使用して、単純な単位正方形から任意の表面への良好な空間的再分散のようなプロパティを転送する方法を示すためのユースケースです。
アプリケーション: 点群の圧縮
PyWaveletsとPillowが必要です(pip install "flatpoints[compress]")
fp.exemple_compression("bunny", save="plots") # plots/compression/bunny.png
隣接ピクセルに隣接点が保持されるため、XYZ画像は滑らかであり、滑らかな画像はよく圧縮されます。flat.compressは、3つの方法のいずれかでそれらを圧縮します(compressor.py):
- `