图像修复扩展与编辑 本节摘要:文生图创造新东西,修复(Inpainting)修补旧东西。生产中,70% 的付费图像工作是编辑——换背景、去 logo、扩展画布、重画一只手。修复是扩散真正赚钱的地方。本节讲透:为什么「朴素掩码重注入」会有接缝伪影、正确的修复模型如何用 9 通道 U-Net( )让模型「看见」掩码周围、SDEdit 如何通过「加噪到中间 t 再反向」实现零训练编辑、InstructPix2Pix 如何用 三元组微调出指令式编辑,以及 RePaint 如何用周期性重降噪消除接缝。我们会梳理 SAM + 扩散修复这套 2026 年去背景流水线,以及 Flux-Kontext 如何用「单次前向」取代整条多阶段编辑管线。
本节摘要:文生图创造新东西,修复(Inpainting)修补旧东西。生产中,70% 的付费图像工作是编辑——换背景、去 logo、扩展画布、重画一只手。修复是扩散真正赚钱的地方。本节讲透:为什么「朴素掩码重注入」会有接缝伪影、正确的修复模型如何用 9 通道 U-Net(
带噪潜变量 | 编码源图 | 掩码)让模型「看见」掩码周围、SDEdit 如何通过「加噪到中间 t 再反向」实现零训练编辑、InstructPix2Pix 如何用(图, 指令, 输出图)三元组微调出指令式编辑,以及 RePaint 如何用周期性重降噪消除接缝。我们会梳理 SAM + 扩散修复这套 2026 年去背景流水线,以及 Flux-Kontext 如何用「单次前向」取代整条多阶段编辑管线。
对应原课程:Phase 08 · Lesson 09 ·
inpainting-outpainting-editing(原英文phases/08-generative-ai/09-inpainting-outpainting-editing/docs/en.md)。
阅读完本节,你应当能够:
concat(带噪潜变量 4ch, 编码源图 4ch, 掩码 1ch),训练时随机遮罩、让模型只见未遮罩区做条件。t,再用新提示反向;t/T 在保真与创意之间权衡。客户发来一张完美的产品照,背景里有个抢眼的招牌。你想擦掉招牌,其余像素逐像素不变。你不能从零跑文生图——结果会有不同颜色、不同光照、不同产品角度。你只想只重生成遮罩区域,且重生成要尊重周围上下文。
这就是修复。三个变体:
2026 年的每条扩散流水线都有修复模式:Flux.1-Fill、Stable Diffusion Inpaint、SDXL-Inpaint、DALL-E 3 Edit。它们原理相同。
跑标准文生图,带一个掩码。每个采样步,把未遮罩区域的带噪潜变量替换成「干净图前向扩散后的版本」。它能跑……但很差。边界伪影渗透,因为模型对掩码内有什么毫无信息。
训一个修改过的 U-Net,吃 9 个输入通道而非 4 个:
input = concat([ 带噪潜变量 (4ch), 编码图像 (4ch), 掩码 (1ch) ], dim=channel)
多出来的通道是 VAE 编码后的源图像副本,加一个单通道掩码。训练时,随机遮罩图像区域,训练模型只对遮罩区去噪,而未遮罩区作为干净条件信号给出。推理时,模型能「看见」掩码周围有什么,产出连贯的补全。
SD-Inpaint、SDXL-Inpaint、Flux-Fill 都用这个 9 通道(或类似)输入。对应 diffusers 的 StableDiffusionInpaintPipeline、FluxFillPipeline。
💡 9 通道 vs 朴素重注入的本质区别:朴素做法靠「每步重注入未遮罩」来强制保真,但梯度信息无法跨掩码边界流动,所以接缝处永远对不齐。9 通道做法把源图与掩码直接喂进网络,让 U-Net 在每一层都能「看见」边界两侧,从而学到「如何让生成区与保留区在纹理与光照上连贯」。这是「外部约束」与「内部感知」的区别。
把源图加噪到某个中间 t,然后用新提示从 t 反向跑到 0。无需重训。起始 t 的选择在保真与创意之间权衡:
t/T = 0.3 → 几乎与源图一致,小幅风格变化。t/T = 0.6 → 中等编辑,保留粗结构。t/T = 0.9 → 从近噪声生成,源图几乎不留。在 (输入图, 指令, 输出图) 三元组上微调扩散模型。推理时,同时以输入图和文本指令(「把它变黄昏」「加一条龙」)为条件。两个 CFG 比例:图像比例和文本比例。
保持一个标准的无条件扩散模型。每个反向步,重采样——偶尔跳回更噪的状态再重生成。避免边界伪影。在你没有训练好的修复模型时用。
code/main.py 在 5 维数据上实现一个玩具一维修复。我们训一个 DDPM,数据是来自两个簇之一的 5 个浮点数。推理时,我们「掩掉」5 维中的 2 维,每步注入未遮罩 3 维的前向加噪版,只重生成被掩掉的维度。
def sample_data(rng): cluster = rng.choice([0, 1]) center = [-1.0] * 5 if cluster == 0 else [1.0] * 5 return [c + rng.gauss(0, 0.2) for c in center], cluster
标准 DDPM。网络对 5 维带噪输入输出 5 维噪声预测。
def inpaint_step(x_t, mask, clean_image, alpha_bars, t, rng): # 把未遮罩维度替换成干净源的前向加噪版 a_bar = alpha_bars[t] for i in range(len(x_t)): if not mask[i]: x_t[i] = math.sqrt(a_bar) * clean_image[i] + math.sqrt(1 - a_bar) * rng.gauss(0, 1) # ...然后对 x_t 跑正常反向步
这是朴素做法,在一维玩具上能跑。真实图像修复用 9 通道输入,因为纹理连贯更重要。
扩展就是掩码反转的修复:掩掉新的(原本不存在的)画布区,其余填原图。训练目标相同。
接缝:朴素做法留可见边界,因为梯度信息不跨掩码流动。修复:把掩码膨胀 8-16 像素,或用正规的修复模型。
掩码泄漏:如果条件图的未遮罩区低质量或有噪声,会污染掩码内生成。轻度去噪或模糊。
CFG 与掩码大小交互:高 CFG 配小掩码 = 饱和色块。小编辑降 CFG。
SDEdit 保真悬崖:从 t/T = 0.5 到 0.6 可能丢主体身份。扫描并设检查点。
提示不匹配:提示应描述整张图,不只是新内容。「一只猫坐在椅子上」而非「一只猫」。
⚠️ SDEdit 的 t/T 是双刃剑:
t/T越大,加噪越多,模型自由度越高,但源图保真越低。经验上存在悬崖——0.5→0.6的一步可能让人物身份完全丢失(因为高频身份信息刚好在那个噪声水平被摧毁)。生产中要按主体做扫描,把t/T当离散旋钮而非连续滑块。
| 任务 | 流水线 |
|---|---|
| 去物体、小掩码 | SD-Inpaint 或 Flux-Fill,标准提示 |
| 换天空 | SD-Inpaint +「黄昏蓝天」 |
| 扩画布 | SDXL 扩展模式(8px 羽化)或 Flux-Fill + 扩展掩码 |
| 重画手 / 脸 | SD-Inpaint + 重述主体的提示 + ControlNet-Openpose |
| 改某区域风格 | SDEdit t/T=0.5 在遮罩区 |
| 「变黄昏」 | InstructPix2Pix 或 Flux-Kontext |
| 背景替换 | SAM 掩码 → SD-Inpaint |
| 超高保真 | Flux-Fill 或 GPT-Image(托管)应对最难案例 |
SAM(Meta 的 Segment Anything,2023)+ 扩散修复,是 2026 年的去背景流水线。SAM 2(2024)支持视频。
用户编辑图像期望亚 5 秒往返。1024² 上 30 步 SDXL-Inpaint 在 L4 上约 3-4 秒,加 SAM 掩码生成(~200 ms)和 VAE 编解码(合计 ~500 ms)。用生产术语,这是 TTFT 受限而非吞吐受限——批大小 1、低并发、最小化每个阶段:
SAM-H 是慢的那个:SAM-H 在 1024² 约 200 ms;SAM-ViT-B 约 40 ms,质量损失轻微。SAM 2(视频)加时间开销;单图编辑别用它。
能跳过编码就跳过:pipe.image_processor.preprocess(img) 把图编码到潜变量。如果你有上一轮生成的潜变量(迭代编辑 UI 常见),通过 latents=... 直接传,跳过一次 VAE 编码。
掩码膨胀也影响吞吐:小掩码意味着 U-Net 前向大部分被浪费(未遮罩像素反正被钳住)。diffusers 的 StableDiffusionInpaintPipeline 不管掩码大小都跑完整 U-Net;只有 9 通道正规修复变体才利用掩码计算。
Flux-Kontext 是 2025 的答案:对 (源图, 指令) 单次前向——无独立掩码、无 SDEdit 噪声扫描。H100 上约 1.5 秒交付一个编辑。架构教训:把阶段折叠掉。
本节产出一个编辑流水线技能文件(位于原课程 outputs/skill-editing-pipeline.md)。
skill-editing-pipeline.md:输入「原图 + 编辑描述 + 可选掩码(或 SAM 提示)」,输出:掩码生成方案、底座模型、CFG 比例(图像 + 文本)、SDEdit-t 或修复模式、QA 清单。简单。 在 code/main.py 里把掩掉的维度比例从 0.2 变到 0.8。在哪个比例下,修复质量(被掩维度的残差)等于无条件生成?
中等。 实现 RePaint:每 10 个反向步,跳回 5 步(加噪)再重去噪。测量它是否减少掩码边界的残差。
困难。 用 Hugging Face diffusers 比较:SD 1.5 Inpaint + ControlNet-Openpose vs Flux.1-Fill,在 20 个脸部重生成任务上。分别给姿态遵从度和身份保持度打分。
带噪|源图|掩码)让模型每层都「看见」边界两侧,学到纹理与光照连贯。t 再用新提示反向;t/T 权衡保真与创意,且有「保真悬崖」。(图,指令,输出) 三元组上微调,双 CFG(图像 + 文本)。下一节,我们把扩散从空间维度扩展到时间维度——视频生成:时空 DiT、时间一致性约束、运动条件,以及 Sora、Veo、Kling 如何在保持帧间连贯的同时生成数秒视频。