Supershipの名畑です。現在放送中のスキップとローファーの美津未、原作で新刊を読む度に2週間は引きずる宝石の国のフォス、もうすぐ特別編が劇場公開される響け! ユーフォニアムの久美子。私が好きな作品にいつもその声があったなあと思います。ご結婚おめでとうございます。
はじめに
「Stable Diffusionでの画像生成をPythonとWeb APIで実装してみた記録」「Stable Diffusionにおける同一人物の別表情生成をPythonとWeb APIで試みた記録」と、Stable Diffusionでの画像生成を記事にしてきました。
前回は画像内の人物の表情を変えることを試みましたが、今回は同じ人物を用いた別画像の生成を試みます。要は同じ顔でたくさん画像を作ろうとしたというものです。
過去の記事同様generation APIの基本機能の範疇で挑みます。
元となる画像を用意
Stable DiffusionのAPIでは、学習もできないため、狙った構図の生成はかなり難しいと感じています。まあ、当然であろうとは思いつつ。
ですので「最終的に作成したい画像に近い画像」を用意した上で加工していくのが現実的と考えています。どこまで近しくできるかはコスト見合いですが(容易に近似な画像を用意できるならAIを使う必要はなくなるわけですし)。流行りのControlNetも構図指定のためには、なんらかの元画像を用いるようですかね。
私は絵を描くのはかなり苦手ですので、写真素材を元にした方が狙った構図の画像を生成しやすいのではと考えました。
極端な話、自分自身を写真に撮ってそれを加工するという手もとれるのではないかと。
今回は、手間を省くため、まずStable Diffusionで写真風の女性画像を5枚生成しました。
これをすべて同一な顔にすることを試みます。
コードは下記です。ほぼ過去記事のままですが、text_promptsにrealisticを追加し、style_presetはphotographicとしています。
import base64
import os
import requests
import time
engine_id = "stable-diffusion-xl-beta-v2-2-2"
# engine_id = "stable-diffusion-v1"
api_host = os.getenv('API_HOST', 'https://api.stability.ai')
api_key = os.getenv("STABILITY_API_KEY")
# API Keyの取得確認
if api_key is None:
raise Exception("Missing Stability API key.")
# API呼び出し
response = requests.post(
f"{api_host}/v1/generation/{engine_id}/text-to-image",
headers={
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": f"Bearer {api_key}"
},
json={
"text_prompts": [
{
"text": "28-year-old-japanese-woman with black bobbed hair, realistic",
"weight": 1.0
},
{
"text": "text, letter, belongings",
"weight": -1.0
},
],
"style_preset": "photographic",
"samples": 5,
"width": 512,
"height": 512,
},
)
# レスポンス確認
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"]))
生成された画像は下記の5枚。
雑コラを作る
同じ顔の画像を生成したいのであれば、同じ顔を貼り付ければいいのではないか。
そんな安易な考えが浮かびました。
ということで、前の記事で生成した下記の画像を使います。
ちなみに顔部分だけをくり抜くのはrembgを用いました。背景を取り除いて人物や動物だけを残してくれるライブラリです。
$ pip install rembg
Collecting rembg
Downloading rembg-2.0.43-py3-none-any.whl (25 kB)
Collecting scipy
Downloading scipy-1.10.1-cp310-cp310-
以下略
$ rembg i origin_img.png output_img.png
こちらの顔を生成済み画像にぺたぺたと貼っていきます。ここは人力でやりました。
元画像 | 雑コラ画像 |
---|---|
あまりに雑すぎますが、まあ、今回は実験なのでよしとします。
雑コラを自然にしてみる
まず、あまりにひどい雑コラ具合を軽減させましょう。
生成済みのコラ画像を元としてimage-to-imageで別画像を生成します。
先述のコードのrequests.postのみ変えています。
image_strengthは0.7として、元画像を強めに残しています。それとstyle_presetをphotographicとしています。
また、ここから先のコードではseedで同一の値を指定することにします。
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]": "28-year-old-japanese-woman with black bobbed hair, realistic",
"text_prompts[0][weight]": 1.0,
"image_strength": 0.7,
"style_preset": "photographic",
"seed": 99999
},
)
結果は下記です。左が元として使った雑コラ画像で、右がAPI経由で生成された画像です。
元が雑すぎて一部画像は特に首回りが不自然に思えますが、全体的に、かなり自然になりはしたでしょうか。コラが顔の向きとかもガン無視なので不自然さが残るのはやむなしですかね。
元画像 | 生成画像 |
---|---|
こうやって並べると気になるところもありますが、なんの前提知識もなしにこの生成画像5枚を「これ、田中さん(仮名)っていう人の写真だよ」と見せられたなら、田中さんを被写体とした5枚の写真として普通に受け入れてしまう気はします。4枚目だけ髪が長いから撮影時期が違うのかもしれないと思いつつ。
だって、現実に撮影した写真でも、いわゆる奇跡の1枚じゃないですが、同一人物だってわからないものが珍しくはないですし。
イラスト風にしてみる
せっかくなので写真風ではなくイラスト風にしてみます。
これらの画像を元として、今度はimage_strengthを0.5、style_presetをanimeとして画像を生成しました。プロンプトからrealisticを削除しています。
変更箇所はdataのみです。
data={
"text_prompts[0][text]": "28-year-old-japanese-woman with black bobbed hair",
"text_prompts[0][weight]": 1.0,
"image_strength": 0.5,
"style_preset": "anime",
"seed": 99999
},
結果は下記です。
まったくもって同じ顔ではないですが、ある程度は近しいのではないかとも思います。
元画像 | 生成画像 |
---|---|
絵柄を軽くしてみる
moe illustrationを指定してみました。moeがそもそも通じるのか不明ではありますが。
data={
"text_prompts[0][text]": "moe illustration",
"text_prompts[0][weight]": 1.0,
"image_strength": 0.4,
"style_preset": "anime",
"seed": 99999
},
結果は下記です。
工程を経すぎてよくわからなくなってきました。同じ顔のイラストを複数生成するという目的からは遠ざかりましたが、軽い絵柄にはなりましたかね。
元画像 | 生成画像 |
---|---|
最後に
丁寧にやればある程度はコントロールできそうだなとは感じました。
まあ、Stable Diffusionを使うメリットみたいなものは薄い方法だなとは思いつつですが。
ただただ楽しんでいます。
宣伝
SupershipのQiita Organizationを合わせてご覧いただけますと嬉しいです。他のメンバーの記事も多数あります。
Supershipではプロダクト開発やサービス開発に関わる方を絶賛募集しております。
興味がある方はSupership株式会社 採用サイトよりご確認ください。