部分修正・合成・後修正の自動化 — CC1向け ComfyUI 実装リファレンス
InpaintはStable Diffusionの潜在空間(latent)上でマスク領域のみを再生成する技術です。ComfyUIでは主にMasked Latent方式とFull Latent方式の2種が使われます。
| 方式 | 動作原理 | 特徴・向いている用途 | ComfyUIノード |
|---|---|---|---|
| Masked Latent | 各ステップでマスク外のlatentを元の値で上書き | 文脈保持が強い / キャラ崩れを防ぐ / CC1の通常用途はこれ | SetLatentNoiseMask + VAEEncodeForInpaint |
| Full Latent | 全latentを処理(保護なし) | グローバル整合性が高い / 大幅な構図変更向き / 変化量が大きい | 標準VAEEncode + latent noise |
| 専用Inpaintモデル (5ch) | マスク情報をUNetに直接入力(5チャンネル) | 境界が最も自然 / 単体で高品質 | CheckpointLoaderSimple(inpaint用checkpoint) |
| 汎用モデル + Fooocus patch | SDXLチェックポイントにパッチ適用 | LoRAとの互換性が高い / waiIllustriousSDXL_v160で動作確認済み | InpaintModelConditioning(Acly製) |
SetLatentNoiseMaskノードはマスクをlatentに適用し、VAE Encode for Inpaintingと組み合わせることでMasked Latent方式を実現します。grow_mask_by = 6-8px(推奨値7)を設定することで、境界のブレンドが自然になりR18の肌・髪のつなぎ目が目立ちません。[1]
Soft Inpaintingはグラデーションマスクを使用してper-pixel denoiseスケジュールを適用する最新手法です。一般的なマスク方式より境界が最も自然になります。ComfyUI Managerから「Differential Diffusion」を検索してインストール可能です。[2]
| ノード | 重要設定項目 | 推奨値 |
|---|---|---|
VAEEncodeForInpaint |
grow_mask_by | 6〜8(標準7) |
KSampler |
steps | 25〜30 |
| cfg | 6.0〜7.0 | |
| sampler_name | dpmpp_2m | |
| scheduler | karras | |
| denoise | 用途により0.25〜0.90(第5章参照) |
| FaceDetailer設定項目 | 推奨値 | 説明 |
|---|---|---|
| dilation | 10〜15 | 顔の周囲のバッファ(px) |
| denoise | 0.35〜0.45 | 軽微修正は0.35、顔崩れは0.45 |
| guide_size | 512 | 顔の処理解像度 |
| steps | 20 | サンプリングステップ(速度優先) |
| cfg | 6.0 | waiIllustriousSDXL_v160 準拠 |
| 手法 | 精度 | 速度 | 適用場面 |
|---|---|---|---|
| SAM2 + GroundingDINO | ★★★★★ 最高 | 中 | R18部位特定・顔・手・背景 |
| GroundingDINO単独 | ★★★★ | 速 | 大まかな物体検出 |
| 色閾値マスク (PIL) | ★★★ | 最速 | 髪色修正・背景単色 |
| 手動マスク | ★★ | 遅 | 非標準形状・最終手段 |
テキストクエリ例: "face", "hand", "background", "hair", "body"。R18部位は英語の解剖学用語が有効。
| ノード | 設定 | 効果 |
|---|---|---|
| Mask Blur (GaussianBlur) | kernel_size=5〜10, sigma=1.0 | エッジ軟化・境界自然化 |
| Grow Mask | expand=6〜8px | マスク境界を外側に拡張 |
| Erode Mask | expand=-3px | 過度な拡張を縮小 |
| モデル | サイズ | 方式 | 強み | CC1向け優先度 |
|---|---|---|---|---|
| inpaint_v26.fooocus.patch | 1.32GB | SDXL patch | 品質最高・汎用checkpointに適用可・LoRA互換 | ★★★★★ 第1推奨 |
| fooocus_lama.safetensors | — | 事前充填 | 背景除去・物体消去が得意 | ★★★★ 背景修正に使用 |
| MAT (Mask-Aware Transformer) | — | Transformer | テクスチャ境界の自然な補完 | ★★★★ 自然背景向け |
| SDXL Inpaint専用ckpt | 6.5GB+ | 5ch UNet | シームレスな境界・単体で高品質 | ★★★ LoRA未対応の場合 |
| 汎用 + VAEEncodeForInpaint | 既存 | 擬似inpaint | 追加モデル不要・すぐ試せる | ★★★ テスト用途 |
https://huggingface.co/lllyasviel/fooocus_inpaintComfyUI\models\inpaint\ に配置[6]
ANNO InpaintingワークフローはSDXL/Pony/Illustrious全対応でタイルアップスケーラー内蔵が便利。Tensor.Art からワークフローJSONをダウンロードして ComfyUI に読み込み可能。[7]
| 用途 | denoise値 | grow_mask | steps | 備考 |
|---|---|---|---|---|
| 顔修正 (軽微・肌荒れ等) | 0.30〜0.35 | 6px | 20 | 同一人物感を最大限維持 |
| 顔修正 (目・輪郭改善) | 0.40〜0.45 | 8px | 25 | FaceDetailerのデフォルト推奨値 |
| 顔修正 (崩れ再生成) | 0.50〜0.60 | 10px | 30 | Fooocus patch使用を推奨 |
| 手の修正 (指形状) | 0.45〜0.55 | 8px | 25 | "perfect fingers, five fingers" プロンプト必須 |
| 局所色修正 | 0.25〜0.35 | 4px | 15 | 形状を変えず色だけ変える |
| 髪色化け修正 | 0.28〜0.35 | 6px | 15 | 髪色タグを(blonde hair:1.5)で強制 |
| 衣装修正 (皺・パターン) | 0.45〜0.55 | 8px | 25 | 衣装タグを継承 |
| 背景修正 (軽微) | 0.50〜0.60 | 10px | 25 | 違和感・不自然なライン修正 |
| 背景再生成 (大幅変更) | 0.65〜0.75 | 15px | 30 | LaMa事前充填を推奨 |
| 物体消去 | 0.70〜0.80 | 15px | 30 | LaMa + "simple background" プロンプト |
| 全体再構成 | 0.80〜0.90 | 20px | 35 | img2imgに近い。キャラ崩れリスクあり |
| Tile Upscale仕上げ | 0.40〜0.50 | 0px | 20 | ControlNet Tile併用時の標準値 |
| Outpainting (新領域) | 0.85〜0.95 | — | 30 | ImagePadForOutpaint使用時 |
| ImagePadForOutpaint設定 | 右方向 (next panel) | 下方向 (continuation) |
|---|---|---|
| right | 512〜768px | 0px |
| bottom | 0px | 512〜768px |
| left / top | 0px | 0px |
| feathering | 40〜50px | 40〜50px |
| denoise (KSampler) | 0.90 | 0.92 |
| steps | 30 | 30 |
| cfg | 6.0 | 6.0 |
(blonde hair:1.4), blue eyes, white dress + 元の画像と同じNEGプロンプトfeatheringを60以上にすると境界がぼやけすぎるため40-50を標準とします。境界の直線的なラインが目立つ場合はfeathering値を5刻みで調整し、キャラが途切れる場合はdenoiseを0.03刻みで下げます。[9]
Flux.1モデルを使用する場合はIC-LoRAガイダンスを併用することでシームレス性がさらに向上します(guidance_scale=3.5前後)。ただしCC1の現行環境(waiIllustriousSDXL_v160)では上記SDXL設定で十分な品質が得られます。[10]
| 処理種別 | 実装手段 | 主要設定 | DLsite/FANZA適合 |
|---|---|---|---|
| Gaussian Blur (全体) | PIL ImageFilter | radius=15〜25 | 審査要 (ぼかし不可の場合あり) |
| モザイク (ピクセレート) | PIL resize縮小→拡大 | block_size=10〜15 | OK (生殖器完全被覆必須) |
| 部位特定モザイク | SAM2マスク + composite | block_size=12 | OK (最も確実) |
| ComfyUI ImageBlur | ノード内処理 | blur_radius=20 | 条件付きOK |
from PIL import Image, ImageFilter
import numpy as np
def pixelate_region(img: Image.Image, mask: Image.Image,
block_size: int = 12) -> Image.Image:
"""SAM2マスク領域のみモザイク処理"""
w, h = img.size
# 縮小→拡大でピクセレート
small = img.resize(
(max(1, w // block_size), max(1, h // block_size)),
Image.BOX
)
pixelated = small.resize((w, h), Image.NEAREST)
# マスク領域のみ合成
result = Image.composite(pixelated, img, mask)
return result
def apply_blur_region(img: Image.Image, mask: Image.Image,
radius: int = 20) -> Image.Image:
"""マスク領域にGaussian Blur適用"""
blurred = img.filter(ImageFilter.GaussianBlur(radius=radius))
return Image.composite(blurred, img, mask)
DLsite/FANZA規格ではモザイクによる生殖器の完全被覆が必須です。block_size=12〜15が実務標準です。モザイクを適用した画像には品質ゲート確認(目視)を必ず実施してください。[11]
プロンプトに perfect fingers, five fingers, detailed hand, natural hand を追加。
| 修正パターン | denoise | 追加プロンプト | 注意点 |
|---|---|---|---|
| 顔崩れ (軽微) | 0.35〜0.40 | beautiful face, perfect eyes | FaceDetailerで自動化 |
| 顔崩れ (再生成) | 0.50〜0.60 | detailed face, youthful | Fooocus patch使用推奨 |
| 手崩れ | 0.45〜0.55 | five fingers, perfect hand | HandDetailer (ImpactPack) |
| 色修正のみ | 0.25〜0.35 | 目的の色タグを強調 | 形状を維持したい場合は低め |
| 髪色化け修正 | 0.28〜0.35 | (blonde hair:1.5) 等 | 化け色を NEG に追加 |
| 背景物体消去 | 0.70〜0.80 | simple background | LaMa事前充填を必ず使用 |
| 局部再生成 (R18) | 0.55〜0.65 | 部位特化タグ | 品質ゲート通過後に量産 |
| アクセサリ追加/削除 | 0.35〜0.45 | 対象アクセサリのタグ | 眼鏡・リボン等 |
D:\projects\fanza3_mass\inpaint_batch\ ├── input\ # 修正対象画像 (*.png) ├── output\ # 修正済み出力 ├── masks\ # SAM2生成マスク (キャッシュ) ├── errors\ # OOM・失敗した画像 ├── done.json # 処理済みリスト (resume用) └── batch_log.jsonl # コスト・進捗ログ
import json, uuid, requests, websocket, pathlib, time
from pathlib import Path
from tqdm import tqdm
SERVER = "127.0.0.1:8188"
INPUT_DIR = Path(r"D:\projects\fanza3_mass\inpaint_batch\input")
OUTPUT_DIR = Path(r"D:\projects\fanza3_mass\inpaint_batch\output")
DONE_FILE = Path(r"D:\projects\fanza3_mass\inpaint_batch\done.json")
def queue_inpaint(wf_template, image_path, mask_path, client_id):
wf = json.loads(json.dumps(wf_template))
# ノードID は実際のワークフローJSONに合わせて変更
wf["10"]["inputs"]["image"] = str(image_path) # Load Image
wf["11"]["inputs"]["image"] = str(mask_path) # Load Mask
wf["3"]["inputs"]["seed"] = int(uuid.uuid4()) % 2**32
r = requests.post(f"http://{SERVER}/prompt",
json={"prompt": wf, "client_id": client_id})
return r.json()["prompt_id"]
def wait_done(ws_conn, prompt_id, timeout=300):
ws_conn.settimeout(timeout)
while True:
msg = json.loads(ws_conn.recv())
if msg["type"] == "executing":
if msg["data"].get("node") is None:
if msg["data"]["prompt_id"] == prompt_id:
return True # 完了
def free_vram():
requests.get(f"http://{SERVER}/free",
params={"unload_models": "true", "free_memory": "true"})
def batch_run():
done = json.loads(DONE_FILE.read_text()) if DONE_FILE.exists() else []
wf_template = json.loads(Path("inpaint_wf.json").read_text())
client_id = str(uuid.uuid4())
ws = websocket.WebSocket()
ws.connect(f"ws://{SERVER}/ws?clientId={client_id}")
images = sorted(INPUT_DIR.glob("*.png"))
for i, img_path in enumerate(tqdm(images)):
if str(img_path) in done: continue
mask_path = Path("masks") / img_path.name
for retry in range(3): # OOM自動リトライ
try:
pid = queue_inpaint(wf_template, img_path, mask_path, client_id)
wait_done(ws, pid)
done.append(str(img_path))
break
except Exception as e:
if retry == 2:
(Path("errors") / img_path.name).touch()
if i % 50 == 0:
free_vram() # 50枚毎にVRAM解放
DONE_FILE.write_text(json.dumps(done))
ws.close()
| 処理条件 | 推定時間 (RTX3090Ti) |
|---|---|
| 100枚 / denoise=0.40 / steps=25 | 25〜35分 |
| 100枚 / denoise=0.55 / steps=30 (FaceDetailer込み) | 40〜55分 |
| 100枚 / ControlNet Tile + Inpaint | 60〜90分 |
| 設定項目 | 推奨値 | 説明 |
|---|---|---|
| ControlNet モデル | tile_xl_v1.1 または controlnet-tile-sdxl |
SDXL向け Tile ControlNet |
| strength (ControlNet) | 0.50〜0.70 (標準 0.60) |
高すぎると色変化・低すぎると効果なし |
| start_percent | 0.0 | 最初から適用 |
| end_percent | 1.0 | 最後まで適用 |
| tile_size | 1024px | 24GB VRAM でのOOM回避 |
| overlap | 128px | タイル境界のブレンド幅 |
| denoise (KSampler) | 0.40〜0.50 (標準 0.42) |
Tile処理での詳細生成 |
| cfg | 6.0 | waiIllustriousSDXL_v160 準拠 |
| steps | 20 | 速度優先(品質重視なら25) |
Tile ControlNet処理後に色調が変化することがあります。Image Color Match ノードを後段に追加し、元画像の色調を参照させることで原因を解消できます。[13]
| モデル | 特徴 | CC1での用途 |
|---|---|---|
| 4x-UltraSharp | シャープ・ディテール重視 | DLsite/Booth高解像度サムネ |
| RealESRGAN_x4plus_anime_6B | アニメ特化・ノイズ除去 | R18漫画の解像度向上 |
| 4x_NMKD-Siax_200k | バランス型 | 汎用 |
| 落とし穴 | 症状 | 対策 |
|---|---|---|
| 1. denoise=1.0 使用 | 周囲を無視した完全ランダム生成 | 0.90以上は全体再構成のみ |
| 2. grow_mask_by=0 | 境界に直線ラインが残る | 必ず6-8pxを設定 |
| 3. Fooocus patch未設定 | 汎用VAE Encodeで品質が低い | 3ファイルをmodels/inpaint/に配置 |
| 4. mature/adult NEG削除 | 顔修正後におばさん顔に変化 | 全inpaintでNEGプロンプト継承必須 |
| 5. FaceDetailerのguide_size不足 | 顔が小さすぎて修正効果なし | guide_size=512〜768に設定 |
| 6. マスクの精度不足 | 不要な部位まで変更される | SAM2+GroundingDINOで自動生成 |
| 7. Tile ControlNet強度0.9超 | 色調が大幅に変化 | strength=0.5-0.7 + Color Match |
| 8. バッチ処理でVRAM管理なし | 50枚超でOOMクラッシュ | 50枚毎に/free APIを呼び出す |
| 9. Outpaintのfeathering過大 | 境界がぼやけすぎる | feathering=40-50px |
| 10. モザイク後に目視確認省略 | 被覆不完全でDLsite/FANZA否認 | 品質ゲートの目視チェック必須 |
| 期間 | タスク | 完了KPI |
|---|---|---|
| Day 1-3 | Fooocus patch 3ファイル配置 / FaceDetailer導入 / smoke 5枚確認 | 顔修正成功率 80%以上 |
| Day 4-7 | SAM2 + GroundingDINO インストール / マスク自動生成テスト | 自動マスク精度 SAM2で確認 |
| Day 8-14 | denoise最適値テーブルを実際の画像で検証 / バッチスクリプト初版 | 20枚バッチ自動修正成功 |
| Day 15-21 | ControlNet Tile 超解像フロー構築 / モザイク自動化スクリプト | 1024→2048品質向上を目視確認 |
| Day 22-30 | 100枚バッチInpaint全自動化 / 既存量産パイプラインに統合 | 100枚30分以内の自動修正完成 |