☰
Stable Diffusion Inpaint原理与实战:从潜空间到局部重绘
2026/9/30 8:16:35 网站建设 项目流程

很多人第一次接触Stable Diffusion的inpaint功能时,都会觉得它不过是个“涂抹后重新生成”的小工具——把不想看到的东西涂掉,点一下生成,完事。但真正上手做局部修改,问题马上就来了:要么把不该动的地方改得面目全非,要么修补区域的风格、光照跟原图完全是两个世界,更别提那些莫名其妙出现的畸形物体和诡异纹理。我刚开始玩SD的时候也被这些坑折磨得够呛,直到认真把inpaint背后的扩散模型原理捋清楚,才明白这功能远不是“涂掉重画”那么简单,它涉及到Stable Diffusion最核心的潜空间(latent space)扩散去噪机制、mask在噪声预测过程中的显式干涉方式,以及模型训练阶段对条件信息的注入策略。这篇就结合我自己跑图、修图、调参的实际经验,把inpaint的原理和实操一并讲透。

如果你正准备用Stable Diffusion做电商商品图的瑕疵修复、老照片翻新,或者想在生成图里微调某个局部元素,这篇文章能帮你从“知其然”走到“知其所以然”。我默认你已经能用SD WebUI或ComfyUI跑通基础文生图流程,如果还没装好环境,建议先去把模型下载和整合包部署弄清楚,再回来看这篇会顺畅得多。

1. 从文生图到inpaint:同一个去噪框架下的不同“玩法”

在拆inpaint之前,得先把Stable Diffusion的底子讲清楚。很多人学了几个月SD,反而被各种插件和LoRA搞得云里雾里,根源就在于没理解它本质上是一个“在潜空间里做去噪”的扩散模型(Diffusion Model)。

1.1 扩散模型训练与推理的核心逻辑

扩散模型的前向过程(forward process)是给一张干净图片逐步叠加高斯噪声,经过足够多步之后,图片彻底变成一片纯噪声。反向过程(reverse process)则是训练一个神经网络(在SD里是U-Net),让它学习如何一步步去除噪声、还原出清晰图像。

实际训练时,我们并不会真的“逐步”加噪,而是直接用一个公式,把任意时间步t的带噪潜变量一次性算出来,用正态分布累积分布函数的记号可以写成:给定一个干净图像潜变量z,随机采样噪声ε,然后通过噪声调度器(noise scheduler)算出第t步的带噪潜变量。U-Net的输入就是这个带噪潜变量和时间步t的条件编码,输出的是预测噪声ε_θ,损失函数就衡量预测噪声和真实采样噪声之间的误差。

推理阶段则反过来:训练时我们固定了噪声调度器的总步数T(SD默认是1000步),推理时从一个纯高斯噪声出发,用U-Net逐步预测噪声、减去噪声,循环若干步(DDIM采样通常20~50步)之后,得到干净的潜变量,再通过VAE解码器(Decoder)还原成像素级图片。

这套机制放到inpaint里的意义在于:图像修复本质上仍然是一次条件去噪,只不过我们希望在去噪过程中,除了文本prompt之外,还要让模型遵守另一条重要约束——用户指定的mask区域之外的像素必须保持原样。

1.2 为什么Stable Diffusion把去噪过程放在潜空间做

早期的DDPM等扩散模型直接在像素空间(pixel space)做前向加噪和反向去噪,对一张512×512的RGB图片来说,每一步U-Net要处理的就是一个512×512×3的张量,计算量相当大。Stable Diffusion的关键改进是先通过一个预训练好的VAE(变分自编码器)将图像压缩到潜空间:编码器(Encoder)把512×512的图像压缩为64×64×4的潜变量,U-Net在这个小得多的张量上做去噪,最后再用解码器把它还原回512×512。

这样做的直接好处有两个:一是训练和推理的计算开销大幅下降,个人显卡有望跑动;二是U-Net在更紧凑的表示空间里更容易学到图像的语义结构与高频细节的分离。潜空间虽然“维度小”,但它并不是简单的像素缩放,而是经过编码器抽象后的语义紧凑表示。

