第 19/60 天
引言
一篇漫画是否”好看”,很大程度上取决于分镜(Storyboard)与页面布局(Panel Layout)。同样的台词和情节,格子怎么切、镜头怎么给、留白怎么安排,直接决定了读者的阅读节奏与情绪张力。然而,对于单打独斗的 AI 漫剧创作者来说,最耗时的往往不是”生成画面”,而是”把画面组织成一页书”:一格一格手动排版、反复调整比例、拼接出血线……几个小时就过去了。
好消息是,分镜恰恰是 AI 最容易”结构化”的环节。漫画分镜本质上是一套可量化的规则系统:页数、格子数量、格子比例、阅读顺序(Z 字形)、重点格子(Splash Panel)的放大规则——这些都能用脚本和模型自动化。本文将从”分镜的底层逻辑”讲起,手把手带你搭建一套 AI 辅助的分镜自动化流水线:用 LLM 生成分镜脚本 JSON → 用 Python 切割与排版画布 → 用 Stable Diffusion / ComfyUI 逐格生成 → 自动拼合为成品页面。
核心概念
1. 漫画页面布局的基本规则
漫画阅读顺序在东亚地区通常为从右到左、从上到下(日漫标准),欧美为从左到右。无论哪种,页面布局都遵循几条”铁律”:
| 规则 | 说明 | 违反的后果 |
|---|---|---|
| 格子数量控制 | 常规页 4~8 格,动作页可少、对话页可多 | 太密难读,太疏浪费篇幅 |
| 重点格放大 | 每 1~2 页安排一个重点格(Splash / 大格) | 失去视觉锚点,节奏平淡 |
| 视线引导 | 相邻格子按阅读顺序自然衔接,避免”跳格” | 读者走神、读错顺序 |
| 留白与出血 | 页边出血位(Blend)至少 3~5mm,内部留白均匀 | 印刷裁切后内容被切掉 |
| 网格对齐 | 格子边线尽量落在统一的网格线上 | 页面显得杂乱、廉价 |
AI 辅助布局的价值,就是把上面这些”经验值”转换成参数与约束,交给脚本强制执行,从而把人类的精力解放给创意本身。
2. 分镜自动化的三层架构
一个完整的 AI 分镜自动化流水线通常分为三层:
┌─────────────────────────────────────────────────┐
│ 第 1 层:结构与脚本层(LLM) │
│ → 剧本/文戏 → 分镜脚本 JSON(格数、景别、对白) │
├─────────────────────────────────────────────────┤
│ 第 2 层:布局与画布层(Python/规则引擎) │
│ → JSON → 页面网格坐标(绝对定位 + 阅读顺序) │
├─────────────────────────────────────────────────┤
│ 第 3 层:生成与拼合层(SD/ComfyUI + 后处理) │
│ → 逐格出图 → 按蒙版/区域生成 → 拼图 + 气泡位 │
└─────────────────────────────────────────────────┘
第 1 层负责”想”,第 2 层负责”排”,第 3 层负责”画”。每一层都可以独立升级——比如你把第 3 层的模型从 SD 1.5 换成 SDXL,流水线骨架完全不用动。
3. 关键术语速查
- Panel(格子):漫画页面上的一个画面单元。
- Gutter(格沟):格子之间的空白间隔,通常 2~4mm。
- Splash Panel(跨页/整页大格):占据整页或大半页的重点画面。
- Bleed(出血):印刷时超出裁切线的部分,AI 生成时建议扩 5%~8%。
- Camera/Shot(景别):远景(LS)、中景(MS)、特写(CU)等,是分镜脚本的核心字段。
- Reading Order(阅读顺序):格子编号,决定读者视线路径,也是拼图时重排的依据。
实战步骤
第一步:环境准备
分镜自动化需要 Python 3.10+、Pillow 和 OpenAI 兼容的 LLM 接口(本地 Ollama 或云端 API 均可):
# 创建独立虚拟环境(避免污染系统 Python)
python3 -m venv ~/manga-pipeline
source ~/manga-pipeline/bin/activate
# 核心依赖:图像处理 + HTTP 请求 + 提示词渲染
pip install pillow requests jinja2 pyyaml
# 可选:调用本地 LLM 完成"文戏 → 分镜脚本"转换
# (只需 OpenAI 兼容接口,Ollama 亦可用)
curl -fsSL https://ollama.com/install.sh | sh
ollama pull qwen2.5:14b # 中文能力较强的本地模型
# 验证
python -c "from PIL import Image; print('Pillow OK')"
第二步:用 LLM 生成分镜脚本 JSON
把剧本片段喂给大模型,让它输出结构化分镜 JSON。关键是给出明确的字段约束(scene、shot、panel 数量、文本框内容),这样后续脚本才能直接消费。
{
"page": 3,
"title": "雨夜追凶",
"layout": "6-panel",
"reading_order": "rtl",
"panels": [
{
"id": 1,
"shot": "LS",
"subject": "主角站在天桥,雨幕中望向远方的霓虹",
"text": "",
"grid": {"row": 1, "col": 1, "rowspan": 1, "colspan": 2}
},
{
"id": 2,
"shot": "CU",
"subject": "主角紧握的拳头,雨水顺指缝滑落",
"text": "……果然还是追过来了。",
"grid": {"row": 1, "col": 3, "rowspan": 2, "colspan": 1}
},
{
"id": 3,
"shot": "MS",
"subject": "反派从巷口现身,风衣被风掀起",
"text": "你逃不掉的。",
"grid": {"row": 2, "col": 1, "rowspan": 1, "colspan": 2}
}
]
}
实际调用时,把上面的 JSON Schema 作为 response_format 或 few-shot 示例放进 prompt:
import json
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
SCHEMA = """输出 JSON,字段:
page:int, title:str, layout:str,
panels: [{id:int, shot:LS|MS|CU|ECU, subject:str, text:str,
grid:{row, col, rowspan, colspan}}]"""
script = "第三话开篇:雨夜,主角在天桥被反派截住……"
resp = client.chat.completions.create(
model="qwen2.5:14b",
messages=[
{"role": "system", "content": "你是资深漫画分镜师,只输出合法 JSON。"},
{"role": "user", "content": f"{SCHEMA}nn请为以下文戏设计一页 6 格分镜:n{script}"},
],
temperature=0.7,
)
storyboard = json.loads(resp.choices[0].message.content)
print(f"生成 {len(storyboard['panels'])} 个分镜格,布局:{storyboard['layout']}")
第三步:Python 规则引擎——把 JSON 变成画布坐标
分镜 JSON 里的 grid 只是”相对网格”,要真正出图,必须换算成像素级的绝对坐标。下面这个脚本会把 6 格布局渲染成带编号的布局预览,并输出每格的裁切区域(给后续逐格生成使用):
from PIL import Image, ImageDraw, ImageFont
def grid_to_boxes(page_w, page_h, panels, gutter=40):
"""根据 grid 网格信息计算每格 (x1, y1, x2, y2) 区域,返回按阅读顺序排列的列表"""
# 网格列:从布局中推导最大行列
cols = max(p["grid"]["col"] + p["grid"]["colspan"] - 1 for p in panels)
rows = max(p["grid"]["row"] + p["grid"]["rowspan"] - 1 for p in panels)
col_w = (page_w - gutter * (cols + 1)) / cols
row_h = (page_h - gutter * (rows + 1)) / rows
boxes = []
for p in sorted(panels, key=lambda x: x["id"]):
g = p["grid"]
x1 = gutter + (g["col"] - 1) * (col_w + gutter)
y1 = gutter + (g["row"] - 1) * (row_h + gutter)
x2 = x1 + col_w * g["colspan"] + gutter * (g["colspan"] - 1)
y2 = y1 + row_h * g["rowspan"] + gutter * (g["rowspan"] - 1)
boxes.append({"id": p["id"], "box": (x1, y1, x2, y2), "meta": p})
return boxes
# 预览 800x1200 的 A4 比例页面
canvas = Image.new("RGB", (800, 1200), "white")
draw = ImageDraw.Draw(canvas)
for b in boxes_for_page:
x1, y1, x2, y2 = b["box"]
draw.rectangle([x1, y1, x2, y2], outline="black", width=4)
draw.text((x1 + 10, y1 + 10), str(b["id"]), fill="red")
canvas.save("/tmp/layout_preview.png")
print("布局预览已保存:/tmp/layout_preview.png")
第四步:ComfyUI 节点式逐格生成
有了每格的坐标和 subject,下一步就是逐格出图。推荐用 ComfyUI 搭一个”分镜批处理”工作流:KSampler → VAE Decode → 按区域保存。关键节点配置用 YAML 表达(对应 ComfyUI 的 API 格式——每个节点是一个 dict):
# storyboard_workflow.yaml — ComfyUI API 格式(节选)
3: # KSampler 节点
class_type: "KSampler"
inputs:
seed: 42
steps: 28
cfg: 7.0
sampler_name: "dpmpp_2m"
scheduler: "karras"
denoise: 0.85 # 配合 img2img 保持角色一致
model: ["4", 0]
positive: ["6", 0]
negative: ["7", 0]
latent_image: ["10", 0]
6:
class_type: "CLIPTextEncode"
inputs:
text: "" # 每格动态注入:shot + subject 渲染的提示词(见第五步)
clip: ["4", 1]
组合一套负向提示词模板,避免漫画中最常见的翻车:
negative: "blurry, lowres, bad anatomy, bad hands,
extra fingers, watermark, text, ugly, deformed,
photorealistic, 3d render, jpeg artifacts"
第五步:提示词模板渲染 + 批量生成循环
用 Jinja2 把 shot + subject 渲染成稳定的正向提示词,然后循环调用 ComfyUI 的 /prompt API。分镜自动化的核心技巧:每格共享同一段”风格前缀”,只替换画面主体——这是保证整页风格统一的关键:
import requests, json
from jinja2 import Template
STYLE = "black and white manga page, high contrast, screentone, clean lineart"
TPL = Template("""{{ style }}, {{ shot_desc }}, {{ subject }}, {{ extra | default('') }}""")
def build_prompt(panel, shot_map=None):
shot_map = shot_map or {"LS": "wide shot", "MS": "medium shot",
"CU": "close-up", "ECU": "extreme close-up"}
return TPL.render(style=STYLE,
shot_desc=shot_map[panel["shot"]],
subject=panel["subject"])
# 循环逐格提交 ComfyUI
wf = json.load(open("/tmp/storyboard_workflow.json"))
for panel in storyboard["panels"]:
panel_id = panel["id"]
positive, negative = build_prompt(panel), "blurry,bad anatomy,bad hands,watermark"
# 将提示词注入工作流 JSON 的对应节点
wf["6"]["inputs"]["text"] = positive
wf["7"]["inputs"]["text"] = negative
resp = requests.post("http://127.0.0.1:8188/prompt",
json={"prompt": wf, "client_id": f"panel-{panel_id}"})
print(f"Panel {panel_id}: {resp.status_code} -> {resp.json().get('prompt_id')}")
time.sleep(3) # 节流,避免队列过载
第六步:拼版与出稿
所有格子生成完毕后,按第三步的坐标把图片裁剪并粘贴回画布,自动加上格沟(Gutter)与文本框占位(后续再接第 18 天讲的文字处理流程):
# 一键执行完整流水线(从分镜 JSON 到成品页面)
python manga_layout.py --script storyboard.json
--pages-dir ./generated_panels/
--output ./final_pages/page_003.png
--gutter 40 --bleed 5%
# manga_layout.py 核心:拼版函数
from PIL import Image
def assemble(boxes, panel_images, canvas_size, gutter=40):
canvas = Image.new("RGB", canvas_size, "white")
for b, img in zip(boxes, panel_images):
x1, y1, x2, y2 = b["box"]
canvas.paste(img.resize((int(x2 - x1), int(y2 - y1))), (int(x1), int(y1)))
return canvas
final = assemble(boxes_for_page, rendered_panels, (1600, 2400))
final.save("/tmp/page_003_final.png")
常见问题
Q1:逐格生成的风格总是不统一怎么办?
把”风格前缀”作为每格提示词的固定常量(如 black and white manga, screentone, clean lineart),并让所有格子共享同一个 LoRA(如日漫风格 LoRA)。进阶做法是用 img2img 以”上一页最后一个格子”为底图做低 denoise 重绘(0.5~0.6),画面会像”接力”一样连贯。
Q2:角色在不同格子之间长相差很多,如何处理?
分镜自动化只解决”布局”,角色一致性需要 IP-Adapter / InstantID / 角色 LoRA 配合(这正是本系列第 5、13、14 天讲的内容)。流水线中应该为每个分镜格传入”角色参考图”作为 ControlNet/Image 输入节点,而不是只靠文字描述。
Q3:LLM 输出的分镜 JSON 格式不稳定,经常报错?
三重防御:① 在 prompt 里给 1~2 个 few-shot 完整 JSON 示例;② 用 response_format={"type": "json_object"}(OpenAI 系接口支持);③ 解析失败时降级——用正则提取 "panels": [...] 片段再 json.loads,仍然失败就让脚本按默认 6 格模板兜底,绝不让流水线中断。
Q4:格子数量怎么定才合理?
对话戏一页 6~8 格,动作戏 4~5 格,情绪大场面直接 1 个大 Splash。经验法则:”每页至少 1 个重点格,任何一格放不下对白就砍格数”。可以把这条规则写进第 2 层的校验器——生成布局后自动检查 Splash 缺失/格子过密 并报警告。
Q5:拼出来的页面总感觉”格子边缘对不齐”?
所有格子必须在同一套网格坐标系下计算(本文第三步),不要各自独立缩放。拼版时统一按”格沟 40px + 计算后尺寸”粘贴;若结果仍有 1~2px 误差,把 gutter 设成 4 的整数倍(打印分辨率 300dpi 下 4px ≈ 0.34mm),并在最终一步做全画布轻微整数缩放。
Q6:分镜脚本自动生成会吞掉我的创意吗?
不会,它吞掉的是”机械化劳动”。景别、构图、翻页节奏这类创意决定仍然由你把控——你只需要把 LLM 的分镜当成”第一稿”,在 JSON 上改格子布局比在白纸上重画快一个数量级。
总结
- 分镜是可编程的:漫画页面布局本质是一套网格 + 编号 + 比例规则,完全可以交给 LLM 出 JSON、Python 排坐标、SD 逐格出图的自动化流水线。
- 三层架构各司其职:脚本层(想)→ 布局层(排)→ 生成层(画),任何一层都可以独立替换升级,这是 AI 漫剧制作效率的关键。
- 风格统一靠”常量 + 共享参考”:整页共享风格前缀、同一 LoRA、img2img 接力,比逐格手调提示词可靠得多。
- 校验规则要内置:Splash 缺失、格子过密、坐标越界这类低级错误交给脚本自动拦截,让你的精力始终留在讲故事上。
- 下一站是文字层:页面拼好了,接下来就是气泡、拟声词与排版的战场——把这套流水线接到文字处理模块,你就拥有了接近”全自动”的 AI 漫画生产线。
下期预告:第 20 天《AI漫画风格迁移:从日漫到美漫》,我们将对比风格 LoRA、模型合并与 CFG 调整三种风格迁移路线,并给出跨风格批量迁移的实战配方。
📚 AI漫剧制 60 天系列目录(每日更新):
- 第 1 天:AI漫剧制是什么?从概念到行业全景
- 第 2 天:AI漫画生成工具全景对比
- 第 3 天:从小说到漫画:AI漫剧制完整工作流
- 第 4 天:提示词工程:AI漫画分镜的基石
- 第 5 天:角色一致性:AI漫画最难攻克的技术
- 第 6 天:画面构图:用AI控制镜头语言
- 第 7 天:AI漫画的版权问题与法律边界
- 第 8 天:漫剧制 vs 传统漫画:效率与艺术的平衡
- 第 9 天:漫画脚本自动生成:AI编剧入门
- 第 10 天:Stable Diffusion WebUI 漫画工作流搭建
- 第 11 天:ComfyUI 节点式漫画工作流入门
- 第 12 天:ControlNet 在漫画中的应用:姿态控制与构图
- 第 13 天:LoRA 训练:打造专属漫画角色
- 第 14 天:IP-Adapter 实现角色一致性
- 第 15 天:AI漫画上色工作流:从线稿到彩色
- 第 16 天:AI漫画文字处理:气泡、拟声词与排版
- 第 17 天:AI漫画背景生成:场景与特效
- 第 18 天:AI漫画的叙事结构:如何让AI讲好故事
- 第 19 天:漫画分镜自动化:AI辅助页面布局(🟢 今日)
- 第 20 天:AI漫画风格迁移:从日漫到美漫
- ……(共 60 天,持续更新中)














暂无评论内容