226 lines
7.9 KiB
Markdown
226 lines
7.9 KiB
Markdown
---
|
|
id: wiki-2026-0508-해부학적-오류-디버깅-워크플로우
|
|
title: 해부학적 오류 디버깅 워크플로우
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [Anatomy Error Debugging, Anatomy Fix Workflow]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.9
|
|
verification_status: applied
|
|
tags: [image-generation, stable-diffusion, flux, controlnet, inpainting, workflow]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: python
|
|
framework: comfyui
|
|
---
|
|
|
|
# 해부학적 오류 디버깅 워크플로우
|
|
|
|
## 매 한 줄
|
|
> **"매 anatomy 깨진 region 의 의 isolate → controlnet pose 의 enforce → low-denoise inpaint 의 surgical fix"**. 매 2026 image-gen 의 anatomy artifact (extra finger, fused limb, broken hand, twisted neck) 의 의 매 entire image 의 regenerate 의 X — 매 mask + ControlNet (OpenPose / DWPose / DensePose) + low-strength img2img 의 combine 의 의 fix 한 이후 매 surrounding pixel 의 preserve.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 common anatomy failure
|
|
- **Hand**: 매 6 finger / 4 finger / fused / extra thumb — 매 most common.
|
|
- **Limb**: 매 missing arm / 3 leg / asymmetric.
|
|
- **Face**: 매 misaligned eye / 3 eye / merged feature.
|
|
- **Joint**: 매 inverted knee / impossible bend.
|
|
- **Topology**: 매 long neck / floating head / mid-body merge.
|
|
|
|
### 매 fix strategy ladder (cheap → expensive)
|
|
- **Step 0 — Prevent**: better prompt + negative + LoRA (RealHands, GoodHands).
|
|
- **Step 1 — Detail upscale**: face/hand detailer (ADetailer, FaceDetailer node).
|
|
- **Step 2 — Mask + inpaint**: 매 region only 의 redraw, denoise 0.4-0.6.
|
|
- **Step 3 — ControlNet pose**: 매 OpenPose skeleton 의 enforce — 매 limb count 의 lock.
|
|
- **Step 4 — Reference + IP-Adapter**: 매 good-anatomy reference 의 inject.
|
|
- **Step 5 — Manual sketch + ControlNet Scribble**: 매 hand-drawn skeleton overlay.
|
|
- **Step 6 — External tool (Photoshop Generative Fill, Krita AI)**: 매 brush-driven local edit.
|
|
|
|
### 매 응용
|
|
1. Portrait commission post-processing.
|
|
2. Comic / manga panel correction.
|
|
3. Product mockup hand fix.
|
|
4. Concept art iteration.
|
|
5. Batch dataset cleanup (매 1000 image 의 anatomy QC).
|
|
|
|
## 💻 패턴
|
|
|
|
### Prompt-level prevention
|
|
```text
|
|
Positive: "detailed hands, anatomically correct, five fingers, perfect anatomy"
|
|
Negative: "extra fingers, fused fingers, six fingers, missing fingers, deformed hand,
|
|
mutated, extra limb, malformed, bad anatomy, twisted, asymmetric"
|
|
LoRA: <lora:GoodHands-beta2:0.7>
|
|
```
|
|
|
|
### ComfyUI — automated hand detailer
|
|
```python
|
|
# pseudo-graph (ComfyUI workflow JSON)
|
|
# 1. Generate base image (FLUX.1-dev or SDXL)
|
|
# 2. UltralyticsDetectorProvider("hand_yolov8n.pt") → bbox of hands
|
|
# 3. SAMSegment → precise mask
|
|
# 4. DetailerForEach:
|
|
# - guide_size: 512, max_size: 768
|
|
# - denoise: 0.5
|
|
# - cfg: 7.0
|
|
# - prompt: "perfect hand, five fingers, detailed"
|
|
# 5. Composite back into original
|
|
```
|
|
|
|
### Manual mask + inpaint (Diffusers)
|
|
```python
|
|
from diffusers import StableDiffusionXLInpaintPipeline
|
|
import torch
|
|
from PIL import Image
|
|
|
|
pipe = StableDiffusionXLInpaintPipeline.from_pretrained(
|
|
"stabilityai/stable-diffusion-xl-base-1.0",
|
|
torch_dtype=torch.float16
|
|
).to("cuda")
|
|
|
|
img = Image.open("broken_hand.png")
|
|
mask = Image.open("hand_mask.png") # white = inpaint, black = keep
|
|
|
|
fixed = pipe(
|
|
prompt="perfect human hand, five fingers, detailed knuckles, anatomically correct",
|
|
negative_prompt="extra fingers, fused fingers, deformed",
|
|
image=img,
|
|
mask_image=mask,
|
|
strength=0.55, # 매 low denoise — 매 surrounding 의 preserve
|
|
num_inference_steps=30,
|
|
guidance_scale=7.5
|
|
).images[0]
|
|
```
|
|
|
|
### ControlNet OpenPose enforcement
|
|
```python
|
|
from diffusers import StableDiffusionXLControlNetInpaintPipeline, ControlNetModel
|
|
from controlnet_aux import OpenposeDetector
|
|
|
|
pose_detector = OpenposeDetector.from_pretrained("lllyasviel/Annotators")
|
|
controlnet = ControlNetModel.from_pretrained(
|
|
"thibaud/controlnet-openpose-sdxl-1.0", torch_dtype=torch.float16
|
|
)
|
|
|
|
# 매 reference image (good pose) 의 의 pose extract
|
|
pose_map = pose_detector(reference_img, hand_and_face=True)
|
|
|
|
pipe = StableDiffusionXLControlNetInpaintPipeline.from_pretrained(
|
|
"stabilityai/stable-diffusion-xl-base-1.0",
|
|
controlnet=controlnet, torch_dtype=torch.float16
|
|
).to("cuda")
|
|
|
|
fixed = pipe(
|
|
prompt=prompt, image=img, mask_image=mask,
|
|
control_image=pose_map,
|
|
controlnet_conditioning_scale=0.8,
|
|
strength=0.6
|
|
).images[0]
|
|
```
|
|
|
|
### IP-Adapter reference injection
|
|
```python
|
|
from diffusers import StableDiffusionXLPipeline
|
|
pipe.load_ip_adapter("h94/IP-Adapter", subfolder="sdxl_models",
|
|
weight_name="ip-adapter-plus_sdxl_vit-h.safetensors")
|
|
pipe.set_ip_adapter_scale(0.6)
|
|
|
|
reference = Image.open("good_anatomy_ref.png")
|
|
fixed = pipe(prompt=prompt, ip_adapter_image=reference, ...).images[0]
|
|
```
|
|
|
|
### YOLO-based hand detection mask
|
|
```python
|
|
from ultralytics import YOLO
|
|
import numpy as np
|
|
import cv2
|
|
|
|
model = YOLO('hand_yolov8n.pt')
|
|
results = model(img_np)
|
|
|
|
mask = np.zeros(img_np.shape[:2], dtype=np.uint8)
|
|
for box in results[0].boxes.xyxy:
|
|
x1, y1, x2, y2 = map(int, box)
|
|
# pad 의 inpaint context 의 give
|
|
pad = 20
|
|
mask[max(0,y1-pad):y2+pad, max(0,x1-pad):x2+pad] = 255
|
|
|
|
cv2.imwrite("hand_mask.png", mask)
|
|
```
|
|
|
|
### FLUX.1 Fill (2026 native inpaint)
|
|
```python
|
|
from diffusers import FluxFillPipeline
|
|
pipe = FluxFillPipeline.from_pretrained(
|
|
"black-forest-labs/FLUX.1-Fill-dev",
|
|
torch_dtype=torch.bfloat16
|
|
).to("cuda")
|
|
|
|
fixed = pipe(
|
|
prompt="perfect anatomically correct hand",
|
|
image=img, mask_image=mask,
|
|
height=1024, width=1024,
|
|
guidance_scale=30, # 매 FLUX 의 high CFG OK
|
|
num_inference_steps=50
|
|
).images[0]
|
|
```
|
|
|
|
### Batch anatomy QC pipeline
|
|
```python
|
|
def qc_pipeline(image_paths):
|
|
for p in image_paths:
|
|
img = Image.open(p)
|
|
# 1. detect anatomy issues
|
|
issues = anatomy_classifier(img) # custom CLIP-based or YOLO
|
|
if not issues: continue
|
|
# 2. mask offending region
|
|
mask = build_mask(img, issues)
|
|
# 3. inpaint with ControlNet pose
|
|
fixed = controlnet_inpaint(img, mask, pose_from_ref(img))
|
|
fixed.save(p.replace('.png', '_fixed.png'))
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Approach |
|
|
|---|---|
|
|
| Single hand artifact | ADetailer / FaceDetailer node |
|
|
| Pose 의 corrupt | ControlNet OpenPose + inpaint |
|
|
| 매 specific style 의 reference | IP-Adapter + low denoise |
|
|
| 매 fine detail (eye, finger) | Mask + denoise 0.3-0.5 |
|
|
| 매 entire pose 의 wrong | Re-generate with ControlNet from start |
|
|
| FLUX-based pipeline | FLUX.1 Fill native |
|
|
|
|
**기본값**: ADetailer (auto) + ControlNet OpenPose (manual fallback) + 0.5 denoise.
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[Image-Generation]] · [[Inpainting]]
|
|
- 변형: [[Outpainting]] · [[Img2Img]] · [[Region-Prompting]]
|
|
- 응용: [[Stable Diffusion]] · [[FLUX]] · [[ComfyUI-Workflow]]
|
|
- Adjacent: [[ControlNet]] · [[IP-Adapter]] · [[ADetailer]] · [[LoRA]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: 매 prompt rewrite (anatomy negative 의 expand); 매 ComfyUI graph 의 LLM 의 emit; 매 batch QC 의 caption-based filter.
|
|
**언제 X**: 매 actual pixel 의 fix 의 X — 매 image model 의 job. LLM 의 의 graph orchestrate 만.
|
|
|
|
## ❌ 안티패턴
|
|
- **High denoise (>0.8)**: 매 surrounding 의 destroy — 매 seam 의 visible.
|
|
- **No mask padding**: 매 hard edge — context 의 lose.
|
|
- **Re-roll only**: 매 매 same prompt 의 의 broken anatomy 의 re-generate — 매 root cause 의 X fix.
|
|
- **Negative prompt overload**: 매 negative 의 50 token — model 의 confuse.
|
|
- **No ControlNet on bad pose**: 매 inpaint alone 의 의 같은 pose 의 same fail 의 재생산.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (Diffusers docs 0.30+; ComfyUI ADetailer extension; FLUX.1 Fill model card; Civitai workflows).
|
|
- 신뢰도 A.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — ADetailer + ControlNet OpenPose + FLUX.1 Fill patterns 추가 |
|