OpenVINO™ を使用した 3D 点群パーツのセグメント化#

この Jupyter ノートブックはオンラインで起動でき、ブラウザーのウィンドウで対話型環境を開きます。ローカルにインストールすることもできます。次のオプションのいずれかを選択します:

BinderGoogle ColabGitHub

このノートブックでは、点群データを処理し、OpenVINO で 3D パーツのセグメント化を実行する方法を説明します。PointNet の事前トレーニング済みモデルを使用して椅子の各パーツを検出し、そのカテゴリーを返します。

PointNet#

PointNet は、2016 年にスタンフォード大学の研究者 Charles Ruizhongtai Qi によって提案されました: PointNet: 3D 分類およびセグメント化のための点セットに関するディープラーニング。研究の目的は、画像の 3D 表現を分類してセグメント化することです。これらは、3D 形状またはオブジェクトを表す点のセットである点群と呼ばれるデータ構造を使用します。PointNet は、オブジェクトの分類、パーツのセグメント化、シーンのセマンティック解析に至るまでのアプリケーションに統合アーキテクチャーを提供します。非常に効率的かつ効果的で、最先端技術と同等、またはそれ以上の強力なパフォーマンスを示します。

目次:

import platform 

%pip install -q "openvino>=2023.1.0" "tqdm" 

if platform.system() != "Windows":
     %pip install -q "matplotlib>=3.4" 
else:
     %pip install -q "matplotlib>=3.4,<3.7"
Note: you may need to restart the kernel to use updated packages.
Note: you may need to restart the kernel to use updated packages.

インポート#

from pathlib import Path 
from typing import Union 
import numpy as np 
import matplotlib.pyplot as plt 
import openvino as ov 

# `notebook_utils` モジュールを取得 
import requests 

r = requests.get( 

url="https://raw.githubusercontent.com/openvinotoolkit/openvino_notebooks/latest/utils/notebook_utils.py", 
) 
open("notebook_utils.py", "w").write(r.text) 

from notebook_utils import download_file

モデルの準備#

事前トレーニングされた PointNet ONNX モデルをダウンロードします。この事前トレーニング済みモデルは axinc-ai で提供されており、その他の点群の例はこちらで見つけることができます。

# データとモデルのディレクトリー、モデルソースの URL、モデルファイル名を設定 
MODEL_DIR = Path("model") 
MODEL_DIR.mkdir(exist_ok=True) 
download_file( 
    "https://storage.googleapis.com/ailia-models/pointnet_pytorch/chair_100.onnx", 
    directory=Path(MODEL_DIR), 
    show_progress=False, 
) 
onnx_model_path = MODEL_DIR / "chair_100.onnx"

ONNX モデルを OpenVINO IR に変換します。OpenVINO IR (中間表現) モデルは、ネットワーク・トポロジーに関する情報を含む .xml ファイルと、重みとバイアスのバイナリーデータを含む .bin ファイルで構成されます。モデル変換 Python API は、ONNX モデルから OpenVINO IR への変換に使用されます。ov.convert_model Python 関数は、デバイスにロードして予測を開始できる状態の OpenVINO モデルを返します。ov.save_model を使用して、次回使用するためディスクに保存できます。モデル変換 Python API の詳細については、このページを参照してください。

ir_model_xml = onnx_model_path.with_suffix(".xml") 

core = ov.Core() 

if not ir_model_xml.exists():
    # モデルを OpenVINO モデルに変換 
    model = ov.convert_model(onnx_model_path) 
    # モデルを OpenVINO IR 形式 xml + bin でシリアル化 
    ov.save_model(model, ir_model_xml) 
else:
    # モデルをリード 
    model = core.read_model(model=ir_model_xml)

データ処理モジュール#

def load_data(point_file: Union[str, Path]): 
    """
    Load the point cloud data and convert it to ndarray 

    Parameters: 
        point_file: string, path of .pts data 
    Returns: 
        point_set: point clound represented in np.array format 
    """

    point_set = np.loadtxt(point_file).astype(np.float32) 

    # 正規化 
    point_set = point_set - np.expand_dims(np.mean(point_set, axis=0), 0) # center 
    dist = np.max(np.sqrt(np.sum(point_set**2, axis=1)), 0) 
    point_set = point_set / dist # scale 

    return point_set 

