Open3Dによる平面検出①:RANSACを利用したsegment_plane関数

画像処理および三次元物体認識

本記事では、Open3Dの平面検出手法の一例として、RANSACを利用したsegment_plane関数について解説する。

また、本記事の作成にあたり、以下の書籍が非常に参考になりましたので良ければご参考に。

なぜ平面検出を行う?

平面検出を実行するシチュエーションは以下が考えられる

  • 「平面」の特徴を持った物体(地面やテーブル)を点群情報から抽出したい
  • 平面以外の物体を点群情報から抽出したい
    平面でない物体が抽出対象の場合、平面を構成する点群情報は”除去対象”である。
    そのため、物体検出のための前処理として平面検出することがある。
    また、平面上に位置する物体(地面の車やテーブル上のマグカップなど)の検出するシチュエーションにおいて、平面を除去または「平面上に位置している」ことを活用する手法もある。

実行環境

本記事の実行環境です

  • OS:Windows 10
  • Python Ver.3.11
  • Open3d Ver.0.18.0
    インストールはこちらを参考にしました。

処理対象の点群および課題設定

処理対象の点群

RealSenseにより取得した点群およびテキスチャ情報です。

以下のRealSenseの箱とマウスの情報を、Ply形式で保存しています。

処理対象のテキスチャデータ

課題設定

以下の2つの平面を検出する

  • 箱とマウスが置かれている床
  • 写真上側にある、床の平面に対して垂直な壁

RANSACを用いた平面検出

簡単なRANSACの理論

  1. データからランダムに少数のサンプル(例: 3点)を選ぶ。
  2. サンプルを使ってモデル(平面や直線など)を仮定する。
  3. 仮定したモデルに近いデータ点(インライア)を数える。
  4. この手順を繰り返し、最も多くのインライアを含むモデルを選ぶ。

Open3Dの関数の詳細

関数

open3d.geometry.PointCloud.segment_plane

引数

  • distance_threshold: 平面上の点とみなすための最大距離(単位:m)
  • ransac_n: RANSACアルゴリズムで選択するサンプル数(通常は3)
  • num_iterations: アルゴリズムの最大反復回数

戻り値

  • plane_model: 平面の方程式([a, b, c, d])。平面は ax+by+cz+d=0 で表される。
  • inliers: 平面とみなされた点

サンプルコード

サンプルコードでは以下を実行している

import open3d as o3d
import random
import numpy as np


# 点群を読み込む
filename = 'realsensebox.ply'
print(o3d.io.read_file_geometry_type(filename))
mesh = o3d.io.read_triangle_mesh(filename)
# メッシュモデルから点群モデルへの変換
vertices = mesh.vertices
pcd = o3d.geometry.PointCloud()
pcd.points = vertices

# 外れ値除去のパラメータ設定
nb_neighbors = 20  # 各点の近傍点数
std_ratio = 2.0    # 標準偏差比(高い値にすると除去が緩やかに)
# 外れ値除去(統計的アウトライヤ除去)
pcd, ind = pcd.remove_statistical_outlier(nb_neighbors=nb_neighbors, std_ratio=std_ratio)

# ダウンサンプリング
voxel_size = 0.01  # ボクセルサイズを設定
pcd = pcd.voxel_down_sample(voxel_size=voxel_size)
o3d.visualization.draw_geometries([pcd])

# パラメータ設定
distance_threshold = 0.01  # 平面との距離の閾値
ransac_n = 3              # 平面モデルの最小点数
num_iterations = 1000     # RANSACの試行回数

# 検出された平面を格納するリスト
planes = []

while True:
    # RANSACを使って平面を検出
    plane_model, inliers = pcd.segment_plane(
        distance_threshold=distance_threshold,
        ransac_n=ransac_n,
        num_iterations=num_iterations,
    )
    
    # 小さい平面の場合、検出を終了
    if len(inliers) < 1000:
        break
    
    # 平面の点群を抽出
    plane_cloud = pcd.select_by_index(inliers)
    
    # ランダムな色を生成して塗り分け
    color = [random.uniform(0, 1) for _ in range(3)]
    plane_cloud.paint_uniform_color(color)
    
    # 平面情報を格納
    planes.append(plane_cloud)
    o3d.visualization.draw_geometries(planes)

    # 検出された平面を除去
    pcd = pcd.select_by_index(inliers, invert=True)
    o3d.visualization.draw_geometries([pcd])


# 残りの点群を特定の色で可視化
if len(pcd.points) > 0:
    pcd.paint_uniform_color([0.0, 0.0, 0.0])  # 黒色で塗りつぶし
    planes.append(pcd)

# 結果を可視化
o3d.visualization.draw_geometries(planes)

まとめ

本記事では、Open3Dの平面検出手法の一例として、RANSACを利用したsegment_plane関数について解説した。

三次元点群処理は二次元の画像処理よりも情報が少なく、手探りで書籍や論文、公式ドキュメントを調査する日々です。

その中で、導入しやすいPythonとOpen3Dで三次元点群処理を体系的にまとめた書籍が以下になります。現在数少ない三次元点群処理の書籍ですので私も重宝しています。是非参考にしてみてください。

参考リンク

タイトルとURLをコピーしました