【StableDiffusionのImg2Imgで桜を紅葉に変換してみた】

## はじめに
自分は24卒でWeb系の事業会社にフロントエンジニアとして入社する予定の大学生です。

普段ではReact×TypeScriptを利用したフロント周りの開発をメインで行なっています。現在は、内定者アルバイトでSREに入門しています。

今回は、AIによる画像生成ツールであるStableDiffusion-v1-5 img2img modelを使用して、既存の画像を新しい画像に変換するするための方法について紹介します。

## 忙しい人向け
解説なんていらないので、とりあえず画像変換がしたいという方は[ここをクリック](#プログラム全体)してください。
[※input画像をcolab上に配置する必要があります。](#前提)

## StableDiffusionについて

Stable Diffusionは「入力されたテキスト」をもとに画像を生成する「訓練済のAIモデル（Diffusion Model）」を搭載した画像生成AIで、作成したい画像のイメージ（例えば、車を運転する猫、サングラスをかけた猫、など）を英単語で区切って入力することで、様々な画像を作成できます。

今回は、よく見るText2Imgではなく、Img2Imgを試してみます。

## 環境

- Google Colab
- GPU T4

## 前提

- 画像(**sample.jpg**)を用意して、Google Colab上の任意の場所に移動してください。 

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1212014/9ecb85da-2245-096b-1978-cd7026f901eb.png" width="50%"/>


- Change runtime typeからRun timeをGPU T4にしてください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1212014/16ffda7c-b4f1-5e8f-c51e-2ac4563b2648.png" width="50%" />

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1212014/84b75807-dcea-5ede-5b19-23bcb896830f.png" width="50%" />

# Stable Diffusion Image-to-imageモデルについて

- ドキュメント：[Stable diffusion Image2image](https://huggingface.co/docs/diffusers/api/pipelines/stable_diffusion/img2img)

- [Stable Diffusion Online - AI Image Generator](https://stablediffusionweb.com/)

# Pythonのインストール済みパッケージ確認方法

インストール済みのパッケージとそのバージョンは、以下のコマンドで確認できます。

```python
!pip list
```

## サンプルプログラム解説

### 1. 必要なパッケージのインストール

以下のパッケージが必要です。エラーが発生した場合は、それぞれのパッケージをインストールしてください。

```python
!pip install diffusers transformers safetensors accelerate
```

```python
import matplotlib.pyplot as plt
import random
import torch
import pandas as pd
import openpyxl as op
import requests
from io import BytesIO
from PIL import Image
from datetime import datetime
from diffusers import StableDiffusionImg2ImgPipeline
```

### 2. StableDiffusionの初期化と画像生成のプロセス初期化

StableDiffusion[?](http://klab.kyoto-su.ac.jp/~wiki/?cmd=edit&page=StableDiffusion&refer=StableDiffusion-v1-5%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9FImg2Img)のImg2Imgパイプラインを以下のコードで初期化します。

```python
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float32,
    use_safetensors=True,
).to("cuda")
pipe.enable_attention_slicing()
```

### 3. メソッドの初期化

#### 画像の読み込み

```python
def load_and_resize_image(image_path):
   # 画像の読み込み
   image = Image.open(image_path).resize((1024, 512)).convert("RGB")
   return image
```

#### 画像変換

```python
def imgToImg(prompt, image_path):
   """
   * パラメータの初期化
   """
   # 推論ステップ数
   num_inference_steps = 100
   guidance_scale = random.uniform(12, 16)
   # ネガティブプロンプト
   n_prompt = "keep the architecture, EasyNegative, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, (worst quality:1.2), low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, lowres graffiti, (low quality lowres simple background:1.1),sketch, painting, cartoon, 3d, anime, drawing,ugly face, unclear eyes, bad mouth, same peoples,no change in buildings, no change in landscape, no change in scenery, no change in buildings"
   # 乱数生成のシード値を設定
   seed = random.randint(1, 1000000)
   # シード値を設定
   torch.manual_seed(seed)
   strength = 0.7

   # インプット画像の読み込み
   input_image = load_and_resize_image(image_path)

   # 例外処理
   if input_image is None:
       raise ValueError("インプット画像がありません。'./'に画像[サンプル1.png] or [サンプル2.png]が存在するか確認してください。")

   if input_image is None:
       # エラーハンドリング: input_imageがNoneの場合にエラーを処理する
       return None

   try:
       # 画像の生成
       edit_image = pipe(
           prompt,
           negative_prompt=n_prompt,
           image=input_image,
           num_inference_steps=num_inference_steps,
           strength=strength,
           guidance_scale=guidance_scale,
       ).images[0]

       # タイムスタンプを取得
       timestamp = datetime.now().strftime("%Y%m%d%H%M%S")

       # 画像の保存
       output_image_path = f"./output_{timestamp}.png"
       edit_image.save(output_image_path)

       # 入力画像と出力画像を表示
       plt.figure(figsize=(12, 6))
       plt.subplot(1, 2, 1)
       plt.imshow(input_image)
       plt.title("Input Image")
       plt.axis('off')

       plt.subplot(1, 2, 2)
       plt.imshow(edit_image)
       plt.title("Output Image")
       plt.axis('off')

       plt.show()

       # デバッグ用出力
       print(f"プロンプト: {prompt}")
       print(f"出力画像のパス: {output_image_path}")
       print(f"シード値: {seed}")
       print(f"推論ステップ数: {num_inference_steps}")
       print(f"ガイドスケール: {guidance_scale}")
       print(f"強度: {strength}")
       print("---")

       return output_image_path

   except Exception as e:
       print(e)
       return None
```

### 4. プログラムの実行

今回使用するプロンプトは、使った画像が桜の景色画像だったので、桜から紅葉に変換するようなプロンプト：`"Converting autumn leaves"`を指定しています。


```python
prompt = "Converting autumn leaves" #英語の方が精度いい
image_path = "/content/sample.jpg" # インプット画像を指定する

imgToImg(prompt, image_path)
```

### 実行結果

以下のように画像がいい感じの紅葉に画像が変換されました。

![スクリーンショット 2023-11-15 13.22.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1212014/ba4a2f0c-c79a-5a5a-584c-70b56e4d44d2.png)


# プログラム全体

```python
# 必要なパッケージのインストール
!pip install diffusers transformers safetensors accelerate

# パッケージのインポート
import matplotlib.pyplot as plt
import random
import torch
from PIL import Image
from datetime import datetime
from diffusers import StableDiffusionImg2ImgPipeline

# StableDiffusionのImg2Imgパイプラインの初期化
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float32,
    use_safetensors=True,
).to("cuda")
pipe.enable_attention_slicing()

# 画像の読み込みとリサイズの関数
def load_and_resize_image(image_path):
    image = Image.open(image_path).resize((1024, 512)).convert("RGB")
    return image

# 画像変換の関数
def imgToImg(prompt, image_path):
    num_inference_steps = 100
    guidance_scale = random.uniform(12, 16)
    n_prompt = "keep the architecture, EasyNegative, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, (worst quality:1.2), low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, lowres graffiti, (low quality lowres simple background:1.1),sketch, painting, cartoon, 3d, anime, drawing,ugly face, unclear eyes, bad mouth, same peoples,no change in buildings, no change in landscape, no change in scenery, no change in buildings"
    seed = random.randint(1, 1000000)
    torch.manual_seed(seed)
    strength = 0.7

    input_image = load_and_resize_image(image_path)
    if input_image is None:
        raise ValueError("インプット画像がありません。'./'に画像[サンプル1.png] or [サンプル2.png]が存在するか確認してください。")

    try:
        edit_image = pipe(
            prompt,
            negative_prompt=n_prompt,
            image=input_image,
            num_inference_steps=num_inference_steps,
            strength=strength,
            guidance_scale=guidance_scale,
        ).images[0]

        timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
        output_image_path = f"./output_{timestamp}.png"
        edit_image.save(output_image_path)

        plt.figure(figsize=(12, 6))
        plt.subplot(1, 2, 1)
        plt.imshow(input_image)
        plt.title("Input Image")
        plt.axis('off')

        plt.subplot(1, 2, 2)
        plt.imshow(edit_image)
        plt.title("Output Image")
        plt.axis('off')

        plt.show()

        print(f"プロンプト: {prompt}")
        print(f"出力画像のパス: {output_image_path}")
        print(f"シード値: {seed}")
        print(f"推論ステップ数: {num_inference_steps}")
        print(f"ガイドスケール: {guidance_scale}")
        print(f"強度: {strength}")
        print("---")

        return output_image_path

    except Exception as e:
        print(e)
        return None

# プログラムの実行
prompt = "Converting autumn leaves"
image_path = "/content/sample.jpg"

imgToImg(prompt, image_path)
```

## まとめ
【StableDiffusionのImg2Imgで桜を紅葉に変換してみた】の説明は終わりになります。
もしこの記事が参考になれば、Stable diffusionを触りたそうな人にぜひ送りつけてください。

この記事を読んだことがきっかけで画像生成AIに触れてみたなんてことを言ってくれる人がいたら、泣いて喜びます！
ここまでご覧いただきありがとうございました。


Kitsune🦊について

筆者（🦊）のTwitter : [@kitsune_yk](https://twitter.com/kitsune_yk)
筆者が代表として活動していた団体（あまてく）Twitter : [@amatech1006](https://twitter.com/amatech1006)

## 参考資料
https://aismiley.co.jp/ai_news/what-is-stable-diffusion/

https://huggingface.co/docs/diffusers/api/pipelines/stable_diffusion/img2img

https://stablediffusionweb.com/