这篇能做出什么
按下面流程走完,你会得到一套可复用的角色出图流水线,产出大概是这样:
- 同一个角色(同样的脸型、发型、发色、瞳色、服装主色)出现在 10~20 张不同场景、不同姿势、不同景别的图里,缩略图拼在一起能一眼认出来是同一个人;
- 单独崩掉的手、眼神、饰品,用局部重绘(inpainting)在不动整张图的前提下修掉;
- 一张 CSV 或 JSON 表驱动批量出图,每张图对应哪个种子、哪个场景、哪组参数都有记录,换电脑也能复现;
- 一套命名和归档规范,方便后续做角色资产库、分镜或电商素材。
核心思路只有一句:把"角色"和"场景"拆成两段,角色部分完全冻结,场景部分才允许变化。参考图负责兜住脸,局部重绘负责兜住细节,批量脚本负责兜住稳定。
前置条件清单
1. 一个能调用 FLUX 3 Image 的入口。可以是官方 API、官方在线画布,或者本地把权重跑在支持它的推理框架里(如 ComfyUI 一类带参考图与蒙版节点的前端)。具体模型名、权重来源、支持的输入字段,以官方文档当前版本为准。
2. 凭据:API Key 或账号登录态。写在环境变量里,不要硬编码进脚本。
3. 参考图 3~8 张:正面、半侧、侧面各一张,再加 1~2 张不同光照或不同表情的。要求同一人、分辨率接近、单人、居中、脸部清晰、背景尽量干净。
4. 角色契约卡:一段固定不变的描述文字,后面会给模板。
5. 基础工具:curl 或 Python 3.9+,一个能画蒙版的工具(任意图片编辑器都行,PS、GIMP、Krita、画图均可)。
6. 磁盘与命名规范:建议目录 character_a/raw、character_a/fixed、character_a/masks、character_a/logs。
7. 授权确认:用真人照片做参考时,确认有使用授权;商用场景尤其注意。
分步骤
步骤 1:先跑通一次最小调用
不要一上来就批量。先用一条命令确认鉴权、字段名、返回结构都对。
```bash
export FLUX_BASE_URL="你的服务地址"
export FLUX_API_KEY="你的密钥"
curl -sS -X POST "$FLUX_BASE_URL" \
-H "Authorization: Bearer $FLUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "a woman with shoulder-length black hair, round face, brown eyes, wearing a navy blue shirt, standing in a bookstore, soft daylight, medium shot",
"aspect_ratio": "3:4",
"seed": 123456,
"output_format": "png"
}' | head -c 800
```
字段名(prompt、seed、宽高比写法、返回里的图片字段)各平台写法不同,以官方文档当前版本为准。这一步的目标是拿到一张能保存下来的图,并且确认 seed 传进去有效——后面复现全靠它。
步骤 2:写一张"角色契约卡"
一致性差的头号原因不是模型,是提示词每次都重写。把不变量固化成一段文本,每次只动最后一段。
```text
【角色契约卡 · character_a】
主体:25 岁左右东亚女性,鹅蛋脸,下颌线柔和,鼻梁挺直,单眼皮,深棕色瞳色
发型:肩下 5 cm 直发,黑色,中分,发尾自然内扣
服装主色:藏青
常驻配饰:细金细项链
镜头:中景,平视,85mm 等效,浅景深
光照:柔和自然光,从画面左前方打入
画风:写实摄影,肤色自然,不过度磨皮
负面:多余手指、变形手部、模糊五官、双人、文字水印
```
然后每次出图只拼一段场景描述:
```python
CHARACTER = open("character_card.txt", encoding="utf-8").read()
scene = "站在旧书店木质书架前,手里拿着一本翻开的书,背景有暖黄色台灯"
prompt = f"{CHARACTER}\n【场景】{scene}"
negative = "多余手指、变形手部、模糊五官、双人、文字水印"
```
要点:契约卡里不要出现会变的形容词(比如"微笑"),那些放进场景段。改了契约卡就等于换了角色,要重新出全套。
步骤 3:用参考图把脸"锚住"
参考图的作用是提供契约卡描述不出来的细节:颧骨高度、眼距、发际线形状。调用时把参考图一起传进去,字段名可能是 image、reference_images 或 image_prompt,以官方文档为准。
```python
import os, requests, json
BASE = os.environ["FLUX_BASE_URL"]
KEY = os.environ["FLUX_API_KEY"]
def generate(prompt, ref_images, seed, ratio="3:4"):
payload = {
"prompt": prompt,
"aspect_ratio": ratio,
"seed": seed,
字段名以官方文档为准,这里是常见写法
"reference_images": ref_images,
"reference_strength": 0.65,
}
r = requests.post(
BASE,
headers={"Authorization": f"Bearer {KEY}"},
json=payload,
timeout=180,
)
r.raise_for_status()
return r.json()
refs = [
建议用 base64 或已上传后的资源 ID,两种方式哪个可用以官方文档为准
"ref_front.png",
"ref_half_side.png",
"ref_side.png",
]
print(generate("测试", refs, seed=123456))
```
参考强度(reference strength / image weight)怎么调:
- 偏高(例如 0.7~0.9):脸更像参考,但姿势、构图容易被带跑,画面发僵;
- 偏低(例如 0.3~0.5):姿势自由,但脸会慢慢漂移,出到第 8 张可能已经是另一个人;
- 实操做法:先用同一段 prompt 出一张 0.4、一张 0.6、一张 0.8,肉眼比对,选定一档后这一整套都不再改。
参考图本身也要挑:
- 三张以上、角度有差异,比一张高清正面照效果好;
- 参考图之间的光照尽量接近,否则模型要在矛盾信息里做取舍;
- 不要把带明显滤镜或美颜的图混进来;
- 参考图尺寸过大通常没必要,按官方建议的输入尺寸处理。
步骤 4:局部重绘修细节
整套图里总有几张"整体都对、手崩了"。这时候不要重新出图——重出会换脸。
流程:
1. 把原图拖进编辑器,在崩掉的手(或眼睛、耳环)上涂一块白色区域,导出成 PNG。
2. 蒙版比目标区域放大一圈,再把边缘羽化 5~15 像素,避免出现硬接缝。
3. 蒙版外的像素保持原样,提交局部重绘请求。
4. 重绘提示词只写局部,比如 一只自然放松的右手,五指分明,肤色与手臂一致,不要把整段契约卡再贴一遍——贴了容易让模型重画整个人。
```python
def inpaint(prompt, image_path, mask_path, seed):
payload = {
"prompt": prompt,
"image": image_path, # 原图,编码方式以官方文档为准
"mask": mask_path, # 白色 = 要重绘的区域
"seed": seed,
"mode": "inpaint",
}
r = requests.post(
BASE,
headers={"Authorization": f"Bearer {KEY}"},
json=payload,
timeout=180,
)
r.raise_for_status()
return r.json()
inpaint("一只自然放松的右手,五指分明", "raw/scene_03.png", "masks/hand_03.png", 123456)
```
三条经验:
- 一次只改一处。手修好了再看脸,不要在一个蒙版里塞三个目标。
- 重绘会消耗一批种子,把每次用的 seed 记下来,好结果要能复现。
- 修完的图另存到
fixed/,不要覆盖原图,方便对比和回退。
步骤 5:批量出图
到这一步,参数都定了,把变量抽成一张表:
```json
[
{"id": "s01", "scene": "在旧书店书架前,手拿翻开的书", "ratio": "3:4"},
{"id": "s02", "scene": "在雨天窗边,侧脸看向窗外", "ratio": "3:4"},
{"id": "s03", "scene": "在咖啡店吧台前,双手捧着纸杯", "ratio": "1:1"},
{"id": "s04", "scene": "在户外街角,逆光回眸", "ratio": "2:3"}
]
```
批量脚本要做四件事:限流、重试、断点续跑、落盘记录。
```python
import json, time, csv, os
from pathlib import Path
OUT = Path("character_a/raw"); OUT.mkdir(parents=True, exist_ok=True)
LOG = Path("character_a/logs/run.csv")
def run(tasks, seeds_per_task=2, sleep=2.0, retry=3):
done = set()
if LOG.exists():
with LOG.open(encoding="utf-8") as f:
done = {r["filename"] for r in csv.DictReader(f)}
write_header = not LOG.exists()
with LOG.open("a", encoding="utf-8", newline="") as f:
w = csv.writer(f)
if write_header:
w.writerow(["filename", "task_id", "scene", "seed", "ratio", "ref_strength"])
for t in tasks:
for i in range(seeds_per_task):
seed = 100000 + hash((t["id"], i)) % 900000
name = f"{t['id']}_{i:02d}_{seed}.png"
if name in done:
continue
prompt = f"{CHARACTER}\n【场景】{t['scene']}"
for attempt in range(retry):
try:
resp = generate(prompt, refs, seed=seed, ratio=t["ratio"])
save_image(resp, OUT / name) # 按返回结构自行解析
w.writerow([name, t["id"], t["scene"], seed, t["ratio"], 0.65])
f.flush()
break
except Exception as e:
wait = sleep * (2 ** attempt)
print(f"{name} 第 {attempt+1} 次失败:{e},等待 {wait}s")
time.sleep(wait)
else:
print(f"{name} 放弃")
time.sleep(sleep) # 简单限流,具体速率以官方文档为准
tasks = json.load(open("tasks.json", encoding="utf-8"))
run(tasks)
```
几点说明:
- 并发不要一上来就拉满。先串行跑 4 张,确认稳定再加并发;遇到 429 就退避重试。
- 每个场景至少出 2~3 个种子,再挑选,比死磕一个种子划算。
- 日志边写边 flush,中断后重跑会自动跳过已完成的文件。
步骤 6:验收与抽检
出一批图之后,先做一张"接触印相"(contact sheet):把 12 张缩略图缩小后拼成 3×4 一格,一眼就能看出哪几张脸开始漂。
逐图检查三层:
1. 脸部层:眼距、鼻型、脸宽是否和参考图对得上;
2. 细节层:手指数量与关节、耳朵、项链这类小物件;
3. 风格层:色调、锐度、景深是否和其他图统一。
建议做一个简单的打分表,方便回溯是哪组参数开始崩的:
```csv
filename,face,detail,style,note
s01_00_123456.png,4,4,5,可直接用
s02_01_778812.png,3,5,5,脸略窄,换种子重出
```
脸分低于 3 的,先别急着修局部——通常是参考强度或契约卡的问题,改完重出整张更省事。
常见坑与排错
脸越出越不像。 按顺序排查:参考图是不是只有一张正面?参考强度是不是偏低?契约卡里有没有被中途改过?每个场景是不是用了同一套参考图?
同一段提示词,两张图风格差很多。 多半是场景描述写太长、太文学化,压过了契约卡。把场景压到一句话,只保留"地点 + 动作 + 光线"。
局部重绘后出现色块接缝。 蒙版贴得太紧。把蒙版向外扩 5~15 像素并羽化边缘,重绘提示词里补一句肤色/光照要和周围一致。
重绘之后整个人变了。 说明重绘提示词里带了整体描述,或者蒙版面积过大(超过画面三成)。缩小蒙版,只保留"局部 + 一致性约束"的描述。
返回 429 或超时。 降低并发,加大请求间隔,重试用指数退避。别用固定间隔猛冲。
换台机器结果对不上。 种子、参考强度、宽高比、参考图文件都要一起带过去。参考图换了哪怕一张,结果就会变,这也是为什么要把它纳入版本管理。
批量跑到一半中断。 靠日志重跑,别从头再来。日志里没记录的文件,说明没成功落盘,重跑是安全的。
参考图涉及真人肖像。 有授权再用;没有的话,用生成的角色图作为参考图,同样能建立一致的角色。
下一步建议
1. 建立角色资产库:把每个角色的契约卡、参考图、已选种子、蒙版、参数版本收进一个目录,配一份 README。换人或交接时,直接复用。
2. 同一角色做多套服装:把"服装主色"从契约卡里挪到场景段,就能在不换脸的前提下换装,适合电商或分镜。
3. 多角色同框:先把两个角色各自单独跑稳,再尝试同框构图,蒙版分区域重绘会更好控。
4. 向视频延伸:图片阶段的角色一致性稳定后,再考虑首尾帧或图生视频,一致性问题的难度会明显上升。
5. 不要停止看官方文档:模型能力、支持字段、参考强度取值范围都在迭代,动手前花五分钟核对一遍当前版本的参数说明,比事后排查省时间。
