Qwen Edit Align Composite
Your Qwen edit shifted the whole frame by three pixels. This node puts them back.
- source
- edited
- edit_mask
- composite
- aligned_edit
- mask
- warp_params
Qwen-Image-Edit does not patch your image, it re-renders it. The pixels you didn't ask about come back close to the original, not identical - and "close" is exactly the problem when you want to keep everything except the one thing you changed. Whole-frame offset is the classic symptom; it's the reason half the community workflow posts from late 2025 onward end in "then composite the original back".
Qwen Edit Align Composite is a compositor built for that reality. It measures how far the edit drifted, warps the edit back onto the source, and blends only the region you say changed. Where the mask is zero, the output is your source, bit for bit.
How it works
There's no model call, no patch, no download. It's image registration plus a paste.
The align step converts both images to grayscale, builds a weight map from everything you told it to ignore (edit_mask, the border), and runs a coarse-to-fine fit across a pyramid up to a 1024-pixel longest edge. A phase-correlation guess seeds it, that guess is only trusted if it actually lowers the robust background error, and then a reweighted Gauss–Newton loop refines it. translation fits 2 parameters, affine fits 6 (scale, rotation, shear). Border pixels and masked regions get thrown out of the fit so the edit itself can't drag the alignment.
The edit is then resampled at full source resolution and composited. Mask comes from your edit_mask if you connected one, otherwise from a simple per-pixel difference over a 5×5 average against auto_mask_threshold.
The inputs that matter
source/edited- the original and the Qwen output. Matching batches are allowed; each pair is aligned separately. A single image broadcasts over a batch; any other size mismatch raises rather than silently dropping frames.mode-translationfor the usual small drift,affineif the edit also got slightly bigger or rotated.edit_mask- white selects the edit. Supply it when you already know what you asked Qwen to change; it also gets excluded from the alignment fit, which makes the fit far more reliable. This is the path you want.grow_px(12) andfeather_px(8) - deliberately generous defaults, because the auto-mask is crude. With a realedit_maskyou'll usually pull these down to a few pixels.auto_mask_threshold(0.06) - only used when no mask is connected, i.e. "per-pixel change that counts as edited".warp_params- wire it from the measure node so you're not fitting twice.
Outputs: composite (what you save), aligned_edit (the warped edit on its own - a clean input for the difference-mask node), mask (preview it, always), and warp_params (JSON, reusable).
Install
ComfyUI Manager → search WepeNerd, or:
cd ComfyUI/custom_nodes
git clone https://github.com/WepeNerd/ComfyUI-WepeNerd
python -m pip install -r ComfyUI-WepeNerd/requirements.txt
Restart and hard-refresh the browser. No models, no GPU wheels - the pack leans on Torch that ComfyUI already has, plus Pillow, numpy, SciPy and PyAV. Nodes live under WepeNerd/Qwen Edit Align.
One trap worth knowing before you file a bug: the pack imports PyAV and SciPy at module level, so if you cloned it and skipped the pip step, you don't get a broken video node - you get no WepeNerd nodes at all, and a ModuleNotFoundError in the console. Also, don't stack this pack on the old all-in-one WepeNerd core; that one ships duplicate nodes.
Where people get burned
Flat backgrounds. A sky, a seamless studio backdrop, a fully blacked-out mask: there's nothing to register against, and the node logs a warning and returns zero drift. If your edit looks un-aligned and the console said "no usable background", that's your answer - connect a proper edit_mask or accept the drift.
Assuming it fixes the edit. It doesn't. Alignment is geometric only; if Qwen also recoloured the whole frame or redrew the background, that comes back too. Crop-and-stitch and mask-limited editing are still the standard defence there, and this pack's own docs say the same thing - the fit assumes unchanged, textured background and the same framing.
Snapping masks at random. Preview mask. Big redraws, repeated patterns (tiles, grating, foliage) and local warping can all pull the fit somewhere silly. Feathered edges blend both images, so a sloppy mask shows as a visible seam, not a hard cut.
Parameters from a different size. warp_params are measured for a specific image geometry; the node rescales the translation for a different resolution, but affine terms measured on another aspect ratio will be wrong. Re-measure.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| source | IMAGE | — | |
| edited | IMAGE | — | |
| mode | COMBO | 2 options: translation, affine | |
| auto_mask_threshold | FLOAT | 0.0600–1 | Used when no mask is given: per-pixel change that counts as 'edited'. |
| grow_px | INT | 120–256 | — |
| feather_px | INT | 80–256 | — |
| edit_maskopt | MASK | — | |
| warp_paramsopt | STRING | From QwenEditMeasureShift; re-measured if omitted. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| composite | IMAGE | — |
| aligned_edit | IMAGE | — |
| mask | MASK | — |
| warp_params | STRING | — |