自作の3D点群ビューアーをオープンソース化してみた

私はSLAMの研究に従事しており、3D点群データなど大規模な3Dオブジェクトを効率的に可視化する必要があるため、自分のニーズを満たすために可視化ライブラリ「q3dviewer」を開発しました。

せっかく作ったので、オープンソース化（MITライセンス）してみました！本記事では「q3dviewer」の活用例を交えながら、使い方を紹介します。多くの方に利用していただけると嬉しいです。

## q3dviewerとは

**q3dviewer**は、3Dビューアを迅速に開発するためのライブラリです。3Dオブジェクト（例えば、点群、カメラ、3Dガウス）を表示するためのアイテムを組み合わせることで、さまざまなビューアをすばやく開発できます。利用例として、[cloud_viewer](#1-cloud-viewer)、[film_maker](#3-film-maker)などのとても便利なツールも同梱しています。


### 特徴
- 効率的な3Dレンダリング：点群など大規模な3Dデータを効率的に表示可能
- 豊富な設定：3Dデータを動的に調整するためのGUIがあり、データを美しく表示可能
- 簡単に拡張：カスタマイズビューアを迅速に開発、独自のオブジェクトの表示も拡張可能

### インストール方法

LinuxまたはWindowsの端末で、以下のコマンドを実行するだけでq3dviewerをインストールできます：

```bash
pip install q3dviewer
```

**Windowsでの注意点**

- Python 3の環境を事前に準備してください:
  - [Python公式サイト](https://www.python.org/downloads/)からPython 3をダウンロードしてインストールします。
  - インストール時に「Add Python to PATH」にチェックを入れることを忘れないでください。

**Liunxの注意点：**

Ubuntu 20.04または22.04で共有ライブラリ`libxcb-cursor.so.0`の読み込みに関するエラーが発生した場合は、`libxcb-cursor0`をインストールしてください。

```sh
sudo apt-get install libxcb-cursor0
```

## ツール類

インストール後、以下のツールを直接に使用できます。

### 1. Cloud Viewer

点群ファイル（LAS、PCD、PLY、E57）の可視化ツールです。以下のコマンドで起動できます。

```sh
cloud_viewer  # これだけで、viewerが表示される
python3 -m q3dviewer.tools.cloud_viewer #コマンドが長くて、おすすめしませんが、PATHがとおらないとき
```

Viewerが起動したら、ウィンドウ上にファイルをドラッグ＆ドロップすることで点群を表示できます。複数のファイルを同時にドロップすることも可能です。

**基本操作**
* ファイルのロード：点群ファイルを画面に引っ張ってきて放すだけ（複数ファイルOK）
* `M`キー：点群、背景色などの可視化設定画面
* `マウス左ボタン`or`W,A,S,D`キー：水平面での視点移動
* `Z,X`キー：画面の向いている方向に沿って視点を移動
* `マウス右ボタン`or`矢印`キー：画面の中心(赤い点)を変えずに視点を回転
* `Shift`+`マウス右ボタン`or`Shift`+`矢印`キー：カメラの位置を変えずに視点を回転


例えば、東京都のLAS形式点群をダウンロードして確認できます。


https://www.geospatial.jp/ckan/dataset/tokyopc-23ku-2024/resource/7807d6d1-29f3-4b36-b0c8-f7aa0ea2cff3

![Screenshot from 2025-01-26 23-06-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/4e51f0aa-6646-c21b-e13f-8b76cfc72760.png)



以下の動画のように、キーボード`M`を押すと、メニューが画面に表示され、いろんな可視化設定を変更できます。点群の形状、サイズ、色、透明度など、さまざまな設定が可能ですので、ぜひ試してみてください。


<iframe width="560" height="315" src="https://www.youtube.com/embed/UuCBlQfQ-fQ?si=Ci0lYr41jYrKA8Ch" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
大阪南港にある大規模商業施設ATCの点群データです。全体で3億点がある高密度な点群を間引かずにスムーズに表示できます。


### 2. ROS Viewer

ROSとの親和性が高く、RVIZの代わりに、高性能なSLAMビューアとして使用できます。

```sh
roscore &
ros_viewer
```
以下の動画は、私が開発したF4-SLAM([F3-SLAM](https://www.jstage.jst.go.jp/article/sicetr/60/12/60_631/_article/-char/en)のバージョンアップ)のROS Viewerです。SLAMから点群を受け取りながら、リアルタイム的に点群を表示します。LiDARの点群を2D画像に投影した様子も可視化しています。


<iframe width="560" height="315" src="https://www.youtube.com/embed/OrQhS6eMd1s?si=nlZ7OiPC5zP1bvjY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

*YouTubeの設定で1080pで再生していただくと高精細な映像でご覧いただけます!*

とてもキレイな点群地図を作成していますね。F4-SLAMも近くの将来に紹介する予定ですので、ぜひお楽しみにしてください。


### 3. Film Maker


3D点群などの動画を作成する際、手動でカメラの視点を動かすことがよくありますが、その動作が不規則で美しくないです。そこで、film_makerをお試しください。

簡単なGUIを使っていくつかのキーフレームを設定することで、スムーズな補完を自動で行い、美しい点群動画を作成できます。

以下のコマンドで起動できます。

```sh
film_maker
```
**基本操作**
* ファイルのロード＆視点移動：Cloud_Viewerと同じ
* `Space`キー：キーフレームを追加
* `Delete`キー：キーフレームを削除
* Playボタン：動画の自動再生（再度押すと再生終了）
* Recordチェックボックス：チェックした状態で動作を再生すると、自動で録画

![Peek2025-02-0412-47-ezgif.com-optimize.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/378dca5f-f769-a527-5599-e833d1f669f4.gif)

*[京橋駅周辺三次元点群データ](https://www.geospatial.jp/ckan/dataset/kyoubasiekisyuuhen_las)を使用して、Film Makerで動画を作成する様子*


### 4. Gaussian Viewer

以前の記事で紹介された[3D Gaussian](https://qiita.com/scomup/items/92716342a3ef0b915e0c)の簡易ビューアです。

```sh
gaussian_viewer  # drag and drop your gaussian file to windows
```

![viewer-ezgif.com-resize.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/441e6f5a-214d-f7c1-11bf-5fa79e63b38e.gif)


### 5. LiDAR Calibration Tools


2つのLiDARの相対姿勢を計算するツールです。相対姿勢を手動で調整したり、自動キャリブレーションを行うことも可能です。

```sh
lidar_calib --lidar0=/YOUR_LIDAR0_TOPIC --lidar1=/YOUR_LIDAR1_TOPIC
```
![lidar_to_lidar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/5a8a9903-a42a-8322-1d23-0cbecd3fa99a.png)


### 6. Lidar Camera Calibration Tools

LiDARとカメラの相対姿勢を計算するツールです。相対姿勢を手動で調整し、リアルタイムでLiDARの点を画像に投影する結果を確認できます。

```sh
lidar_cam_calib --lidar=/YOUR_LIDAR_TOPIC --camera=/YOUR_CAMERA_TOPIC --camera_info=/YOUR_CAMERA_INFO_TOPIC
```

![manual_lidar_cam_calib.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/f8359820-2ae7-aa37-6577-0fa035f4dd95.png)

## ライブラリとしての使用

「q3dviewer」を使って独自の3Dビューアを簡単にカスタマイズ開発できます。以下はコーディング例です。

### カスタマイズ3Dビューア

```python
#!/usr/bin/env python3

import q3dviewer as q3d  # q3dviewerをimportする

def main():
    # Qtアプリケーションの作成
    app = q3d.QApplication([])

    # 各種3Dアイテムの作成
    axis_item = q3d.GLAxisItem(size=0.5, width=5)
    grid_item = q3d.GridItem(size=10, spacing=1)

    # ビューアの作成
    viewer = q3d.Viewer(name='example')
    # ビューアにアイテムを追加
    viewer.add_items({
        'grid': grid_item,
        'axis': axis_item,
    })

    # ビューアの表示 & Qtアプリケーションの実行
    viewer.show()
    app.exec_()

if __name__ == '__main__':
    main()
```

q3dviewerには、以下の3Dアイテムが提供されています。


- **AxisItem**: 座標軸、または自己位置の表示
- **CloudItem**: 点群の表示
- **CloudIOItem**: IO機能付きの点群表示
- **GaussianItem**: 3Dガウスの表示
- **GridItem**: グリッドの表示
- **ImageItem**: 2Dイメージの表示
- **Text2DItem**: 2Dテキストの表示
- **LineItem**: 線（ロボット軌跡など）の表示


### 独自アイテムの開発


標準で提供される3Dアイテム以外にも、簡単なコーディングで独自の3Dアイテムも可視化できます。以下はサンプルです。

```python

from OpenGL.GL import *
import numpy as np
import threading
import q3dviewer as q3d

from PySide6.QtWidgets import QLabel, QSpinBox

class YourItem(q3d.BaseItem):
    def __init__(self):
        super(YourItem, self).__init__()
        pass  # 必要な初期化

    def add_setting(self, layout):
        # このアイテムを設定するためのGUI
        label = QLabel("Add your setting:")
        layout.addWidget(label)
        box = QSpinBox()
        layout.addWidget(box)

    def set_data(self, data):
        pass  # データをsetする

    def initialize_gl(self):
        pass  # OpenGLの初期化設定(必要であれば)

    def paint(self):
        pass  # OpenGLを使って3D物体を可視化する
```

------------------

興味のある方は、ぜひ「q3dviewer」をインストールして、試してください。

ソースはGithubに公開しています。

https://github.com/scomup/q3dviewer