Pixel Snapping (SIFT)
Line up two images without hand-placing a single point
- reference_image
- target_image
- target_mask
- stitched_image
- mask
- corrected_target
You've got two photos of the same scene that overlap, or a re-rendered crop that has to sit back on its original, and the thought of dragging one image pixel-by-pixel into place makes you want to quit. That's the job this node exists for. It doesn't generate anything and calls no API - it finds matching texture in both images, works out the transform between them, and stitches them together. No model download, no seed, usually under a second.
Pixel Snapping (SIFT) is one of five nodes in the ComfyUI_pixel_snapping pack, and it's the one doing the cleverest work. Where most alignment tools assume a simple translate-and-scale, this one estimates a full affine transform - rotation, skew, and even non-uniform scaling - which is exactly the case you hit when a scan, a phone photo, or an AI-generated crop is slightly warped relative to your base image.
How it works
The mechanism is classic computer vision, and the node is refreshingly honest about it. It converts both images to grayscale and runs SIFT to detect distinctive keypoints (up to max_features, default 5000). Those keypoints get matched with FLANN, and Lowe's ratio test uses match_ratio (0.75) to keep only unambiguous matches. Then RANSAC - with ransac_threshold in pixels, default 5 - fits an affine matrix to the good matches, and there's a refinement pass that drops the worst 20% of inliers by reprojection error and refits with a more robust estimator.
The interesting bit: if the width scale and height scale differ by more than 0.6%, it decides your target has non-uniform scaling distortion, stretches it, and re-runs the whole match. It'll retry up to ten times before giving up, and it needs at least 80 solid matches to be happy. All of this chatter lands in the console - you'll see a small essay per attempt, which is great for debugging and overwhelming otherwise.
The inputs that matter
reference_image- your base image (what the target gets aligned to).target_image- the image that gets warped.max_features,match_ratio,ransac_threshold- the three knobs you'll actually touch when it fails. More features and a looser ratio help when the images share little texture.target_mask(optional) - limits the output mask to a region of the target, so you control exactly where the overlap counts.mask_grow,mask_blur,invert_input_mask,invert_output_mask- post-process the mask the node emits. Blur is the one worth setting for a soft seam.
Outputs
stitched_image- a canvas holding both images with the overlap included once. Wire this to a preview or save.mask- where the target sits, in original-image coordinates, after any grow/blur/invert. Feed it to a composite if you want to do your own blending.corrected_target- the target after its distortion was corrected (before warping), useful if you want the aligned result without the panorama.
Install
The pack installs like any custom node. Via ComfyUI Manager, search for "Pixel Snapping". Or:
cd ComfyUI/custom_nodes
git clone https://github.com/flywhale-666/ComfyUI_pixel_snapping
cd ComfyUI_pixel_snapping
pip install -r requirements.txt
Then restart ComfyUI completely - the README is explicit that a page refresh isn't enough after this pack changes its node ports. The one dependency to know about is opencv-contrib-python: SIFT lives in the contrib build of OpenCV, so if a node complains about cv2.SIFT_create missing, that's what's wrong.
Troubleshooting
- "Feature points insufficient" - the images share too little texture, or one is blurry. Raise
max_features(say 8000–10000), loosenmatch_ratiotoward 0.85, and bumpransac_threshold. If two images genuinely have nothing in common, no parameter saves them. - It only processes the first image of a batch, silently. If you feed it a video frame stack expecting per-frame alignment, you get one output.
- A huge mismatch in exposure can sink SIFT before it gets to color - matching the exposure first, or running this pack's Powerful Color Alignment afterwards, fixes the two problems in sequence.
It's a quiet, no-drama utility node, the kind that earns its keep in an automated batch rather than a showcase. Pair it with the mask crop/restore pair in the same pack when your "re-crop and re-render" loop drifts out of alignment.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| reference_image | IMAGE | — | |
| target_image | IMAGE | — | |
| max_features | INT | 5000100–20000 | — |
| match_ratio | FLOAT | 0.750.1–1 | — |
| ransac_threshold | FLOAT | 5.01–50 | — |
| invert_input_mask | BOOLEAN | false | — |
| mask_grow | INT | 0-50–50 | — |
| mask_blur | FLOAT | 0.00–50 | — |
| invert_output_mask | BOOLEAN | false | — |
| target_maskopt | MASK | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| stitched_image | IMAGE | — |
| mask | MASK | — |
| corrected_target | IMAGE | — |