我们经常在WebUI里看到“Latent space”“VAE”这些选项,其实就是指这条编解码通路。inpaint里面的“潜空间填充”“潜空间噪声”等术语,都是在说我们是在这个64×64的压缩世界里做文章,而不是直接操作像素。

2. inpaint原理剖析:mask如何干预去噪过程

理解了扩散模型的底子,inpaint的原理就呼之欲出了。它本质上是在标准扩散采样循环中,对潜变量施加一个“局部保护”和“局部重置”的操作。

2.1 SD WebUI中inpaint的直观流程

在SD WebUI里,把一张图拖进img2img页面并切换到Inpaint模式,你会看到四个主要输入源:原图、蒙版(mask)、提示词、参数设置(重绘幅度、蒙版模糊、蒙版内容等)。点击生成之后,代码层面实际做了这些事情:

  1. 原图经过VAE编码,得到完整的潜变量,尺寸是H/8 × W/8 × 4(例如512×512图对应64×64×4)。
  2. 用户涂抹的蒙版(mask)会被缩放到和潜变量一样的分辨率,形成一个二值或带羽化的权重掩码,表示“哪些区域需要被重新生成”。
  3. 在采样开始前,把mask区域内的潜变量替换成随机高斯噪声,或者保留原潜变量,具体取决于你选择的“蒙版内容”(mask content)选项——是“填充”“原图”还是“潜空间噪声”。
  4. 进入去噪循环。每一步U-Net预测噪声之后,将更新后的潜变量与原始潜变量(或根据mask融合)合在一起:mask外的像素强制替换回原图的潜变量,mask内则保留去噪后的新内容。
  5. 循环结束后,把最终的潜变量通过VAE解码回图像。

这个过程的关键环节在第4步:每一步去噪后都会用mask做一次硬性融合(hard masking),以确保非目标区域的像素始终紧贴原图。如果这一步做得不彻底,模型就会连蒙版外的内容一起“自由发挥”,修图就变成了整图重绘。

2.2 关键参数背后的原理

这里就牵出SD WebUI inpaint面板上的几个核心参数,它们直接影响修复质量和生成结果的稳定性:

  • Mask blur(蒙版模糊/羽化):蒙版从边缘到外部有一个过渡带,模糊半径越大,重绘区域和原图之间的过渡越平滑。原理是避免硬边界产生的色彩断层和纹理错位。我一般修人像疤痕、瑕疵时用4~8像素,修大件物体替换时建议15~30像素,边界柔和度直接决定违和感的强弱。
  • Mask content(蒙版内容):决定在开始去噪前,mask区域内塞入什么。常见选项有三个:填充(fill)、原图(original)、潜空间噪声(latent noise)。填充会把蒙版区域用某个固定颜色(通常是灰色或模糊内容)填充,适合完全从零生成;原图则保留原有潜变量再在其上加噪,适合轻微微调;潜空间噪声则是完全随机,适合大改、替换。
  • Denoising strength(重绘幅度):这个参数控制整体采样过程中前面多少比例的噪声步会被实际重跑。重绘幅度0代表完全不动,1代表完全重新生成。对inpaint来说,它要结合mask内部内容一起理解:mask内的“初始状态”是从原图潜变量出发,还是从纯噪声出发。若选“原图”作为蒙版内容,denoising strength控制的是“原有内容被破坏后再重画的程度”;若选“填充”,低denoising strength可能让生成内容与填充色纠缠得出奇怪色块。
  • Inpaint area(重绘区域):选项是“Whole picture”(整张图)和“Only masked”(仅蒙版)。选择Only masked时,WebUI会裁剪mask外扩一定像素的矩形区域,只对这块小图做潜空间去噪,再把结果贴回原图。好处是计算量小、对局部细节约束更精准;缺点是如果裁剪窗口太小,没有足够的全局上下文,生成的物体比例和空间感容易崩。

这三个参数的组合,决定了修复结果的“自由度”与“稳定性”。我曾做过一组对比实验,同一张图、同一个蒙版,分别组合不同参数,结果差异极大。例如蒙版内容选“原图”配合denoising 0.4,适合给物体换颜色、微调形状;而蒙版内容选“填充”配合denoising 0.75,则适合把整个物体替换成另一个完全不同类别的东西。这一点在第四节还会给出一组完整的参数对照表。

