图像分区 · 对齐图差异遮罩
The difference mask that never lets a stray pixel escape the edit zone
- source_local
- generated_local
- target_core_mask
- protection_mask
- editable_support_mask
- automatic_replacement_mask
- bounded_difference_mask
- red_cyan_difference_preview
- report_json
If you've ever done an object swap in ComfyUI - cut a coffee cup out, regenerate the spot with a model like Flux 2 Klein, and then fought the question of which pixels are actually the new object - this is the node that answers it. RegionEditAlignedDifferenceMask takes your before and after crops, compares them pixel by pixel, and hands you back a mask of exactly where they changed. The name is honest: it assumes the two images are already aligned, same resolution, same crop coordinates. Feed it misaligned images and it will happily mark everything as changed.
It's part of the Region Edit Toolkit (Liu-Bot24's ComfyUI-Smart-Removal pack, all 42 RegionEdit* nodes under the "Region Edit Toolkit" menu). In the pack's own smart-removal example it sits right after the local Klein edit pass and before the strict composite: detect target → crop → regenerate → build this mask → paste back.
How it works
The mechanism is refreshingly literal. It computes, per pixel, the maximum absolute difference across the three RGB channels (8-bit values), then keeps any pixel at or above threshold_level. Default 7 means "at least 7 levels of 8-bit RGB change" - which is deliberately low, so it picks up subtle texture changes, not just full object outlines. Then three constraints get applied in a strict priority order:
- The target core always wins. Whatever you marked as the semantic target (via
target_core_mask) is kept regardless of whether the diff caught it. - The difference is clipped to
editable_support_mask. The AI result is only allowed to spread where you said editing is allowed - that's the anti-drift belt around the object. - Protection wins.
protection_maskis subtracted last, so anything you wanted preserved (the cat, the spoon, the background) is untouchable, even if the model rewrote it.
difference_expand dilates the diff (default 4px) so the mask swallows the soft halo most edit models leave at object edges.
The inputs that matter
You'll set three things by hand and pass the rest through from upstream:
source_localandgenerated_local- the original and edited crops, must be identical dimensions or it throws.target_core_mask- from your SAM3 or detection step.editable_support_maskandprotection_mask- your safety rails. Protection that erases the whole target throws an error instead of silently producing nothing, which is the good kind of pedantry.
Outputs: automatic_replacement_mask (what you wire into the composite), bounded_difference_mask (the raw diff before the target core is added back), red_cyan_difference_preview (source in red, generated in cyan - the fastest way to see if your images were actually aligned), and a report_json that counts pixels in every mask so you can tell when a gate ate everything.
Install
ComfyUI Manager: search "Region Edit Toolkit" (package ID native-region-tile-planner-merge), install, restart. Or by hand:
cd ComfyUI\custom_nodes
git clone https://github.com/Liu-Bot24/ComfyUI-Region-Edit-Toolkit.git
Set-Location .\ComfyUI-Region-Edit-Toolkit
& "<ComfyUI 实际使用的 Python>" -m pip install -r requirements.txt
Needs Python 3.10+; deps are numpy, Pillow, scipy, and argostranslate (the last one only matters if you use the offline translation nodes - install it anyway, it's tiny). Search "图像分区" or "RegionEdit" to find the nodes. The pack ships no models - the example workflows expect SAM3 and Klein weights that you point at from your local directories.
Gotchas
The pack is strict by design and this node is the poster child. Misaligned or mismatched crops, an empty target, protection eating the whole target - all hard errors, not silent failures. That's a feature for a pipeline that promises bit-identical compositing, but it means you must keep the source crop and its coordinates in lockstep all the way to the composite. The contract_version string is a version-locked internal agreement; leave it alone unless you know why you're changing it.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| source_local | IMAGE | — | |
| generated_local | IMAGE | — | |
| target_core_mask | MASK | — | |
| protection_mask | MASK | — | |
| editable_support_mask | MASK | — | |
| threshold_level | INT | 71–255 | — |
| difference_expand | INT | 40–256 | — |
| contract_versionopt | STRING | semantic-object-protection-overlap-v2 | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| automatic_replacement_mask | MASK | — |
| bounded_difference_mask | MASK | — |
| red_cyan_difference_preview | IMAGE | — |
| report_json | STRING | — |