Y7 Klein & Qwen Edit Align
Your Edit Model Moved the Whole Frame — This Snaps It Back
- edited_image
- original_image
- edit_mask
- aligned_image
- valid_mask
- report
Flux.2 Klein and Qwen-Image-Edit don't patch your picture, they re-emit it. Ask for a jacket colour change and you get back a new image that's 99% the same - except the whole thing came back a few pixels off, slightly rescaled, slightly rotated, and a shade redder than what you fed in. That's not a prompt problem, and forcing your input to a multiple of 112 doesn't cure it, though everyone tries that first. It's structural: the model generates a frame, it doesn't composite into one.
Y7 Klein & Qwen Edit Align cleans up that residue. Feed it the edit model's output and the original, get the edit warped back onto the original's geometry and colour-matched to the original's untouched background. No model involved - it's milliseconds on CPU.
What it actually does
Under the hood it's OpenCV, not AI. The grey-scale pair gets CLAHE equalisation first - the edit model has probably changed global lighting or style, and raw SIFT keypoints don't survive that well. Then SIFT finds up to 10,000 features per side, a FLANN ratio test keeps the confident matches, and MAGSAC fits a single homography from edited → original. The original never moves; the edit gets warped into its frame with warpPerspective and reflection padding. OpenCV's RNG is pinned first, so the same inputs give the same homography every time.
The colour pass is the part with a real idea in it. A plain colour-match node reads the thing you just changed - the new blue car - as part of the picture and skews the correction. This one Reinhard-transfers in LAB fitted only on background pixels, then applies that transform to the whole frame. Under 100 usable background pixels it skips rather than fitting a transform to noise.
Background is your edit_mask, or its own coarse detection: blurred LAB delta-E with lightness down-weighted, plus a gradient term for shape changes, thresholded at median + 6×MAD. Coarse on purpose - it only has to pick background.
The inputs that matter
edited_image/original_image- in that order, and they don't have to match size: the original is Lanczos-resized to the edited image's dimensions, so the edited image's size is the output size.two_pass(default on) - the good bit. Pass 1 aligns blindly using the whole frame; then it erodes the detected background mask and re-runs SIFT on background keypoints only, so the edit can't drag the solve. Slower, "noticeably more accurate".color_match_strength- 0 disables the transfer, 1 (default) is full. Try ~0.5 if the background comes back over-corrected.edit_mask(optional, MASK) - white marks the edited region. Overrides the auto-detection for pass 2 and the colour statistics, so use it if you already have one from your edit step.
Outputs are aligned_image (IMAGE - pixel space, so straight to Save or a preview), valid_mask (MASK: zero wherever the warp pulled from outside the frame, those pixels are reflection-filled garbage, so use this mask when you composite) and report (STRING) - wire that into any Show Anything/text node, because you should read it before you trust the output.
Installing it
ComfyUI Manager → Custom Nodes Manager → search Y7 → install → restart. Manually:
cd /ComfyUI/custom_nodes
git clone https://github.com/yushan777/ComfyUI-Y7Nodes
cd ComfyUI-Y7Nodes && pip install -r requirements.txt
The pack's requirements.txt pulls opencv-python-headless>=4.5.0 and color-matcher>=0.5.0. This node only needs the first; color-matcher is for the pack's Color Match (Masked) node. No model downloads - if cv2 is missing, the node tells you to pip install opencv-python-headless.
Where people get burned
Read the report. It prints inliers per pass, the homography determinant, valid coverage, edit-region percentage and whether the colour match ran. Alignment: FAILED means too few matching features; the image comes back unaligned on purpose, which is the right call - a SIFT solve on thin evidence is worse than none (users report SIFT-based alternatives warping the whole frame into a single point when matches are scarce). The node rejects determinants outside 0.2–5.0 and hands you the original instead. Low-texture input is where it fails: blurry tiles, flat sky, gradients.
Other reads: Pass 2: skipped means the edit covers so much of the picture there's nothing left to anchor to, so you're on pass-1 accuracy. Color match: skipped means under 100 background pixels, or strength 0. Determinant near 1.0 means barely any scaling was needed - good, not boring.
Two honest limits: one homography cannot fix uneven local warping (if the model moved one arm, you still need a mask composite), and it does no compositing at all - that's valid_mask's job and yours.
The pack is one guy's toolbox - the README opens with "probably only useful to me" - so expect thin docs and a fast changelog rather than a community. This node landed in 1.0.64. For an exact 1:1 match rather than a background-corrected one, Mozer's ComfyUI-PixelDriftFix is the other node in this space.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| edited_image | IMAGE | The edit model's output, to be aligned and colour-matched. | |
| original_image | IMAGE | The image that was edited. Resized to the edited image's size if they differ. | |
| color_match_strength | FLOAT | 1.000–1 | 0 = no colour match, 1 = full Reinhard transfer from the original's background. |
| two_pass | BOOLEAN | true | Re-align using only unedited background so the edit can't bias the solve. Slower, more accurate. |
| edit_maskopt | MASK | White = edited region. Overrides the automatic detection for pass 2 and colour statistics. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| aligned_image | IMAGE | — |
| valid_mask | MASK | 0 where the warp pulled from outside the frame (filled by reflection). |
| report | STRING | — |