2.3 原始SD模型中的inpaint局限

如果你用的只是基础版Stable Diffusion 1.5原版模型,直接在img2img里开inpaint,往往会出现一个现象:重绘区域的内容看起来“孤立”,跟周围环境脱节,像一张透明贴纸贴上去的。这是因为原版模型的训练数据分布里,图像与文本是多模态对齐的,但模型并不天然知道“这是一块被蒙住的洞,外面画的是什么”。

换句话说,原版inpaint的mask融合只是采样时期的一种“后处理约束”,U-Net本身并没有专门针对mask信息进行训练。它看到的是一个“带着随机噪声的洞”的潜变量,以及一段可能的提示词,但并不知道这个洞的外侧应该对应什么样的边缘结构、物体遮挡关系、光照方向。因此模型就像在黑暗中猜谜,能画出“看起来符合提示词的东西”,但不保证能和周围场景严丝合缝。

3. 为什么会有专门的inpaint模型:深入SD的inpaint-conditioning机制

为了缓解上述问题,社区与官方先后推出了专门针对inpaint任务微调的模型版本,比如最常见的sd-v1-5-inpaint。这类模型不是凭空创造新架构,而是在原有SD基础上,把mask通道显式地喂给U-Net,让网络学会“把洞的边界和外部信息作为条件来生成内部内容”。

3.1 五通道输入与mask作为额外条件

具体做法是这样的:普通SD的U-Net输入是带有噪声的潜变量,形状是B×4×H×W(4个通道来自VAE潜空间)。而在inpaint微调模型中,输入被扩展为B×9×H×W,其中:

  • 4个通道:带噪的mask内潜变量;
  • 4个通道:原始图像的潜变量信息(mask外区域为主,mask内则是一个可学习的占位或0);
  • 1个通道:二值化的mask,标记1表示需要重绘,0表示保留原样。

这九个通道拼在一起,从第一层卷积就进入U-Net。模型在微调时看到的每个训练样本都同时携带“原图信息”和“蒙版指引”,因此它能在去噪的早期阶段就感知到:哪片区域是已有内容需要保持,哪片是空洞需要生成。生成结果会在结构布局、边缘贴合度、色调一致性上明显优于原版模型。

这个机制可以类比为一个美术生接到的单子:不只是告诉他“这里补一块”,而是把整个画布、参考照片和标注了修改区域的透明纸同时摆在他面前。他既能看到洞口之外的颜色风格,又能看到洞本身的形状轮廓,补出来的内容自然更贴合整体。

SD WebUI里,你只要在模型列表里选择了像sd-v1-5-inpaint这样带有inpaint字样的模型,程序会自动采用9通道的inpaint模式。如果用的是普通模型,WebUI内部其实也会做一些类似处理(例如V1模型的inpaint后期修复机制),但由于网络的通道数和训练目标没有匹配,效果会打折扣。

3.2 SDXL与新版模型的inpaint差异

如果你已经在用SDXL或更新的模型,可能会发现一个现象:官网并不直接提供SDXL的inpaint专用版本。这是因为SDXL在训练时已经支持了基于mask的inpaint微调范式,社区也在发布后训练了很多适配SDXL的inpaint LoRA或专用checkpoint。

另一个角度是,随着ControlNet(尤其是inpaint专用ControlNet)的普及,很多人直接用“原图+蒙版”作为控制条件,让ControlNet驱动U-Net生成内容,而不是依赖模型内置的9通道。这种方式更加灵活,也更适合风格化重绘、多物体替换等复杂任务。

不过在WebUI里,普通用户最顺手的依然是专门的inpaint模型。如果你经常做局部修图,建议去HuggingFace下载runwayml/stable-diffusion-inpainting,或者直接用秋叶整合包内置的“sd-v1-5-inpaint”版本。实测下来,同样的提示词和参数,用inpaint模型修人像脸部细节,比用原版1.5模型稳定得多。

3.3 代码层面:采样循环里的mask hard-blending

为了让读者更直观地理解inpaint原理,我用伪代码把SD WebUI里的核心采样循环写出来:

for t in range(start_step, 0, -1): # 1. 预测噪声 noise_pred = unet(latent, t, text_embeddings) # 2. 根据采样器更新潜变量 latent = sampler_step(noise_pred, latent, t) # 3. 将mask外部区域还原为原图潜变量 latent = mask * latent + (1 - mask) * original_latent

