アバター自動生成に挑む(4)|インペイントで表情差分を生成

アバター自動生成に挑む(4)|インペイントで表情差分を生成 — アバター, インペイント, 表情差分 AI画像

こんにちは、パレイド思想部です。

前回はガチャシステムで、プロンプトで悩まずベース画像を選べる形を整えました。

今回は、1枚のベース画像からインペイントで表情差分を自動生成するパイプラインを構築します。

本記事はローカル LLM による自動執筆パイプラインで生成されました。現段階ではクラウド AI(Claude 等)の補助や人間の編集が介在していますが、pareido.jp では最終的に AI が自律的にコンテンツを制作できる仕組みの構築を目指しています。

「1枚では終われない」アバターの宿命

アバターが欲しい人にとって、ベース画像の生成はスタート地点。アバターとして使うには、瞬きや口の開閉、いわゆるリップシンク用のアニメーションパターンが必要です。喜怒哀楽のような表情も考えると、最低でも 感情別の表情 × 口の開閉(あいうえお) × 目の瞬き の組み合わせが必要です。

手描きのイラストレーターに依頼すれば、キャラクターの一貫性は保証されますが、差分1枚ごとに工数がかかります。気軽にできると思って画像生成 AI で試してみると、同じキャラクターなのに顔が微妙に変わる「別人問題」が発生し、AIの「創造性」が仇となります。人物や服装などを固定できるGeminiが脚光を浴びたのはこのためですね。

ここでは、Stable Diffusion系の生成AIから良く使われているインペイント(inpaint)を利用して、ベース画像の「一部だけ」を書き換えて差分を作るというアプローチを自動化してみます。

インペイント(画像の部分再生成)を使えば、顔の構造を保ったまま表情だけを変えられます。ただし、どの領域をどの程度書き換えるかの制御は繊細で、手動でやると1体分の差分生成に数時間かかります。パイプラインではこの工程を、マスク生成からリトライまで含めて全自動で処理します。

3フェーズパイプラインの全体像

今回のアバターの表情差分生成は、3つのフェーズに分けて段階的に行います。

Phase 1: ベース画像生成(txt2img)
    ↓ 顔検出・マスク生成
Phase 2: 感情表情のインペイント(顔全体)
    ↓ 6感情 × mouth closed
Phase 3: 口・目のバリアント生成(部分インペイント)
    ↓ mouth open + blink + viseme

なぜ一括でなく3段階か。顔全体を一度に変えようとすると、元のキャラクターの特徴が失われるためです。段階的にスコープを狭めることで、一貫性を保ちながら差分を作れます。

Phase 1: ベース画像とマスク生成

ガチャで選定したベース画像に対して、以下の4種類のマスクを生成します。

マスク名対象領域用途
expression_mask顔全体(眉〜口)Phase 2: 感情インペイント
mouth_mask口周辺Phase 3: 口開閉
eye_mask両目+眉Phase 3: 瞬き
head_mask頭部(首除く)レイヤー分解用

マスクは MediaPipe による顔検出を利用し、得られたランドマークから自動生成します(詳細は第5回で解説)。

今回はベース画像の生成にdreamshaperXLを利用しています。プロンプトへの追従性も高く、かなり安定した画像が得られます。解像度は1024×1024は欲しいところですが、512×512で生成して、あとでアップスケールする手法でもそれほど品質は変わりません。また、同じseedを利用することで品質が安定します。

dreamshaperXLで「1 Japanese girl」のみプロンプトで与えた例。背景がないほうが後処理はしやすい。

Phase 2: 感情表情のインペイント

6つの感情(neutral, happy, sad, angry, relaxed, surprised)それぞれの表情を、expression_mask 領域にインペイントします。neutral はベース画像をそのままコピー。残り5感情をインペイントで生成します。

EMOTION_EXPRESSIONS = {
    "neutral": "calm expression, neutral face, looking forward, mouth closed",
    "happy": "gentle smile, warm expression, slightly closed eyes, mouth closed in smile",
    "sad": "downcast eyes, slight frown, melancholy expression, mouth closed",
    "angry": "furrowed brows, intense gaze, serious expression, mouth closed tightly",
    "relaxed": "serene expression, half-closed eyes, peaceful face, mouth closed gently",
    "surprised": "wide eyes, raised eyebrows, startled look, mouth closed in surprise",
}

ここで重要なのが denoise 値です。インペイントの denoise は「元画像をどれだけ変えるか」を制御します。

  • denoise 0.3 — ほぼ元のまま(微調整レベル)
  • denoise 0.5 — 表情は変わるが顔の構造は保持
  • denoise 0.8 — 大きく変化(別人になるリスク)

denoise を弱くすると安定的ですが表情の変化が乏しくなり、逆に強くすると表情の変化が大きくなりますが全くの別人の顔になってしまう場合があります。

