3D Gaussian Splattingについて調べてみた

# モチベーション
2023年夏に3D Gaussian Splattingが発表され、物体・空間の3Dスキャンが自分の想像以上に精緻に、しかもスマホでも利用可能になっていることを知って驚き、どのように実現しているのか、実際どんな感じのモデリングができるのか知りたくなった！

3D Gaussian Splattingのデモ動画などは、例えばこちらのように、YouTubeにも多数上がっています。

https://www.youtube.com/watch?v=mD0oBE9LJTQ

というわけで本記事の内容は、

:::note info 
* 3D Gaussian Splattingの論文の概要をざっくりまとめてみた。
:::

です。


# 論文
* **論文**

https://arxiv.org/abs/2308.04079

* **研究グループのサイト**
論文と合わせて、GithubやColabなどがあります。

https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/?source=post_page-----273ce61200a8--------------------------------

# アプリ
* **Luma AI**
スマホにアプリをダウンロードして、撮影を行うと、3Dモデリングを生成してくれる。
（私がiPhoneで撮影したものでは、処理に45分〜1時間程度かかっていたかと思います。）

https://lumalabs.ai/

# 3D Gaussian Splattingの紹介
### だいぶざっくり概要
- コンピュータグラフィックスでは、三角形などを代表に、多角形ポリゴンを連結することで立体をモデリングしている。


|<img alt=hoge.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/01c900dd-a7e3-5d8e-1648-372a048bbebf.png width=300>|
|:--|
|ポリゴンでイルカをモデリングした例。<br>出典：Wikipedia「ポリゴン」https://ja.wikipedia.org/wiki/%E3%83%9D%E3%83%AA%E3%82%B4%E3%83%B3|


- Gaussian Splattingでは、**３次元ガウシアン**で表現される**ポイントクラウド**を使用する。
３次元ガウシアンは以下のパラメータを使って表現される。
    - **Position**：位置 (X・Y・Z)
    - **Covariance**：共分散（X・Y・Z方向にどのように伸びているかを表す行列）
    - **Color**：色（RGB）
    - **Alpha**：不透明度（α）

|<img alt=img0.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/81d258f6-553f-d7b3-7fc2-bf573f69835b.png>|<img alt=img0.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/0b7b36af-5521-77a6-8444-b438380d3db6.png>|
|:--|:--|
|単一の３次元ガウシアンを２次元で見た（レンダリングした）イメージ。<br>出典：https://huggingface.co/blog/gaussian-splatting|複数の３次元ガウシアンのレンダリングイメージ。<br>出典：https://huggingface.co/blog/gaussian-splatting|

|<img alt=hoge.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/512098cb-ce3b-97f6-48f7-752f18646bd3.png>|
|:--|
|2次元ガウス分布とその分散共分散行列。<br>共分散の絶対値が大きくなるほど、その変数同士はお互いに強く関係し合った値になる。<br>出典：https://www.iwanttobeacat.com/entry/2018/02/11/134145#google_vignette|

- このような３次元ガウシアン（楕円の回転体のようなものをポリゴンとしたようなイメージ？）を多数生成し、それぞれにおいて上記パラメータ（位置・共分散・色・不透明度）を機械学習によって最適化し、それらを滑らかに繋げることで、３次元データを表す。
またこれを２次元である画面に射影（＝レンダリング）することで、精緻なモデリング画像を生成することができる。
以下に、「Luma AI」を使って弊社オフィスをスキャンしたデータを、机の下方向から見た画角における図を示す。机の足や床などが、よく見ると楕円の集合によって描画されていることがわかる。

|<img alt=hoge.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/fe9af989-d911-a609-5b3d-ff60f6e3d843.png>|
|:--|
|Luma AIの利用で弊社オフィスの机や椅子がモデリングされたもの。<br>ガウシアンによって構成されていること、そして弊社のオフィスが綺麗でイイ感じなことがよくわかる。

- “splat”とは、「薄い平板」や「水気のある物が床などにたたき付けられたり、はねたりする音」のことだそうで、自分の解釈では、立体である3次元ガウシアンを2次元に投影することを指して”gaussian splatting (ガウシアンをペシャッと2次元にする)”なのではないか？と思う。

### もうちょっと詳しく（Gaussian Splattingのアーキテクチャ）
|<img alt=hoge.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/98c6edd1-c740-5893-979b-99d641cdbd33.png>|
|:--|
|3D Gaussian Splattingの論文に掲載されたアーキテクチャの日本語訳。<br>出典：https://www.youtube.com/watch?v=9vSyJQrpn5Y の1:00:13あたりから、本図による解説あり。|


**1. カメラ位置と疎点群の推定**
まず、入力画像から、「カメラ位置の推定」および「疎な点群の生成」を行う。
ここでは、従来技術であるSfM（Structure from Motion）を用いている。入力画像間の画素のマッチングを行うことでカメラの外部パラメータ（位置や傾き）を推定し、そのパラメータをもとに疎な点群を生成する（論文では、SfM等を行えるソフトウェア「 COLMAP 」を使用している）。

|<img alt=.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/505e8845-9273-c24c-6dcf-a257b52285c8.png>|
|:--|
|SfMでは、入力した複数画像に対して特徴量のマッチングを行うことで、カメラの外部パラメータ（位置や角度）を推定。<br>出典：https://jp.mathworks.com/help/vision/ug/structure-from-motion.html

