[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -2,81 +2,221 @@
|
||||
id: wiki-2026-0508-일관된-캐릭터-및-스타일-구축
|
||||
title: 일관된 캐릭터 및 스타일 구축
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Consistent Character, Brand Consistency Maintenance, Character Sheet, Style Lock]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [ai, image-generation, character-consistency, lora, style]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: python
|
||||
framework: diffusers-flux
|
||||
---
|
||||
|
||||
# [[일관된 캐릭터 및 스타일 구축|일관된 캐릭터 및 스타일 구축]]
|
||||
# 일관된 캐릭터 및 스타일 구축
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
일관된 캐릭터 및 스타일 구축은 이미지 생성 시 특정 인물, 사물 또는 시각적 분위기를 여러 작업물에 걸쳐 동일하게 유지하는 프롬프트 작성 및 매개변수 제어 기술이다 [1, 2]. Midjourney나 Veo 3.1과 같은 도구는 참조 이미지 기능과 매개변수를 적극적으로 활용하여 피사체의 정체성과 미학을 고정할 수 있도록 지원한다 [2-4]. 반면, 이전 작업물의 직접적인 재사용이 시스템적으로 매우 어려운 DALL-E 3와 같은 모델에서는 몽타주 기법 등의 우회적인 프롬프트 전략이 요구된다 [5, 6].
|
||||
## 매 한 줄
|
||||
> **"매 character/style consistency 는 single shot 의 prompt 로 안 되며, multi-stack (LoRA + IP-Adapter + ControlNet + reference latents) 의 합으로만 stable 해진다"**. 2026 의 production character pipeline 은 character sheet → multi-view dataset → subject LoRA → generation-time stack → CLIP/face-similarity validation 의 매 5-step loop 로 운영됨. seed lock 만으로는 매 부족.
|
||||
|
||||
## 📖 Core 코어 Content
|
||||
* **Midjourney의 참조 매개변수(Reference Parameters) 활용:**
|
||||
* **캐릭터 참조 (Character Reference, `--cref`):** V6 모델부터 도입된 이 기능은 참조 이미지의 얼굴, 머리 모양 등 시각적 정체성을 여러 장면에 걸쳐 동일하게 유지하게 해준다 [7-9]. `--cw` (0~100) 매개변수를 조합하여 일치 강도를 조절할 수 있는데, 값이 0이면 얼굴에만 집중하고 100이면 의상과 헤어스타일까지 완벽하게 포함하여 유지한다 [1, 10].
|
||||
* **스타일 참조 (Style Reference, `--sref`):** 특정 이미지의 전반적인 분위기, 색상 팔레트, 질감을 새로운 생성물에 복제하여 적용하는 기능이다 [1, 2]. 여러 개의 이미지 URL을 띄어쓰기로 결합하여 고유한 미학적 톤을 만들 수 있으며, 브랜드 시각 자료나 소셜 미디어 피드의 일관성을 지키는 데 유용하다 [1, 3].
|
||||
* **옴니 참조 (Omni Reference, `--oref`):** V7 모델에서 새롭게 추가된 기능으로, 인물뿐만 아니라 커스텀 자동차나 장신구 등 특정 사물(Object)의 형태적 정체성까지 기억하여 다수의 프롬프트 환경에서 정확히 동일하게 유지해준다 [3, 7, 11].
|
||||
* 이러한 매개변수 없이 일관성을 꾀하려면, 핵심적인 스타일과 조명 묘사용 프롬프트 키워드들을 여러 생성 작업 간에 정확하게 반복해서 기입해야 한다 [12].
|
||||
## 매 핵심
|
||||
|
||||
* **DALL-E 3의 일관성 한계와 우회 프롬프트 전략:**
|
||||
* DALL-E 3는 한 번 생성한 캐릭터나 장면을 다음 생성에서 그대로 재사용하는 것이 거의 불가능하다는 구조적 약점이 있다 [5, 6].
|
||||
* 이를 극복하기 위해 동일한 프롬프트(단일 시드 기반) 내에서 한 캐릭터가 여러 상황에 있는 모습을 분할하여 묘사하는 우회법이 쓰인다. 프롬프트에 "왼쪽 위 모서리에...", "오른쪽 위 모서리에..." 와 같이 구역을 나눠 묘사하거나, "몽타주(montage)"라는 핵심 키워드를 입력하여 한 장의 이미지 안에 일관된 캐릭터의 다중 패널 장면을 얻어낼 수 있다 [5, 6].
|
||||
### 매 consistency 의 4 차원
|
||||
- **Identity**: 얼굴, 체형, 비율 (face/body).
|
||||
- **Outfit**: 의상 details, color, accessory.
|
||||
- **Style**: rendering, palette, line/shading.
|
||||
- **Pose/Expression**: 매 controllable variation.
|
||||
|
||||
* **Veo 3.1 비디오 생성 모델의 에셋 유지 기법:**
|
||||
* Google의 비디오 생성 모델인 Veo 3.1에서는 '비디오 재료(Ingredients to video)' 기능을 통해 장면, 캐릭터, 사물 또는 스타일의 참조 이미지를 입력하여 다중 샷 간의 미학을 일관되게 유지한다 [4]. 이 기능을 바탕으로 Gemini가 생성한 피사체 이미지를 결합하면, 완벽하게 일관된 캐릭터들이 대화를 나누는 복잡한 씬(Scene)도 구축할 수 있다 [13, 14].
|
||||
### 매 stack (2026 best)
|
||||
- **Subject LoRA**: 30-50 ref images, identity lock.
|
||||
- **Style LoRA**: separate, 매 stack 가능.
|
||||
- **IP-Adapter Face / FaceID**: face embedding.
|
||||
- **PuLID / Photomaker**: zero-shot face injection.
|
||||
- **InstantID**: identity + pose ControlNet.
|
||||
- **Reference-only ControlNet**: latent reference.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** Midjourney 매개변수, 이미지 참조(Image Prompts), [[프롬프트 엔지니어링|프롬프트 엔지니어링]]
|
||||
- **Projects/Contexts:** 스토리텔링 및 코믹북 캐릭터 디자인, 브랜드 시각 자료 및 소셜 미디어 캠페인 기획
|
||||
- **Contradictions/Notes:** Midjourney와 Veo 3.1은 전용 참조 매개변수(`--cref`, `--oref`)와 참조 에셋 투입 기능을 통해 캐릭터 및 스타일의 일관성 유지를 시스템 차원에서 강력히 지원한다 [3, 4, 7]. 이와 대조적으로 DALL-E 3는 생성된 피사체의 연속적인 재사용이 불가능하므로, 한 프롬프트 안에서 화면 분할을 묘사하는 기법에 의존해야 한다는 명확한 기능적 차이가 존재한다 [5, 6].
|
||||
### 매 응용
|
||||
1. Webtoon / illustrated novel 의 character series.
|
||||
2. Brand mascot 의 cross-channel reuse.
|
||||
3. Game NPC 의 procedural variation with identity.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-30*
|
||||
## 💻 패턴
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
### Character sheet (training data)
|
||||
```
|
||||
data/hero/
|
||||
├─ 01_front_neutral.png "<hero> front view, neutral expression"
|
||||
├─ 02_side_neutral.png "<hero> side profile, neutral"
|
||||
├─ 03_back.png "<hero> back view"
|
||||
├─ 04_3q_smile.png "<hero> 3/4 view, smiling"
|
||||
├─ 05_close_face.png "<hero> close-up portrait"
|
||||
├─ 06_full_body.png "<hero> full body, T-pose"
|
||||
├─ 07_action_run.png "<hero> running pose"
|
||||
...
|
||||
30+ images, varied pose/expression, consistent outfit
|
||||
```
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
### Subject LoRA + caption
|
||||
```python
|
||||
# Captions emphasize TRIGGER + variation, NOT outfit (so it's learned implicitly)
|
||||
captions = [
|
||||
"<hero01>, front view, neutral expression",
|
||||
"<hero01>, side profile",
|
||||
"<hero01>, smiling, 3/4 view",
|
||||
"<hero01>, in forest, full body",
|
||||
]
|
||||
# Train LoRA rank 32, 2000 steps, lr 1e-4, FLUX.1-dev
|
||||
```
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
### Multi-LoRA at inference
|
||||
```python
|
||||
from diffusers import FluxPipeline
|
||||
import torch
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
pipe = FluxPipeline.from_pretrained("black-forest-labs/FLUX.1-dev",
|
||||
torch_dtype=torch.bfloat16).to("cuda")
|
||||
pipe.load_lora_weights("./loras/hero01.safetensors", adapter_name="char")
|
||||
pipe.load_lora_weights("./loras/brand_style.safetensors", adapter_name="style")
|
||||
pipe.set_adapters(["char","style"], adapter_weights=[0.95, 0.7])
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
img = pipe(
|
||||
"<hero01>, drinking coffee in cafe, brand_style",
|
||||
num_inference_steps=28, guidance_scale=3.5,
|
||||
generator=torch.Generator("cuda").manual_seed(42)
|
||||
).images[0]
|
||||
```
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
### PuLID (zero-shot face lock)
|
||||
```python
|
||||
from pulid import PuLIDPipeline
|
||||
pl = PuLIDPipeline.from_pretrained("ByteDance/PuLID-FLUX")
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
img = pl.generate(
|
||||
prompt="<hero> hiking on mountain, golden hour",
|
||||
id_image="hero_face_ref.png",
|
||||
id_weight=0.85,
|
||||
seed=42, steps=20
|
||||
)
|
||||
# No training, single ref → identity preserved
|
||||
```
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
### InstantID (face + pose)
|
||||
```python
|
||||
from diffusers import StableDiffusionXLInstantIDPipeline, ControlNetModel
|
||||
controlnet = ControlNetModel.from_pretrained("InstantX/InstantID")
|
||||
pipe = StableDiffusionXLInstantIDPipeline.from_pretrained(
|
||||
"stabilityai/stable-diffusion-xl-base-1.0", controlnet=controlnet
|
||||
).to("cuda")
|
||||
pipe.load_ip_adapter_instantid("InstantX/InstantID")
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
face_emb = extract_face_embedding(ref_img)
|
||||
img = pipe(
|
||||
prompt="<hero> samurai in feudal japan",
|
||||
image_embeds=face_emb,
|
||||
image=pose_kps_img, # OpenPose keypoints
|
||||
controlnet_conditioning_scale=0.8,
|
||||
ip_adapter_scale=0.8,
|
||||
).images[0]
|
||||
```
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
### Reference image guidance (IP-Adapter)
|
||||
```python
|
||||
pipe.load_ip_adapter("h94/IP-Adapter", subfolder="sdxl_models",
|
||||
weight_name="ip-adapter_sdxl.bin")
|
||||
pipe.set_ip_adapter_scale(0.5)
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
img = pipe(
|
||||
prompt="<hero> sci-fi armor, cyberpunk city",
|
||||
ip_adapter_image=hero_reference_img,
|
||||
).images[0]
|
||||
```
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
### Validation: face similarity
|
||||
```python
|
||||
from insightface.app import FaceAnalysis
|
||||
import numpy as np
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
face = FaceAnalysis(name="buffalo_l"); face.prepare(ctx_id=0)
|
||||
ref_emb = face.get(ref_img)[0].embedding
|
||||
gen_emb = face.get(generated_img)[0].embedding
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
cos_sim = np.dot(ref_emb, gen_emb) / (np.linalg.norm(ref_emb)*np.linalg.norm(gen_emb))
|
||||
assert cos_sim > 0.55, f"identity drift: {cos_sim:.3f}"
|
||||
```
|
||||
|
||||
### Outfit consistency check (CLIP)
|
||||
```python
|
||||
import open_clip
|
||||
model, _, prep = open_clip.create_model_and_transforms("ViT-bigG-14")
|
||||
outfit_prompt = "white hoodie, black cargo pants, red sneakers"
|
||||
txt_emb = model.encode_text(open_clip.tokenize([outfit_prompt]))
|
||||
img_emb = model.encode_image(prep(generated).unsqueeze(0))
|
||||
score = torch.cosine_similarity(txt_emb, img_emb)
|
||||
# alert if score < 0.27
|
||||
```
|
||||
|
||||
### Generation-loop with retry
|
||||
```python
|
||||
def generate_consistent(prompt, max_retry=4):
|
||||
for i in range(max_retry):
|
||||
seed = 1000 + i*7
|
||||
img = pipe(prompt, generator=torch.Generator("cuda").manual_seed(seed)).images[0]
|
||||
sim = face_sim(img, ref_img)
|
||||
if sim > 0.55: return img, sim, seed
|
||||
raise RuntimeError("identity could not be preserved")
|
||||
```
|
||||
|
||||
### Style transfer for series
|
||||
```python
|
||||
# Step 1: generate composition with character locked
|
||||
base = pipe("<hero> sitting on bench", lora=char_lora).images[0]
|
||||
|
||||
# Step 2: img2img with style LoRA
|
||||
styled = i2i_pipe(
|
||||
prompt="<hero> sitting on bench, brand_style",
|
||||
image=base, strength=0.4,
|
||||
lora_stack=[char_lora, style_lora],
|
||||
).images[0]
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 30+ ref available | train subject LoRA |
|
||||
| 1-3 ref only | PuLID / Photomaker |
|
||||
| identity + exact pose | InstantID |
|
||||
| brand style 분리 | separate Style LoRA |
|
||||
| series of frames | seed lock + same LoRA stack |
|
||||
| validation gate | InsightFace cos > 0.55 |
|
||||
|
||||
**기본값**: subject LoRA + style LoRA + IP-Adapter face + face-sim CI.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[AI Image Generation]] · [[Character Design]]
|
||||
- 변형: [[LoRA Fine-tuning]] · [[InstantID]] · [[PuLID]]
|
||||
- 응용: [[인공지능 시각 언어 생성 (AI Visual Language Generation)]] · [[오픈소스 이미지 모델 미세 조정 및 배포]]
|
||||
- Adjacent: [[IP-Adapter]] · [[ControlNet]] · [[Brand Identity Generation]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: caption authoring for char dataset, prompt variation list, validation rubric.
|
||||
**언제 X**: face similarity scoring — deterministic insightface 가 정답.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Single ref overfit**: 1 image LoRA → mode collapse.
|
||||
- **Mixing identities in dataset**: 매 LoRA confused.
|
||||
- **Caption with outfit details**: outfit 이 trigger 와 분리 안 됨 → 매 outfit 변경 어려움.
|
||||
- **No validation**: drift 누적 unnoticed.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (PuLID paper 2024, InstantID Tencent 2024, IP-Adapter Tencent 2023, diffusers docs).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — character/style consistency multi-stack pipeline. |
|
||||
|
||||
Reference in New Issue
Block a user