ComfyUI 局部图像修复加速实战:Inpaint Crop 与 Inpaint Stitch 节点源码原理全解

📅 2026/8/14 13:43:25
ComfyUI 局部图像修复加速实战:Inpaint Crop 与 Inpaint Stitch 节点源码原理全解
ComfyUI 局部图像修复加速实战Inpaint Crop 与 Inpaint Stitch 节点源码原理全解【免费下载链接】ComfyUI-Inpaint-CropAndStitchComfyUI nodes to crop before sampling and stitch back after sampling that speed up inpainting项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Inpaint-CropAndStitch你是否遇到过这样的场景在一张 4K 的高清照片上只是想抹掉电线杆、换掉路牌但整张图丢给 Stable Diffusion 做 inpainting显存报警、单次采样几分钟起步最后连没被遮住的区域都被模型顺手改得面目全非ComfyUI-Inpaint-CropAndStitch 正是为这个痛点而生的插件。它通过Inpaint Crop Improved裁剪与Inpaint Stitch Improved拼接两个节点把整图修复变成局部修复先只裁出掩码附近的一小块区域送去采样采样完再无缝拼回原图。这不仅让高分辨率图像修复提速数倍还能保证未遮罩区域像素级不变。本文不满足于教你怎么用而是带你顺着inpaint_cropandstitch.py的代码走一遍完整流程看懂它究竟怎么做到的。一句话速览它到底做了什么只算该算的像素其余原样保留。修复模型的算力消耗与输入分辨率成正比。与其让模型看完整张 4K 图不如只给它看掩码周围那一小块——模型既能拿到足够的上下文信息又不用为大片无关区域白付算力。裁剪节点负责切出最优的一块并记住位置拼接节点负责修复完再贴回去天衣无缝。全流程下来未遮罩区域甚至不会经过 VAE 编解码从根上杜绝了顺带被改的问题。架构地图先建立全局观整个插件只有两个节点类但它们背后站着一个精心设计的处理器体系整体关系如下两个对外节点InpaintCropImproved裁剪和InpaintStitchImproved拼接定义在inpaint_cropandstitch.py中通过NODE_CLASS_MAPPINGS暴露给 ComfyUI。一个抽象基类ProcessorLogic用ABC定义了 10 多个抽象方法——图像缩放、掩码膨胀、高斯模糊、上下文定位、魔法裁剪、魔法拼接等相当于一份图像处理能力清单。两个具体实现CPUProcessorLogic基于 PIL SciPy兼容性拉满GPUProcessorLogic基于 PyTorch 算子max_pool2d、conv2d、向量化归约速度提升几十倍。一份跨节点契约裁剪节点输出一个STITCHER类型字典里面装着画布图像、裁剪区域坐标ctc、原图在画布中的位置cto等全部元数据拼接节点只凭这份数据就能精确复原。一句话记住模块关系节点负责接客Processor 负责干活STITCHER 负责传话。一次完整的调用旅程从掩码到成图我们以官方工作流example_workflows/inpaint_sd15.json为例模拟一次典型执行。请先看图建立印象图1Inpaint Crop 与 Inpaint Stitch 在 ComfyUI 中的完整工作流示意中间可以插入任意常规采样流程第一站InpaintCropImproved.inpaint_crop 入口裁剪节点的入口函数签名非常长有 26 个参数但它做的事可以拆成清晰的四步1设备与数据准备。根据device_mode选择GPUProcessorLogic或CPUProcessorLogic随后是一大段形状对齐逻辑——单张图配多张掩码、多张图配单张掩码、缺失掩码补全全部在此统一成 batch 维度一致的张量。2掩码整形手术。这是最容易看花眼的部分顺序依次是if mask_fill_holes: sub_mask processor.fillholes_iterative_hipass_fill_m(sub_mask) if mask_expand_pixels 0: sub_mask processor.expand_m(sub_mask, mask_expand_pixels) if mask_invert: sub_mask processor.invert_m(sub_mask) if mask_blend_pixels 0: sub_mask processor.expand_m(sub_mask, mask_blend_pixels) sub_mask processor.blur_m(sub_mask, mask_blend_pixels * 0.5) if mask_hipass_filter 0.01: sub_mask processor.hipassfilter_m(sub_mask, mask_hipass_filter)填洞 → 膨胀 → 反转 → 再膨胀并模糊 → 高通过滤每一步都是可开关的。其中fillholes_iterative_hipass_fill_m值得一提它用一个从 1.0 递减到 0.1 的阈值序列反复做闭运算 填洞每轮只补上当前阈值对应的区域从而在保留灰度渐变的同时把封闭空洞彻底填平——这是普通二值化填洞做不到的细节。3确定上下文区域。关键就三行_, bx, by, bw, bh processor.batched_findcontextarea_m(sub_mask) # 找掩码包围盒 _, bx, by, bw, bh processor.batched_growcontextarea_m(sub_mask, ...) # 按因子向外扩 _, bx, by, bw, bh processor.batched_combinecontextmask_m(sub_mask, ...) # 合并可选上下文掩码先算出掩码的最小外接矩形再按context_from_mask_extend_factor默认 1.2即四周各多留 20% 的上下文向外扩张最后与optional_context_mask的外接区域求并集。optional_context_mask是个很有用的设计当你想让模型看到某个与修复区域没有直接相连、但又对语义至关重要的地方比如镜像反射的参照物时画个包围它的大致范围即可不需要精修。4核心魔法crop_magic_im。这是全文最值得精读的函数我们单独拆解。第二站crop_magic_im 的七步魔法这个函数输入掩码区域和期望的目标尺寸如 512×512输出裁剪好的图、掩码以及拼接所需的两组坐标。它的聪明之处在于**先扩展画布再切窗口**目标尺寸对齐 padding把目标宽高向上取整到output_padding默认 32的整数倍满足模型对输入尺寸的整除要求。算宽高比目标宽高比 target_w / target_h。扩展上下文区域以匹配宽高比如果上下文区域太扁宽高比小于目标就在宽度方向扩太瘦就在高度方向扩。经典的一行if context_aspect_ratio target_aspect_ratio: new_w int(h * target_aspect_ratio) # 宽度扩到目标比例 new_x x - (new_w - w) // 2 # 保持掩码居中 else: new_h int(w / target_aspect_ratio) # 高度扩到目标比例 new_y y - (new_h - h) // 2扩出来的矩形还可能超出图片边界作者的处理是优先整体平移回界内实在塞不下才允许越界——比过去直接以掩码为中心硬切的方案更省内存也更符合直觉。 4.扩展画布若区域越界把画布四周按原图边缘像素补齐edge extension而非镜像同时记录cto画布中原始图像的位置。 5.切窗口在扩展后的画布上按新坐标切出cropped_image和cropped_mask记录ctc裁剪窗口在画布中的位置。 6.缩放若开启output_resize_to_target_size按方向自动选择放大/缩小算法缩放到目标分辨率。 7.返回十元组canvas_image, cto_x, cto_y, cto_w, cto_h, cropped_image, cropped_mask, ctc_x, ctc_y, ctc_w, ctc_h。一句话理解这段代码裁剪不是在图上抠一块而是造一张更大的画布、把图放进去、再切窗这样拼接时才有地方放越界生成的像素。第三站中间随便接采样流程裁剪节点输出cropped_image和cropped_mask之后完全走 ComfyUI 常规流程InpaintModelConditioning编码、KSampler 采样、VAE 解码甚至可以在中间插一层 hiRes 放大官方高分辨率工作流就是这么做的只要保持宽高比即可拼接节点会自动把它缩放回原位。图2官方 SD 1.5 示例工作流Inpaint Crop 裁出局部采样完成后由 Inpaint Stitch 无缝拼回第四站InpaintStitchImproved 的精准回贴拼接节点只有两个输入stitcher和inpainted_image。它的核心逻辑在stitch_magic_im算上注释不到 30 行# 1. 把修复图缩放回 ctc 窗口尺寸 if ctc_w w or ctc_h h: resized_image self.rescale_i(inpainted_image, ctc_w, ctc_h, upscale_algorithm) else: resized_image self.rescale_i(inpainted_image, ctc_w, ctc_h, downscale_algorithm) # 2. 取画布上待覆盖区域 canvas_crop canvas_image[:, ctc_y:ctc_y ctc_h, ctc_x:ctc_x ctc_w] # 3. 掩码加权混合新图 掩码×修复图 (1-掩码)×原画布 blended resized_mask * resized_image (1.0 - resized_mask) * canvas_crop # 4. 贴回画布再裁出原始图像区域 canvas_image[:, ctc_y:ctc_y ctc_h, ctc_x:ctc_x ctc_w] blended output_image canvas_image[:, cto_y:cto_y cto_h, cto_x:cto_x cto_w]混合用的掩码不是硬边掩码而是裁剪阶段就准备好的、经过膨胀和模糊的cropped_mask_for_blend——模糊边缘让修复区与背景渐变过渡接缝就此消失。最后按cto裁回原图范围越界生成的像素被自然丢弃。至此一次完整的裁→修→拼旅程结束。代码亮点放大镜最值得抄的三个技巧亮点一用 max_pool2d 实现掩码膨胀用 conv2d 实现高斯模糊CPU 版的掩码膨胀走 scipy 的grey_dilation高斯模糊走gaussian_filter这在 GPU 模式下会成为瓶颈。GPU 版换了个思路# 膨胀 ≈ 方形核最大值池化 mask_padded TF.pad(mask_in, (padding, padding, padding, padding), modereflect) dilated TF.max_pool2d(mask_padded, kernel_sizekernel_size, stride1, padding0)数学上形态学膨胀就是邻域内取最大值max_pool2d恰好是它的 GPU 原生等价物高斯模糊则是与高斯核做卷积用conv2d一次搞定。用深度学习框架自带的算子表达传统图像算法这个思路在任何需要 GPU 加速图像处理的工程里都值得借鉴。值得注意的是代码中rescale系列仍然回落到 PIL 实现作者注释直言 CPU works better说明作者不是盲目追求全 GPU而是哪里快用哪里。亮点二批量坐标计算的向量化GPU 版batched_findcontextarea_m用一个精巧的 trick 一次性算出整批掩码的包围盒any_y mask.max(dim2).values 0. # 哪些行有掩码 indices torch.arange(size, devicedevice).unsqueeze(0).expand(B, -1) min_indices torch.where(any_dim, indices, torch.tensor(size, devicedevice)) b_min torch.min(min_indices, dim1).values把有掩码的位置标成索引值、没有的标成极大值再取 min/max就把找包围盒翻译成了两次规约运算避免了逐像素的 Python 循环。配合后面的torch.where处理空掩码返回 -1的边界情况代码既紧凑又健壮。用 where min/max 组合表达条件聚合是向量化编程的经典手法。亮点三用字典当跨节点数据契约STITCHER类型本质就是一个 Python 字典里面同时存了数据canvas_image、cropped_mask_for_blend和元数据cto/ctc 坐标、缩放算法、blend 像素数。这让两个节点解耦得极其干净裁剪节点负责生产契约拼接节点只认契约。中间环节无论插什么模型、做什么 upscale只要最终把图像接回 Stitch 节点契约里的坐标和算法会自动完成缩放与回贴。这种数据 元数据打包传递的模式在 ComfyUI 这类图节点系统中非常实用。避坑与设计取舍读源码时容易困惑的地方为什么裁剪要扩展画布而不是直接裁剪因为强制目标分辨率如 SDXL 的 1024×1024时掩码附近的上下文往往不够大需要越界扩展。直接在原图上越界切片会报错而先造画布、再贴图、再切窗越界像素就有了安放之处拼接时再裁掉即可。这是全项目最核心的取巧之处理解它就读懂了一半。掩码不完全透明是头号坑。README 里反复强调即使肉眼看着是全白的掩码像素值可能只有 250 而非 255导致修复后还能隐约透出原图。mask_hipass_filter就是为了应对几乎为 0 的像素被误当掩码的困惑而加入的——源码的注释语气very confusing to users本身就说明作者踩过坑。为什么 GPU 模式的 rescale 反而用 PIL作者实测发现 PIL 的缩放质量在 CPU 上更好或数值更稳定于是 GPU 版也回落到 CPU 做缩放。这提醒我们GPU 模式不等于所有操作都在 GPU 上以实测效果为准才是工程正道。为什么 Stitch 节点那么小因为最重的计算混合掩码的膨胀与模糊在裁剪阶段就做好了拼接节点只是缩放 加权求和 贴回天然轻量。设计上把重活前置也是性能优化的一部分。动手复现三步跑通最小示例安装插件进入 ComfyUI 的custom_nodes/目录执行git clone https://gitcode.com/gh_mirrors/co/ComfyUI-Inpaint-CropAndStitch重启 ComfyUI。官方工作流文件就在example_workflows/下inpaint_sd15.json、inpaint_flux.json、inpaint_hires.json可以直接拖进画布。搭建最小流程Load Image上传一张图并涂抹掩码→Inpaint Crop Improved→InpaintModelConditioning→KSampler→VAE Decode→Inpaint Stitch Improved→Preview Image。中间无需任何特殊节点这正体现了兼容任意标准采样流程的设计目标。体验关键参数把context_from_mask_extend_factor从 1.2 调到 2.0观察裁出区域变大、模型理解上下文更充分把output_target_width/height从 512 改成 1024SDXL/Flux 场景观察强制分辨率 自动回贴的效果对比device_mode的 CPU/GPU 在批量视频修复场景下的耗时差异README 提到可达 30~100 倍差距。收尾与展望这个项目的价值不仅在于快更在于它把局部修复这件事的工程复杂度全部封装进了两个节点掩码整形、上下文控制、越界扩展、分辨率强制、无缝混合全都成了可配置的参数而对外只暴露一个极简的接口。对用户来说它是高分辨率图像修复、视频抽帧批量修复的提速利器对开发者来说它的策略模式、GPU 算子化、数据契约设计都是值得抄进自己插件里的范本。可以想象的方向还有很多把crop_magic_im的上下文选择策略做成可插拔的注意力驱动模式让模型自己决定看哪里、把 GPU 路径延伸到 rescale 环节彻底脱离 PIL、或者基于现有的 batch 支持做成视频逐帧的流水线并行。无论往哪个方向走这套裁——修——拼的骨架都已经替你打好了地基。关键词清单核心关键词ComfyUI 局部图像修复加速长尾关键词 1Inpaint Crop 裁剪节点原理长尾关键词 2Inpaint Stitch 拼接原理长尾关键词 3ComfyUI inpainting 性能优化备选 H1 标题ComfyUI 局部图像修复加速实战Inpaint Crop 与 Inpaint Stitch 节点源码原理全解如何让 ComfyUI inpainting 提速 30 倍Inpaint Crop 裁剪拼接源码深度解析Inpaint Crop 与 Inpaint Stitch 完全指南从掩码裁剪到无缝拼接的 7 步魔法【免费下载链接】ComfyUI-Inpaint-CropAndStitchComfyUI nodes to crop before sampling and stitch back after sampling that speed up inpainting项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Inpaint-CropAndStitch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考