|<img alt=.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/778763a0-3b01-e4cb-2dba-6ec98fddbae6.png>|
|:--|
|弊社オフィスをLuma AIでモデリングした際の疎点群。この疎点群を、適切な形状のガウシアンへと調整する。|

**2. ガウシアンのパラメータ最適化**
- 疎な点群に対して３次元ガウシアンのパラメータを付与し、Pytorchを使用した計算によってパラメータを最適化する。
- 特に初期状態では、疎点群を中心に、最も近い3点までの距離の平均に等しい軸を持つ等方性ガウシアンを仮定して、そこから確率的勾配降下法によってパラメータ最適化を行っている。
- パラメータ最適化は、1.で推定したカメラ位置それぞれにおいてレンダリング（画面への描画＝２次元への射影）を行い、元画像との差分が最小化されることを目指して行われる。これによって、特に撮影したカメラ位置付近では、元画像に近いモデリングを描画することが可能である。

**3. パラメータ最適化における適応的制御**
上記の単純（？）なパラメータ最適化だけでは、ガウシアン密度の過不足が起こりうるので、いくつかの工夫が施されている。代表的なものが以下。
- 100回のイテレーションごとに、透明と見なせる（＝不透明度𝛼が閾値以下である）ガウスを除去することで、単位体積あたりのガウス数とその密度を制御している。
- ガウシアンが小さい領域と、ガウシアンの分散が大きく過剰な領域をカバーしてしまっているの領域について、以下のように制御を行う。
    - ガウシアンが小さい領域については、幾何学情報を増やす必要があるので、単純に同じサイズのガウシアンを、位置勾配の方向へ複製する。
    - 過剰に大きなガウシアンがある領域は、総体積は維持しながら、より小さなガウスに分割する。

|<img alt=.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/64953c49-b00c-a0e0-d3c0-602e7b1454cd.png>|
|:--|
|ガウシアンの小さい領域・大きい領域の調整方法の模式図。<br>出典：元論文 https://arxiv.org/abs/2308.04079 Fig.4|

**4. ガウシアン用の高速微分可能ラスタライザ**
- 「ラスタライズ」とは、ベクター画像データや、本手法のように3次元を表現する情報を持ったデータをビットマップに変換する処理（要するにピクセルデータに変換する処理）のこと。
- 3次元ガウシアンは微分可能な関数であるため、カメラ方向（人間が画面に映したい画角）が決まればその方向に対する射影変換を行い、画面描画に必要な情報を得ることができる。
カメラ方向から見た深度に基づいてガウシアンにIDを付してソートし、画面に近い順に不透明度αを積算して、αが一定値に達すればその時点で積算を終了する（なぜならそれ以上は向こう側が透けて見えないのだから）。またこうした処理を、画面を16x16のタイルに分割して並列処理化することで、高速なレンダリングを可能としている。
- Gaussian Splattingの特徴は、リアルタイムでの利用に耐えるレンダリング速度である（論文の実験では、100fps以上といった従来技術の10倍以上の処理速度を報告）。

|<img alt=.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/39cab72d-b0ec-3d69-46f8-dd0a4ed338b0.png>|
|:--|
|二次元への射影イメージ。<br>出典：https://www.youtube.com/watch?v=HVv_IQKlafQ 52秒あたり|


### Luma AIによる3Dモデリングの紹介
Luma AIは、スマホにアプリをダウンロードして撮影を行うと、3Dモデリングを生成してくれます。

Luma AIでは元々NeRFという技術で学習を行っていましたが、少し前に3D Gaussian Splattingも実装されたとのことです。
ただ、私が撮影データを送った時（2023年12月の1週目ころ）には、処理画面に「Training NeRF」と出てきたので『あれっLuma AIは結局NeRFなのか？』と思いきや、いざ出力されたモデルを見ると明らかにガウシアンでモデリングされているので、やっぱり手元で見られるデータは3D Gaussian Splattingなのだと理解しています。
（もしこのあたりお詳しい方がおりましたらコメントいただけますと幸いです）

これまでも一部写真を載せている通り、Luma AIで実際に弊社オフィスの来客エリアをモデリングしてみたのですが、かなり綺麗にモデリングできていたため逆に果たしてネットの海に載せて大丈夫か確認する時間がなかったので笑、ここでは割愛させていただきます。

サイトには様々なデモがありますので、興味のある方はぜひご覧ください！

https://lumalabs.ai/


### 関連技術
- **NeRF（Neural Radiance Fields）**
以下では、3D Gaussian Splattingについても1:01:09あたりから併せて触れて説明してくれています。

https://www.youtube.com/watch?v=9vSyJQrpn5Y

- **4D Gaussian Splatting**
2023年10月頃に、4D Gaussian Splatting なる、動画版の技術も報告されているようです。

https://guanjunwu.github.io/4dgs/


### その他参考記事
- https://qiita.com/RyeWiskey/items/9ccc862db91e38e8bbc9
- https://note.com/npaka/n/ncd4b84c1e2eb#be81c3dd-74a0-4bd6-a037-54e3c870c2d1