def visualize(point_set: np.ndarray): 
    """
    Create a 3D view for data visualization 

    Parameters: 
        point_set: np.ndarray, the coordinate data in X Y Z format 
    """

    fig = plt.figure(dpi=192, figsize=(4, 4)) 
    ax = fig.add_subplot(111, projection="3d") 
    X = point_set[:, 0] 
    Y = point_set[:, 2] 
    Z = point_set[:, 1] 

    # 各軸のビューをスケーリングして、座標データ分布に適応 
    max_range = np.array([X.max() - X.min(), Y.max() - Y.min(), Z.max() - Z.min()]).max() * 0.5 
    mid_x = (X.max() + X.min()) * 0.5 
    mid_y = (Y.max() + Y.min()) * 0.5 
    mid_z = (Z.max() + Z.min()) * 0.5 
    ax.set_xlim(mid_x - max_range, mid_x + max_range) 
    ax.set_ylim(mid_y - max_range, mid_y + max_range) 
    ax.set_zlim(mid_z - max_range, mid_z + max_range) 

    plt.tick_params(labelsize=5) 
    ax.set_xlabel("X", fontsize=10) 
    ax.set_ylabel("Y", fontsize=10) 
    ax.set_zlabel("Z", fontsize=10) 

    return ax

元の 3D データを可視化#

点群データは、3D 形状の大規模データセットである ShapeNet からダウンロードできます。ここでは例として椅子の 3D データを選択します。

# Download data from the openvino_notebooks storage 
point_data = download_file( 

"https://storage.openvinotoolkit.org/repositories/openvino_notebooks/data/data/pts/chair.pts", 
    directory="data", 
) 

points = load_data(str(point_data)) 
X = points[:, 0] 
Y = points[:, 2] 
Z = points[:, 1] 
ax = visualize(points) 
ax.scatter3D(X, Y, Z, s=5, cmap="jet", marker="o", label="chair") 
ax.set_title("3D Visualization") 
plt.legend(loc="upper right", fontsize=8) 
plt.show()
data/chair.pts: 0%|          | 0.00/69.2k [00:00<?, ?B/s]
/tmp/ipykernel_113341/2434168836.py:12: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored ax.scatter3D(X, Y, Z, s=5, cmap="jet", marker="o", label="chair")
../_images/3D-segmentation-point-clouds-with-output_11_2.png

推論の実行#

推論を実行し、3D セグメント化の結果を視覚化します。- 入力データは、1 バッチサイズ、3 軸値 (x、y、z) および任意の数の点 (動的形状) を持つ点群です。- 出力データは、入力ポイントごとに 1 つのバッチサイズと 4 つの分類信頼度を持つマスクです。

# 椅子の部品 
classes = ["back", "seat", "leg", "arm"] 

# 入力データを前処理 
point = points.transpose(1, 0) 
point = np.expand_dims(point, axis=0) 

# モデルの入力と出力の形状に関する情報をプリント 
print(f"input shape: {model.input(0).partial_shape}") 
print(f"output shape: {model.output(0).partial_shape}")
input shape: [1,3,?] 
output shape: [1,?,4]

推論デバイスの選択#

OpenVINO を使用して推論を実行するためにドロップダウン・リストからデバイスを選択します

import ipywidgets as widgets 

device = widgets.Dropdown( 
    options=core.available_devices + ["AUTO"], 
    value="AUTO", 
    description="Device:", 
    disabled=False, 
) 

device
Dropdown(description='Device:', index=1, options=('CPU', 'AUTO'), value='AUTO')
# 推論 
compiled_model = core.compile_model(model=model, device_name=device.value) 
output_layer = compiled_model.output(0) 
result = compiled_model([point])[output_layer] 

# 椅子のすべてのポイントのラベルマップを最高の信頼性で検出 
pred = np.argmax(result[0], axis=1) 
ax = visualize(point) 
for i, name in enumerate([0, 1, 2, 3]):
    XCur = [] 
    YCur = [] 
    ZCur = [] 
    for j, nameCur in enumerate(pred): 
        if name == nameCur:
            XCur.append(X[j]) 
            YCur.append(Y[j]) 
            ZCur.append(Z[j]) 
    XCur = np.array(XCur) 
    YCur = np.array(YCur) 
    ZCur = np.array(ZCur) 
    # パーツの現在のポイントを追加 
    ax.scatter(XCur, YCur, ZCur, s=5, cmap="jet", marker="o", label=classes[i]) 

ax.set_title("3D Segmentation Visualization") 
plt.legend(loc="upper right", fontsize=8) 
plt.show()
/tmp/ipykernel_113341/2804603389.py:23: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored ax.scatter(XCur, YCur, ZCur, s=5, cmap="jet", marker="o", label=classes[i])
../_images/3D-segmentation-point-clouds-with-output_16_1.png