一律の解はなく、ここはトライ&エラーの世界ですが、さまざまなチェックポイントやプロンプトを試して平均的に安定する denoise 0.45 を採用しました。表情の変化を出しつつ、キャラクターの同一性を維持するバランスポイントです。

感情ごとの目の開閉のバリエーション。denoiseを抑えても、目を閉じたパターンは顔が結構変わってしまう。

Phase 3: 口・目のバリアント

Phase 2 で生成した各感情画像に対して、さらに部分インペイントを行います。
インペイントで生成したパーツの色が浮いてしまう場合は、色調を馴染ませる処理を入れると良いでしょう。

口開き(mouth open)

mouth_mask 領域を denoise 0.4 でインペイント。プロンプトで「口を開けた状態」を指定します。これについては、多くのチェックポイントで問題なく自然な画像が生成できました。

"mouth open, jaw dropped, parted lips, visible tongue"
口の開閉のパターン。ここだけ切り取ると違和感はないが、歯の形や見え方はかなり差が出るので全体でみる必要あり。

瞬き(blink)

eye_mask 領域を denoise 0.82 でインペイント。目を閉じた状態を生成します。

目のインペイントは denoise が高めです。目を閉じるという変化は「微調整」では表現できないため、ある程度強い書き換えが必要です。ただし、そのままだと背景が染み出す問題があるため、クロップ&ステッチ方式を採用しています。

1. 目の周辺だけを切り出し(crop)
2. 切り出した領域でインペイント
3. 結果を元画像に貼り戻し(stitch)

ここもマスク領域の調整がかなり難しく、自動化に苦労するポイントです。眉と目をセットでマスクする手法で、ある程度安定しました。

また、領域の特定ができても、目を閉じた画像はチェックポイント全般、学習データが少ないためか苦手としているようです。瞼が下から閉じたように目の位置が変わったり、目や眉が二重に生成される場合もあります。基本的にseedは揃えてバリエーションを生成しますが、再生成の場合は変えないと決定論的に同じ画像が出るため、近いパターンを探す必要が出てきます。

目を閉じたパターンはアイシャドウが濃く入る傾向。違和感が強い時は再生成。

ビゼム(viseme)

口の形を5種類(あ・い・う・え・お)で生成します。リップシンク用のバリアントです。6感情 × 5ビゼム = 30枚の追加生成になるため処理が重くなりますが、VOICEVOXなどリップシンクに対応したTTSと組み合わせると格段に自然な動作になります。

表情の変化とは独立して、口の部分の変化を共通で使い回すことも可能ですが、人形のような動作になりがちなので、このあたりはトレードオフです。また、歯や唇は生成のたびにイメージが変わってしまうことが多く、個別に何枚か「ガチャ」を引く覚悟は必要です。

表情が”neutral”だと、美是無も変化が少ない。
“surprise”だと変化が出やすい。厳密に「あいうえお」に見えるかというと微妙でも、動かすと違和感は少ない。

リトライと品質保証

各インペイントには品質チェッカーが走ります。

  • 色の一貫性チェック — マスク境界での色ずれを検出
  • 目の閉じチェック — blink フレームで目が実際に閉じているか
  • 目の位置チェック — 目の中心位置が不自然にずれていないか

品質チェックに失敗したら seed を +100 して再生成。最大20回リトライし、全失敗なら最良の結果を採用します。ここはチェックポイントやプロンプトによってはかなりの試行回数が必要だったり、ガチャを繰り返してもあたりが出ないことがあります。ガチャを繰り返してもあたりを引くのは難しいので、その場合はチェックポイントやプロンプトの変更が経験上はおすすめです。

生成結果

1体のアバターで、Phase 1〜3 を通じて最低でも約40回、チェックポイントにもよりますがリトライが多ければ桁が変わるぐらいの枚数を生成して「当たり」を引く必要があります。所要時間は GPU 性能次第ですが、Windows + RTX4070の環境でも1パターン10〜15分程度かかります。

最終的な出力は: – 6感情 × 口閉じ = 6枚 – 6感情 × 口開き = 6枚 – 6感情 × 瞬き = 6枚 – (オプション)6感情 × 5ビゼム = 30枚

合計 18〜48枚 のパーツが「スプライト」として自動生成されます。

42パターンの例。実際の利用シーンでは感情表現は偏りがちなので、よくあらわれるパターンを中心にチェックするとベター。

次回予告

次回は、Phase 1 で簡単に触れたマスク生成の詳細です。MediaPipe の68点ランドマークからポリゴン楕円でマスクを作り、フェザリングでインペイント境界を自然にする仕組みを掘り下げます。

コメント

タイトルとURLをコピーしました