第3步就是所谓的hard-blending。对于特定模型,unet内部会同时读取mask通道,所以第1步的输入其实是9通道拼接张量,而不仅仅是4通道带噪潜变量。

这里有一个实践细节要提醒:如果你的修复对象包含复杂纹理,比如草地、头发丝、布料褶皱,仅仅依赖hard-blending是不够的,因为相邻像素在潜空间里的差异经过解码器放大后,会出现“边缘锯齿”或“纹理撕裂”。这也是为什么官方inpaint工具会默认提供inpaint_full_res选项,即在全分辨率下先对mask边缘区域做一次专用的“高分修复”步骤,再用低阶去噪改善细节。

4. 实战:一张照片的局部重绘参数化配置全流程

说到底,理解了原理是为了更好地使用工具。下面我以“给一张室内人像换掉沙发上的抱枕”为例,走一遍用SD WebUI inpaint修复图片的完整流程。

4.1 环境准备与模型选择

我用的是秋叶整合包v4.5版本,内置了Stable Diffusion WebUI 1.9.3,模型选用sd-v1-5-inpaint(也可用Anything-v5-inpaint等二次元向模型,主要看你做的素材类型)。

启动WebUI后,进入img2img标签页,上传原始图片,然后点击右上角的“绘制蒙版”按钮,进入蒙版编辑器。用画笔仔细涂抹掉抱枕区域。这里我建议把画笔尺寸调大一点,覆盖住抱枕及其投在地面的投影,宁多勿少——多涂一点模型能用边缘信息自行推理,漏涂了则会出现残留原物体的幽灵边缘。

蒙版画完后,建议先点“预览蒙版”确认黑白分布。如果边缘呈锯齿状,可以适量调高Mask blur参数(比如15)来做羽化。

4.2 参数配置对照表

下面是我实测过的一组参数配置,直接套用就能获得不错效果:

参数项推荐值原理解释
重绘幅度(Denoising Strength)0.5~0.65既能较大程度改变新物体形态,又不会让背景因为重绘而漂移
蒙版内容(Mask Content)填充(fill)抱枕被完全替换,旧颜色和纹理不应影响新物体
蒙版模糊(Mask Blur)12~16让新旧物体边界平滑过渡
重绘区域仅蒙版(Only Masked)只计算抱枕周围一小块区域,减少对全局画面的扰动
重绘尺寸倍数0.85~1.0太小会导致新物体分辨率不足,太大容易超出显存
采样方法DPM++ 2M Karras在细节还原和采样速度间比较均衡
采样步数28~32默认20步也能用,但修复局部时30步更细腻
Batch Count1~2,打开“额外生成网格”一次生成多张,选择最优,避免反复修改参数

提示词部分,我写的是:

a photo of a cozy living room with sofa and decorative pillow, soft natural lighting, photorealistic, highly detailed, 8k

负面提示词:

lowres, bad anatomy, bad hands, blurry, pixelated, oversaturated, unnatural lighting, extra objects, duplicate pillow

需要特别提醒的是,提示词里要明确描述“沙发上有抱枕”这个语义,而不是只写“修复”。因为inpaint模型生成时,text embedding会同步引导局部区域的内容,你不描述,它就可能随机画出一个坐垫、一个毛绒玩具或者其他东西。

4.3 多图对比与调参方向

我第一次生成时,结果中抱枕形状OK但颜色和沙发色调不一致,看起来像从别的场景搬来的。这时我给提示词增加了“pillow in warm beige color, matching sofa style”,重绘幅度下调到0.5,同时勾选“重绘区域仅蒙版”里的“Resize to original resolution”选项。第二次生成,新抱枕明显融入了画面,阴影也更自然。

如果生成结果中抱枕边缘有像素噪点或过渡生硬,我建议把Mask Blur从默认提到20,同时检查是否开启了“Advanced masking”里的“Mask blur for latent space”。很多版本的WebUI把这个参数单独拆出来了,默认是0,不开启的话即使面板上设置了Mask Blur,潜空间融合时也没有羽化效果。

4.4 语义引导增强:ControlNet inpaint的额外选项

