LoginSignup
0
3

More than 1 year has passed since last update.

ColabでControl Netをお試し 〜落書きも構図もボーンもpix2pix〜

Posted at

Control Netとは

論文: https://github.com/lllyasviel/ControlNet/raw/main/github_page/control.pdf

画像とテキストから新しい画像を生成するPix2Pixです。
Control Netの例
このように亀の落書きにturtleのpromptをつけるとクオリティの高い亀の絵が生成されます。

Control Netでは落書き以外にも
Canny Edge
image.png
Hough Line
image.png
HED Edge
image.png
Pose
image.png
(画像は論文より引用)
などから画像を生成することができます。
これらCanny Edgeなど画像はイラストや写真から変換することができるので、元の画像と同じ構図の画像を生成することができます。
Control Netの例

このControl NetはStable Diffusionをベースにされていますが、他のモデルにも適応させることが可能でAnythingV3などで線画から画像を生成することもできます。
AnythinV3ControlNet

Colabで試してみる

今回はこのリポジトリのgradio_scribble2imageをためして
落書きから画像生成をしてみます。

※Colabの無料枠でもギリギリいけました

まずランタイムからハードウェア アクセラレータをGPUにします。

先ほどのリポジトリをクローンし必要なパッケージをインストールします

!git clone https://github.com/lllyasviel/ControlNet
!pip install omegaconf einops pytorch_lightning transformers open_clip_torch gradio safetensors
%cd ./ControlNet

実行に必要なモデルなどをダウンロードしてきます

!wget https://huggingface.co/lllyasviel/ControlNet/resolve/main/models/control_sd15_scribble.pth -O ./models/control_sd15_scribble.pth  # 落書きモデル
!wget https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned.ckpt -O ./models/v1-5-pruned.ckpt
!wget https://github.com/lllyasviel/ControlNet/raw/main/models/cldm_v15.yaml -O ./models/cldm_v15.yaml

落書きモデルではなくて他のモデルを試したい時は、
https://huggingface.co/lllyasviel/ControlNet/tree/main/models
こちらから必要なモデルのリンクに一番上の

!wget https://huggingface.co/lllyasviel/ControlNet/resolve/main/models/control_sd15_scribble.pth -O ./models/control_sd15_scribble.pth  # 落書きモデル

の部分を変更してください。

/content/ControlNet/gradio_scribble2image.pyを実行したいのですが、gradioが含まれていて、そのまま実行してもうまくいかないので、その中身をそのままコピペして実行します。

from share import *
import config

import cv2
import einops
import gradio as gr
import numpy as np
import torch
import random

from pytorch_lightning import seed_everything
from annotator.util import resize_image, HWC3
from cldm.model import create_model, load_state_dict
from ldm.models.diffusion.ddim import DDIMSampler


model = create_model('./models/cldm_v15.yaml').cpu()
model.load_state_dict(load_state_dict('./models/control_sd15_scribble.pth', location='cuda'))
model = model.cuda()
ddim_sampler = DDIMSampler(model)


def process(input_image, prompt, a_prompt, n_prompt, num_samples, image_resolution, ddim_steps, scale, seed, eta):
    with torch.no_grad():
        img = resize_image(HWC3(input_image), image_resolution)
        H, W, C = img.shape

        detected_map = np.zeros_like(img, dtype=np.uint8)
        detected_map[np.min(img, axis=2) < 127] = 255

        control = torch.from_numpy(detected_map.copy()).float().cuda() / 255.0
        control = torch.stack([control for _ in range(num_samples)], dim=0)
        control = einops.rearrange(control, 'b h w c -> b c h w').clone()

        if seed == -1:
            seed = random.randint(0, 65535)
        seed_everything(seed)

        if config.save_memory:
            model.low_vram_shift(is_diffusing=False)

        cond = {"c_concat": [control], "c_crossattn": [model.get_learned_conditioning([prompt + ', ' + a_prompt] * num_samples)]}
        un_cond = {"c_concat": [control], "c_crossattn": [model.get_learned_conditioning([n_prompt] * num_samples)]}
        shape = (4, H // 8, W // 8)

        if config.save_memory:
            model.low_vram_shift(is_diffusing=True)

        samples, intermediates = ddim_sampler.sample(ddim_steps, num_samples,
                                                     shape, cond, verbose=False, eta=eta,
                                                     unconditional_guidance_scale=scale,
                                                     unconditional_conditioning=un_cond)

        if config.save_memory:
            model.low_vram_shift(is_diffusing=False)

        x_samples = model.decode_first_stage(samples)
        x_samples = (einops.rearrange(x_samples, 'b c h w -> b h w c') * 127.5 + 127.5).cpu().numpy().clip(0, 255).astype(np.uint8)

        results = [x_samples[i] for i in range(num_samples)]
    return [255 - detected_map] + results


block = gr.Blocks().queue()
with block:
    with gr.Row():
        gr.Markdown("## Control Stable Diffusion with Scribble Maps")
    with gr.Row():
        with gr.Column():
            input_image = gr.Image(source='upload', type="numpy")
            prompt = gr.Textbox(label="Prompt")
            run_button = gr.Button(label="Run")
            with gr.Accordion("Advanced options", open=False):
                num_samples = gr.Slider(label="Images", minimum=1, maximum=12, value=1, step=1)
                image_resolution = gr.Slider(label="Image Resolution", minimum=256, maximum=768, value=512, step=256)
                ddim_steps = gr.Slider(label="Steps", minimum=1, maximum=100, value=20, step=1)
                scale = gr.Slider(label="Guidance Scale", minimum=0.1, maximum=30.0, value=9.0, step=0.1)
                seed = gr.Slider(label="Seed", minimum=-1, maximum=2147483647, step=1, randomize=True)
                eta = gr.Number(label="eta (DDIM)", value=0.0)
                a_prompt = gr.Textbox(label="Added Prompt", value='best quality, extremely detailed')
                n_prompt = gr.Textbox(label="Negative Prompt",
                                      value='longbody, lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality')
        with gr.Column():
            result_gallery = gr.Gallery(label='Output', show_label=False, elem_id="gallery").style(grid=2, height='auto')
    ips = [input_image, prompt, a_prompt, n_prompt, num_samples, image_resolution, ddim_steps, scale, seed, eta]
    run_button.click(fn=process, inputs=ips, outputs=[result_gallery])


block.launch()

あとは落書きの画像をアップロードしてRUNをクリックで画像が生成されます。
これで絵心がなくてもこれで初音ミクとわかってもらえます。
スクリーンショット 2023-02-14 10.09.06.png

全体

宣伝

個人でいろいろなサービスを開発しています。

そういった記事を書いたりしたのでぜひよろしくお願いします。

最後に

Control Netはさまざま種類の加工画像から多くの画像生成モデルで画像を生成することができるpix2pixです。
なので、ダンス動画のボーンからアニメーションを作ったり、LoRaなどでファインチューニングさせた後で指定の構図の画像を生成したりと多くの使い道が考えられます。
余裕があったらそういったことも試してみたいです。

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3