「Point-E」 3Dモデルを作成するAI PythonのCollabでやってみましょう。AIで3Dモデルは本当に作成できるか？


# イントロ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/161fa0bc-6993-293d-3d4f-5b0d3e1b73c8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/5a2cb8dc-3bbb-e271-fe5e-d5432ebcb3a2.png)
Openaiは12月に[「point-e」のGithub](https://github.com/openai/point-e)を公開されて、テクストや2D画像から1~2分で3Dモデルを作成できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/b31b94eb-6011-ae90-58b7-ef2123e917b0.png)

今回の記事のコードはすべてCollab内で利用できるものです。ぜひcollabのノートブックを使ってください 
→[リンク](https://colab.research.google.com/drive/1k8E047VCRt_-SZJLRi5ahL3ttt7O_Nur?usp=sharing)←

# Point-E collabでセットアップする
最初にPoint-Eを設定しましょう。これは簡単です。githubのレポをダウンロードして、インストールするだけです。
```python
!git clone https://github.com/openai/point-e.git
%cd point-e
!pip install -e .
```

# AIで3Dモデルを作成

実にPoint-Eは二つのモデルです。最初に2Dの画像からPointCloud（点群）を作成するDiffusionModelです。二つ目は、PointCloudからメッシュを作成するSDFモデルです。論文参考： [Nichol 2022  Point·E: A System for Generating 3D Point Clouds from Complex Prompts](https://arxiv.org/pdf/2212.08751.pdf)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/13d46076-f37b-a3b5-e9e5-3239eadea26a.png)

最初のセットアップがUPとDownのサンプルのモデルをセットアップすることです。このモデルはDiffusion種類のモデルです。ノイズからものを作れるモデルです（詳しい説明の記事の[リンク](https://zenn.dev/nakky/articles/09fb1804001ff8)）、最近のAIアートでよく利用しています

# モデルのセットアップ

```python
#Imports 
from PIL import Image
import torch
from tqdm.auto import tqdm
from point_e.diffusion.configs import DIFFUSION_CONFIGS, diffusion_from_config
from point_e.models.download import load_checkpoint
from point_e.models.configs import MODEL_CONFIGS, model_from_config
from point_e.util.plotting import plot_point_cloud

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
#Base down sampling moderl
print('creating base model...')

base_name = 'base40M' # use base300M or base1B for better results 
#base40M-textvec text promt 
base_model = model_from_config(MODEL_CONFIGS[base_name], device)
base_model.eval()
base_diffusion = diffusion_from_config(DIFFUSION_CONFIGS[base_name])
#Updasmpling model 
print('creating upsample model...')
upsampler_model = model_from_config(MODEL_CONFIGS['upsample'], device)
upsampler_model.eval()
upsampler_diffusion = diffusion_from_config(DIFFUSION_CONFIGS['upsample'])

#Load state 
print('downloading base checkpoint...')
base_model.load_state_dict(load_checkpoint(base_name, device))
print('downloading upsampler checkpoint...')
upsampler_model.load_state_dict(load_checkpoint('upsample', device))
```

最初に変更できる変数は「base_name」です。これはモデルの名前です。base40Mは標準ですが、もっと精度が高い結果が欲しければ、base300Mとbase1Bに変換できます。（Mは百万枚という意味です。40百万枚の画像で訓練してくれて、OpenAIさん　ありがとうございます。）

ここには、textのプロンプトからモデルに変換できます。base_nameで、「-textvec」を加えば、モデルはテクストから3Dモデルを作成できます。

次のステップはPointCloudのモデルをセットアップです。「PointCloudSampler」というクラスを定義して、モデル変数とポイント数の設定があります。上に定義したBase_modelとupsample_modelとdiffusionのモデルを入り込みます。次はnum_pointsというパラメーターがあります。最初にこれはX,Y,Zの点だと思ったが、実にbase_modelのポイントとupsamplerのポイントです（参考 [point-e/issues/7](https://github.com/openai/point-e/issues/7))。最後にテクストのプロンプトを使いたい場合は、model_kwargs_key_filterのコメントを削除してください

```python
from point_e.diffusion.sampler import PointCloudSampler

sampler = PointCloudSampler(
    device=device,
    models=[base_model, upsampler_model],
    diffusions=[base_diffusion, upsampler_diffusion],
    num_points=[1024, 4096 - 1024]
    aux_channels=['R', 'G', 'B'],
    guidance_scale=[3.0, 3.0],
#model_kwargs_key_filter=('texts', ''), #text promt read 
)
```

# PointCloud(点群）を作成
samplerを定義した後で、次はsamplerのpointcloud(点群）を作成する関数を実行してみます。これは「sample_batch_progressiveです」です。複数の画像にも対応できます。その場合がsamplesはarrayに変更して、xを「np.append(x)」に変更してください。

```python
img = Image.open('/content/point-e/point_e/examples/example_data/corgi.jpg')
samples = None
for x in tqdm(sampler.sample_batch_progressive(batch_size=1, model_kwargs=dict(images=[img]))):
    samples = x

```

上記の例は画像から予測の例です。テクストのプロンプトを使いたい場合は、imagesがtextsに変更して、そこでpromptを入り込んでください

```python
#Prompt 
prompt = "train"
samples = None
for x in tqdm(sampler.sample_batch_progressive(batch_size=1,model_kwargs=dict(texts=[prompt]))):
  samples=x
```

次は、この結果を表示しましょう。運があり、Point-Eのモジュール内では、plot_point_cloudの関数プロットがあります
```python
pc = sampler.output_to_point_clouds(samples)[0]
fig = plot_point_cloud(pc, grid_size=3, fixed_bounds=((-0.75, -0.75, -0.75),(0.75, 0.75, 0.75)))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/9713f419-7e1e-b96f-0421-84c90dd4e0a1.png)

# PointCloud(点群）からメッシュを作成
Pointcloudを作成した後で、次はメッシュを作ります。Point-Eでは、SDFモデルを利用して、PointCloudからメッシュに変換できます。下記のコードでは、modelの定義した後で、marching_cubes_meshの関数はメッシュへ変換の処理を行います。解像度を上げりたいなら、grid_sizeを上げってください。

```python
from point_e.util.pc_to_mesh import marching_cubes_mesh
import skimage.measure #変な skimageのエラー対策

#Load model
print('creating SDF model...')
name = 'sdf'
model = model_from_config(MODEL_CONFIGS[name], device)
model.eval()
print('loading SDF model...')
model.load_state_dict(load_checkpoint(name, device))

#メッシュをサック性
# Produce a mesh (with vertex colors)
mesh = marching_cubes_mesh(
    pc=pc,
    model=model,
    batch_size=4096,
    grid_size=32, # increase to 128 for resolution used in evals
    progress=True,
)


# Write the mesh to a PLY file to import into some other program.
# Plyのファイルで保存する
prompt="corgy"
with open(f'{prompt.replace(" ","-")}_mesh.ply', 'wb') as f:
    mesh.write_ply(f)
```
メッシュを作成した後で、.plyのファイルで保存して、blenderでインポートしてみましょう。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/ee88e006-12b2-17a5-aa5f-b35d1f9079fe.png)

<div align="center">
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/18f6759e-5523-3ad6-cad5-a4b3baf34727.png" width=30%>
</div>


結果はひどいですね（笑)。　解像度を上げ、別のモデルを使ってみましたが、結果の精度を上げれません。この良くない結果は、github内でよくあるそうです  [point-e/issues/15](https://github.com/openai/point-e/issues/15)。まだ開発中だからね。私よりうまく結果ができれば、共有してくださいね (@jarvissan22)。

# クルミちゃんの3Dモデルの結果は？


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/c7ae55a7-b033-51e9-013d-674f1d832eed.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/c81e7238-8c7f-63a5-b8ef-3f41eba397e8.png)