如果你在重绘大幅物体时总感觉模型“缺少空间透视感”,可以考虑加装ControlNet的inpaint专用预处理器与模型。在ControlNet面板中,选择“inpaint”类型并上传原图+蒙版,控制权重建议0.75。这样U-Net除了文本条件之外,还有一个显式的结构条件在引导,生成内容的边界保持能力会明显增强。

这套流程用熟了之后,修路人像上的电线杆、清理背景杂物、改商品颜色,都是同一套方法论。难点不在操作步骤,而在理解和调节denoising strength、mask content与提示词之间的微妙平衡。

5. inpaint实战中最容易踩的坑:完整踩坑链路复盘

搞AIGC的朋友应该都有体会,很多参数在说明书上写得很简单,一到实际项目里就各种翻车。下面我挑出我在inpaint修复上踩得最深的三个坑,完整复盘一下排查过程,帮大家少走弯路。

5.1 坑一:重绘幅度过高导致整个画面风格漂移

现象:我最初修图时习惯沿用文生图里的默认参数——Denoising strength=0.75,结果生成的图片里,mask内的物体确实换了,但整张图的颜色、对比度、甚至远处背景的人都变了。这种在全图中扩散的“风格漂移”其实是因为去噪步数多,导致mask外的潜变量也被多次加噪去噪,边缘约束虽然强制把外部像素还原回原图,但因为高位特征被破坏过,解码后色彩已经对不齐。

排查过程:我先关掉inpaint,在img2img里测原图在不同denoising strength下的变化程度,发现0.6以下时画面几乎不变,0.7以上时背景明暗开始偏移。结合inpaint时模型是在“原图潜变量”基础上加噪声重画的机制,我判断问题出在这:如果选择“蒙版内容=原图”,denoising强度会把整个从原图潜变量到噪声的路径重走一遍,所以即使mask约束了像素,全局风格仍会漂。

解决方案:把denoising strength降到0.55,同时开启“蒙版外区域添加少量噪声”选项(WebUI有个“Masked content padding”下拉框,选“Original”并设置padding为32,意思是蒙版外扩展32像素后原图区域也参与潜空间噪声注入,但最后通过hard masking还原),这样模型有足够的上下文感知,又不会破坏外部的低位色彩信息。

5.2 坑二:生成的物体边缘像抠图,生硬锯齿

现象:用一张老照片修掉照片角落的日期水印,mask画得很仔细,但生成后水印区域边缘有一圈暗色轮廓,像是PS里没处理好边缘的透明过渡。

排查过程:我最初怀疑是模型质量或提示词问题,换成更精细的inpaint模型后依然存在。后来发现是我没开启“Advanced masking”里的羽化功能。WebUI在蒙版编辑器里画出的蒙版是硬边界的,而inpaint模型训练时通常使用的是带羽化的mask,在推理时如果仍用硬边界,网络就会看到“一个像素级别的极端分割”,它生成的内容在与外部潜变量融合时,解码器会因为在潜空间里两类特征差异过大而产生局部过曝或暗边。

解决方案:把Mask blur调到20~30,同时开启“Inpainting conditioning mask strength”为0.8。这个参数控制的是“U-Net对mask条件的置信度”,取值太高会让模型完全无视边缘外部信息,太低则外部信息会渗入重绘区。我个人经验是0.7~0.85之间效果最好,既能保持边缘过渡,又不会让原图纹理直接污染修复区域。

5.3 坑三:修复人脸时出现“第二张脸”或器官错位

现象:给一张合影里闭眼的人像补开眼,mask只涂在眼部,结果生成的区域里出现了一只完整的眼睛和半张鼻子,比例完全不对。

排查过程:这个问题最初让我很困惑,因为眼部区域在潜空间里只占几个像素宽,为什么生成结果会那么离谱,甚至多处了一个鼻子?后来我看了OpenPose和检测模型的方法才明白:人在潜空间里是一个整体结构,不同器官的特征是纠缠在一起的,你只给出一个眼部小窗,意味着窗口内的潜变量经过随机初始化后没有任何“人脸结构先验”,模型只能从全局文本信息和窗口边缘的反推来猜测内容。

