Stable DiffusionのWeb APIを用いて写真的素材をイラストに変換してみた

[Supership](https://supership.jp/)の名畑です。TVアニメ[マッシュル-MASHLE-](https://mashle.pw/)の2期の[OP](https://www.youtube.com/watch?v=210R0ozmLwg)が海外でバズっているという噂は聞いていたけれど、公開一月足らずでYouTubeの動画が2000万再生を超えていてびっくりしました。

## はじめに

画像生成モデルである[Stable Diffusion](https://ja.stability.ai/stable-diffusion)ではテキストからの画像生成(**text-to-image**)だけではなく、画像を元にした画像生成(**image-to-image**)もございます。

今回の記事では**Python**で[stability.aiのAPI](https://api.stability.ai/docs)を呼び出すことで「**写真を元にしたイラスト生成**」を行なっています。

目新しい試みではないというか、私の過去記事「[Stable Diffusionでの同じ顔の複数画像生成をPythonとWeb APIで試みた記録](https://qiita.com/nabata/items/189344164c166b98a89a)」でも過去のモデルで似たことはやっているのですが、あれから半年以上経っているので改めてやってみようと思いました。

余談ですが、現時点において狙った構図の画像を生成するには、やはりなにかしらの元画像を用いるのが手間的な意味で良いのではないかと思っています。今後どうなっていくかはわかりませんが。

## 注意

- 元画像、生成画像共に実際の解像度は**1024x1024**なのですが、記事容量を抑えるために本記事では**512x512**に変更した上でアップロードしています
- Web APIは有料です。Web APIを用いずローカルで実行させたい場合は[stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui)等をご活用ください

## 元画像

今回は**Photoshop**の[生成塗りつぶし](https://helpx.adobe.com/jp/photoshop/using/generative-fill.html)で用意してみました。

![photoshop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/6c119707-7c76-2fab-f46c-bf76706ac409.png)

プロンプトに「**Young Japanese woman in a suit drinking coffee at a coffee shop**」と入れて生成した画像が以下です。訳すと「**喫茶店でコーヒーを飲んでいるスーツ姿の若い日本人女性**」です。

![init_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/6b03bde4-3b6f-2d6d-ccd7-226d42fa4c0a.png)

## コード

今回用いたPythonのコードは**下記**です。ここではコード内容について詳しくは触れませんので、興味がある方は[API reference](https://platform.stability.ai/docs/api-reference#tag/v1generation/operation/imageToImage)や過去記事「[Stable Diffusionでの画像生成をPythonとWeb APIで実装してみた記録](https://qiita.com/nabata/items/153ed75192004420c2e2)」をご覧ください。

```python
import base64
import os
import requests
import time  # ファイル名にタイムスタンプを入れるために使用

engine_id = "stable-diffusion-xl-1024-v1-0"  # SDXL 1.0

api_host = os.getenv('API_HOST', 'https://api.stability.ai')
api_key = os.getenv("STABILITY_API_KEY")  # 環境変数にAPIキーを保存済み

# API Keyの取得確認
if api_key is None:
    raise Exception("Missing Stability API key.")

# API呼び出し
response = requests.post(
    f"{api_host}/v1/generation/{engine_id}/image-to-image",
    headers={
        "Accept": "application/json",
        "Authorization": f"Bearer {api_key}"
    },
    files={
        "init_image": open("./init_img.png", "rb")
    },
    data={
        "text_prompts[0][text]": "Young Japanese woman in a suit drinking coffee at a coffee shop",
        "text_prompts[0][weight]": 1.0,
        "image_strength": 0.9,  # 元画像の強度
        "style_preset": "anime",  # スタイル
        "seed": 99999  # シード値
    },
)

# レスポンス確認
if response.status_code != 200:
    raise Exception("Non-200 response: " + str(response.text))

# レスポンス取得
data = response.json()

# 画像保存
for i, image in enumerate(data["artifacts"]):
    with open(f"./{engine_id}_{int(time.time())}_{i}.png", "wb") as f:
        f.write(base64.b64decode(image["base64"]))
```

元画像をそのまま画風だけ変更したいため、プロンプトには**Photoshop**に渡したものと同じ「**Young Japanese woman in a suit drinking coffee at a coffee shop**」を書きました。

**image\_strength**が元画像をどれだけ活かすかを示すパラメータ(**0〜1**)となります。**1**に近いほど元画像のままで、**0**に近いほどに元画像から離れていきます。
今回はこの値を**0**へと徐々に近づけて、どれだけ元画像を保ったまま画風が変わっていくかを記録に残します。

##  image\_strengthを変更しつつ生成した画像たち

### image\_strength = 0.7

![coffee_is_0_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/fc5e3c1e-017b-9ecd-cfb6-3b9c5b02f931.png)

### image\_strength = 0.5

![coffee_is_0_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/7502b95f-ecf7-910f-7240-eea612927d55.png)

### image\_strength = 0.3

![coffee_is_0_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/74497384-eae0-64f5-9352-1706b3ca9ac6.png)

### image\_strength = 0.1

![coffee_is_0_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/2be576b0-d939-1f3c-5fd3-3072a83f5dd5.png)

### image\_strength = 0.01

![coffee_is_0_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/e1faeb0a-ea20-4398-35b6-443943f1abf6.png)

**0.7**、**0.5**あたりは元画像とそれほど差がないように感じられるかもしれませんが、並べて見るとやっぱり違います。

**0.3**あたりが最も「**元画像の構図を残しつつ画風が変わった**」と言える感じでしょうか。
胸のコサージュ的なものが見栄えに悪影響を及ぼしていますが。


## プロンプトを変えてみた

画風をさらに変更するため、プロンプトを以下のように変えてました。
「**moe**」を重み**0.3**として追加しています。

```python
"text_prompts[0][text]": "Young Japanese woman in a suit drinking coffee at a coffee shop",
"text_prompts[0][weight]": 0.7,
"text_prompts[1][text]": "moe",
"text_prompts[1][weight]": 0.3,
```

**0**に近づくほどに画風が変わっていることがわかると思います。

### image\_strength = 0.7

![coffee_moe_is_0_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/abbd0830-e653-b9d7-ca36-13f14749944a.png)

### image\_strength = 0.5

![coffee_moe_is_0_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/6ddcbe2c-8080-6609-e72e-7dab3938436f.png)

### image\_strength = 0.3

![coffee_moe_is_0_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/6e85d681-4b9d-3a07-afd3-881890e00380.png)

### image\_strength = 0.1

![coffee_moe_is_0_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/22fd70c2-7361-bc65-c0ad-3cbabe838055.png)

### image\_strength = 0.01

![coffee_moe_is_0_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/866611e6-087e-2b6a-9a58-1ac3d3d9877d.png)

## 二つを並べてみた

比較をしやすくするため、結果をすべて並べてみました。変化が明らかです。

| strength |  moe有り  |  moe無し  |
| --- | --- | --- |
| 1.0(元) | ![init_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/6b03bde4-3b6f-2d6d-ccd7-226d42fa4c0a.png) | ![init_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/6b03bde4-3b6f-2d6d-ccd7-226d42fa4c0a.png) |
| 0.7 | ![coffee_moe_is_0_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/abbd0830-e653-b9d7-ca36-13f14749944a.png) | ![coffee_is_0_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/fc5e3c1e-017b-9ecd-cfb6-3b9c5b02f931.png) |
| 0.5 |  ![coffee_moe_is_0_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/6ddcbe2c-8080-6609-e72e-7dab3938436f.png)  |  ![coffee_is_0_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/7502b95f-ecf7-910f-7240-eea612927d55.png)  |
| 0.3 |  ![coffee_moe_is_0_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/6e85d681-4b9d-3a07-afd3-881890e00380.png)  |  ![coffee_is_0_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/74497384-eae0-64f5-9352-1706b3ca9ac6.png)  |
| 0.1 |  ![coffee_moe_is_0_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/22fd70c2-7361-bc65-c0ad-3cbabe838055.png)  |  ![coffee_is_0_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/2be576b0-d939-1f3c-5fd3-3072a83f5dd5.png)  |
| 0.01 |  ![coffee_moe_is_0_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/866611e6-087e-2b6a-9a58-1ac3d3d9877d.png)  |  ![coffee_is_0_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/e1faeb0a-ea20-4398-35b6-443943f1abf6.png)  |

## 余談 生成塗りつぶし

AIで生成した画像はどうしても部分的におかしな箇所が発生することが多いです。

たとえば今回生成した画像も、左腕に対して左手の位置がおかしいです。

![coffee_is_0_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/74497384-eae0-64f5-9352-1706b3ca9ac6.png)


これはコサージュが手として変換されてしまったからですね。

こういった場合の修正方法は色々と考えられますが、今回使った**Photoshop**の**生成塗りつぶし**でさくっとできますので、今更感ありつつご紹介まで。

![photoshop2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/cd8e8ba7-0a7b-f106-8555-a5e0021bef46.png)

違和感のある部分を選択して、プロンプトとしてなにも入れずに**生成**を押します。

これだけで以下のように該当箇所だけをAIで再生成した絵が出力できます。

![coffee_is_0_3_new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/99d7b69c-af97-0111-59de-301f1cfe8670.png)

さらに同じ要領でちょっといじってみたのが以下です。

![coffee_is_0_3_new_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/5f8b4cad-f1f0-b34f-024d-845170b932c3.png)

不自然さが0ではないですが、最初よりはかなり良くなったと思います。

## 余談2 生成拡張

選んだ箇所を拡張する[生成拡張](https://helpx.adobe.com/jp/photoshop/using/generative-expand.html)という機能もあります。
せっかくなのでこちらもご紹介しておきます。

![photoshop3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/456b16e4-0de5-de05-47b7-00b66ff3d1dd.png)

まず、切り抜きツールで拡張する範囲を選択します。

そしてプロンプトを入力せずに**生成**を押します。

![coffee_is_0_3_new_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/13c9dbac-ac9a-0e00-491c-1584da5f37e6.png)

本当にすごい時代になりました。

## 最後に

面白かったです。
元画像ありきの画像生成はもっと色々と試していきたい。

## 宣伝

[SupershipのQiita Organization](https://qiita.com/organizations/supership-inc)を合わせてご覧いただけますと嬉しいです。他のメンバーの記事も多数あります。

Supershipではプロダクト開発やサービス開発に関わる方を絶賛募集しております。
興味がある方は[Supership株式会社 採用サイト](https://supership.jp/recruit/)よりご確認ください。