<ジェネレーティブNFT>パーツ画像から画像を大量生成する

<h2>目次</h2>
1. [作りたいもの](#anchor1)
2. [前提](#anchor2)
3. [コード](#anchor3)
4. [課題](#anchor3)

<h2 id=anchor1>作りたいもの</h2>
ペイントソフトを用いて作ったパーツを組み合わせて、できた画像を保存する。また、組み合わせを変えて生成することで大量に生成できるようにする。

<h2 id=anchor2>前提</h2>

・Pythonの開発環境が整っている。(Numpy、PIL)

私の環境
・Windows10 home
・Python 3.9.7
・Pythonインストール時にインストールされたライブラリ(標準ライブラリ)

<h2 id=anchor3>コード </h2>

*まだまだ改善の必要があるコードなので多めに見てくださると幸いです。

```py:main.py

from PIL import Image, ImageDraw, ImageFilter
import configparser
import numpy as np

config_ini = configparser.ConfigParser()
config_ini.read('config.ini', encoding='utf-8')

# --------------------------------------------------
# config,iniから値取得
# --------------------------------------------------
Layer0 = config_ini['Layers']['0']
Layer1 = config_ini['Layers']['1']
Layer2 = config_ini['Layers']['2']
Layer3 = config_ini['Layers']['3']
Layer4 = config_ini['Layers']['4']
Layer5 = config_ini['Layers']['5']
Layer6 = config_ini['Layers']['6']

def ImgPaste(x ,y):
    z = x
    z.alpha_composite(y)
    return z

for a in range(int(Layer0)):
    for b in range(int(Layer1)):
        for c in range(int(Layer2)):
            for d in range (int(Layer3)):
                for e in range(int(Layer4)):
                    for f in range(int(Layer5)):
                        for g in range(int(Layer6)):
                            BgImg = Image.open("input/0/" + str(a) + ".png")
                            Img1 = Image.open("input/1/" + str(b) + ".png")  # アルファチャンネル込みで読み込む
                            Img2 = Image.open("input/2/" + str(c) + ".png")
                            Img3 = Image.open("input/3/" + str(d) + ".png")
                            Img4 = Image.open("input/4/" + str(e) + ".png")
                            Img5 = Image.open("input/5/" + str(f) + ".png")
                            Img6 = Image.open("input/6/" + str(g) + ".png")

                            OutImg = ImgPaste(BgImg, Img1)
                            OutImg = ImgPaste(OutImg, Img2)
                            OutImg = ImgPaste(OutImg, Img3)
                            OutImg = ImgPaste(OutImg, Img4)
                            OutImg = ImgPaste(OutImg, Img5)
                            OutImg = ImgPaste(OutImg, Img6)

                            trueorfalse = np.random.choice(['true', 'false'], p=[0.1, 0.9])
                            if(trueorfalse == 'true'):
                                OutImg.save("output/" + str(a) + "_" + str(b) + "_" + str(c) + "_" + str(d) + "_" + str(e) + "_" + str(f) + "_" + str(g) + ".png", quality=95)
                                print("saved")

                            
                            print("output/" + str(a) + "_" + str(b) + "_" + str(c) + "_" + str(d) + "_" + str(e) + "_" + str(f) + "_" + str(g) + ".png")
    
```

<h2>解説</h2>

```py
config_ini = configparser.ConfigParser()
config_ini.read('config.ini', encoding='utf-8')

# --------------------------------------------------
# config.iniから値取得
# --------------------------------------------------
Layer0 = config_ini['Layers']['0']
Layer1 = config_ini['Layers']['1']
Layer2 = config_ini['Layers']['2']
Layer3 = config_ini['Layers']['3']
Layer4 = config_ini['Layers']['4']
Layer5 = config_ini['Layers']['5']
Layer6 = config_ini['Layers']['6']
```
↑設定ファイルからパーツの枚数を取得しています。

```py
def ImgPaste(x ,y):
    z = x
    z.alpha_composite(y)
    return z
```
↑第一引数の上に第二位引数を重ねた画像を返す関数です。PILを使用しています。

```py
for a in range(int(Layer0)):
    for b in range(int(Layer1)):
        for c in range(int(Layer2)):
            for d in range (int(Layer3)):
                for e in range(int(Layer4)):
                    for f in range(int(Layer5)):
                        for g in range(int(Layer6)):
                            BgImg = Image.open("input/0/" + str(a) + ".png")
                            Img1 = Image.open("input/1/" + str(b) + ".png")  # アルファチャンネル込みで読み込む
                            Img2 = Image.open("input/2/" + str(c) + ".png")
                            Img3 = Image.open("input/3/" + str(d) + ".png")
                            Img4 = Image.open("input/4/" + str(e) + ".png")
                            Img5 = Image.open("input/5/" + str(f) + ".png")
                            Img6 = Image.open("input/6/" + str(g) + ".png")

                            OutImg = ImgPaste(BgImg, Img1)
                            OutImg = ImgPaste(OutImg, Img2)
                            OutImg = ImgPaste(OutImg, Img3)
                            OutImg = ImgPaste(OutImg, Img4)
                            OutImg = ImgPaste(OutImg, Img5)
                            OutImg = ImgPaste(OutImg, Img6)
```
↑ネスト地獄になっていますが、実際に画像を読み込んで重ねています。

```py
trueorfalse = np.random.choice(['true', 'false'], p=[0.1, 0.9])
                            if(trueorfalse == 'true'):
                                OutImg.save("output/" + str(a) + "_" + str(b) + "_" + str(c) + "_" + str(d) + "_" + str(e) + "_" + str(f) + "_" + str(g) + ".png", quality=95)
                                print("saved")


                            print("output/" + str(a) + "_" + str(b) + "_" + str(c) + "_" + str(d) + "_" + str(e) + "_" + str(f) + "_" + str(g) + ".png")
```
↑画像を保存しています。また、すべての画像を保存するとpcがパンクしてしまうので今回は10%の確率で保存するようにしました。

<h2 id=anchor4>課題</h2>

プログラムの設計の問題で無駄な処理時間がかかってしまっているのを改善する。

<h2 id=anchor5>あとがき</h2>

参考
https://yu-nix.com/blog/2020/10/6/python-pillow-image-alpha-composite/
https://qiita.com/mimitaro/items/3506a444f325c6f980b2
https://note.com/miin_nft/n/n8bffd3ba3490
関連
https://twitter.com/CrazyDaifuku
https://twitter.com/YossiSuper