解决方案:把mask扩大,覆盖到眉毛、鼻子、脸颊的一部分,让模型看到完整的面部轮廓。同时在高级选项里勾选“Use Inpaint width/height”并在下面的尺寸控制里设置为原图的1.0~1.2倍。这样一个192×192的眼睛区域被放大到256×256,U-Net有更多像素去推理五官之间的空间关系,生成结果顿时自然了很多。

另外提示词也很重要。补眼睛时,提示词要写“open eyes, natural expression, detailed iris”,而不是只写“face, detailed”。因为模型需要知道具体补什么,而不是在原地自由发挥。

5.4 坑四:想修背景,结果前景一起去“变形”了

现象:想把照片里的垃圾桶P掉,背景是草地和树,我画了mask覆盖垃圾桶,结果生成的区域里草坪纹理不对,树的枝干也扭曲了。

排查过程:这类问题通常不是模型问题,而是修复的“信息量不足”。背景区域属于大尺度重复纹理,U-Net要生成可信的草地、树木,需要足够大的空间上下文。当我把重绘区域设为“仅蒙版”时,窗口只包含垃圾桶周围很小的区域,模型看到的上下文太少,只能靠猜测补全——其结果往往就是纹理半对半错。

解决方案:切回“全图”模式(Inpaint area = Whole picture),让U-Net在全图尺度上理解场景,然后只对mask区域做强制约束。同时提高重绘幅度到0.7,给模型更多自由去“连贯地”重构背景。这个操作显存占用略高,8G显存跑512×512图没有问题,建议batch size=1。

6. 进阶技巧:产品图修复场景中的inpaint组合拳

最后分享一套我在电商项目里沉淀的组合玩法,适用于商品图瑕疵修复、背景杂物清理、倒影重构等相对复杂的场景。

6.1 分块修复策略

如果一张图上有多个独立瑕疵,不建议一次性画多个分离的mask。因为多个mask同时作用于潜变量时,每个区域都会成为另一个区域的“外部上下文”,模型容易混淆彼此之间的空间关系,导致修补内容互相穿插。我的做法是拆成多次修复,每次只处理一个mask,其它区域保持原样。第一遍修完保存结果,然后再上传到新的inpaint任务修第二个瑕疵。虽然多了一步,但质量提升非常明显。

6.2 结合局部重绘与全尺寸高清放大

电商图片修完后往往要输出4K甚至更大。在WebUI中,可以开启“Tiled VAE”或使用Ultimate SD Upscale插件,在放大过程中继续用小规模去噪,让修复区域的纹理细节和周边区域同步增强。个人经验是先把inpaint搞定,再用1.5倍~2倍放大,效果比直接在原始分辨率上重绘好很多。

6.3 关于蒙版绘制效率的沉痛教训

千万不要用默认的画笔一笔一笔涂大面积区域。建议在蒙版编辑器里先用“多边形套索”粗选目标,再用“变换”调整覆盖范围,最后用“画笔”修细节。我一开始来回涂了十分钟,结果边缘凹凸不平,生成边缘杂色很多。后来用套索+5像素羽化一次选完,配合Mask blur 20,一张复杂商品的修复时间缩短到三分钟以内。

7. 写在最后:从参数调优回到原理理解

虽然文章题目是“以inpaint修复图片为例”,但说到底,这类技术人人都能跑通步骤,差距往往体现在对“为什么这样设置”的理解上。你以为你调的是重绘幅度,实际上你在调噪声采样路径的长度;你以为你画了个蒙版,实际上你在给U-Net指定条件通道;你以为多生成几次总能出好图,实际上如果mask内容和context不够,抽卡只会稳定地抽出废片。

这些年用Stable Diffusion做项目,最大体会是:越依赖随机抽取,越需要知道随机背后的确定性。inpaint的确定性来自diffusion采样轨迹、mask约束、文本嵌入三者的精确配合,只要你愿意花时间把这三者之间的相互作用搞清楚,多数“修不好”的情形都能转化为“换一种参数立即见效”的成就感。

之后如果有机会,我会再展开聊聊ControlNet inpaint、SDXL本地重绘的高分修复链路,以及在ComfyUI里搭一个生产级inpaint工作流的细节。有问题也欢迎在评论区交流,我看到会尽量回。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询