🔄 AffineTransform2img
Putting your design on a screen without re-rolling img2img
- background_image
- source_image
- mapped_image
- cropped_screen
- screen_mask
Want to see your design on a laptop screen, a book cover, or a storefront before you generate anything else? This is the deterministic way to do it. PerspectiveScreenMapper is the second half of ComfyUI-AffineImage: you hand it a background image, a source image, and four corner points, and it does a real perspective transform to place the source exactly inside that quadrilateral. No prompt roulette, no img2img drift - just geometry.
Screen mapping is only the demo. Any four-point surface in a photo - a billboard, a wall, a picture frame, a phone face-down on a table - works the same.
How it works
Under the hood it's plain OpenCV. The source image's four corners (top-left, top-right, bottom-right, bottom-left) are mapped to your four target points via cv2.getPerspectiveTransform, the warp is applied with a transparent border, and a polygon mask is built from the target quad. Then it composites using one of four blend modes.
That's it. This is the "cheap, fast, exact" end of the compositing spectrum - the thing the KB files call infrastructure rather than a topic, because once it works you just use it.
Inputs that matter
background_image- the photo with the surface you're mapping onto.source_image- the content being placed.four_points- a STRING. This must come from the selector node'sfour_pointsoutput; it's a JSON string of coordinates, not something you eyeball.blend_mode-replace,overlay,multiply, orscreen(defaultreplace).opacity- 0 to 1, but read the trap below.crop_to_screen- default on; also returns the mapped region cropped to the quad's bounding box.
Outputs are mapped_image (the full composite), cropped_screen (the mapped region alone - handy if you want to feed it to a detailer), and screen_mask (the quad as a MASK).
Installing it
Same pack as the selector, so installing one installs both. Use ComfyUI Manager (search ComfyUI-AffineImage) or:
cd ComfyUI/custom_nodes/
git clone https://github.com/GuardSkill/ComfyUI-AffineImage.git
cd ComfyUI-AffineImage
pip install -r requirements.txt
Restart ComfyUI. Dependencies are opencv-python, pillow, and numpy - no models, no GPU installs beyond what ComfyUI already needs.
Where people get burned
- The silent no-op is the big one. If
four_pointsisn't a valid four-point JSON, the node prints "needs 4 points" to the console and returns the background image untouched. No red node, no error toast - it just looks like nothing happened. If that's you, re-run the selector and make sure all four points are set, then check the wire. - Point order strikes again. The warp assumes the same top-left → top-right → bottom-right → bottom-left order you clicked in the selector. Rotated or mirrored output means the order drifted.
opacitydoes nothing inreplacemode. The code only applies it in the overlay/multiply/screen path. If you want to fade the paste, switch offreplace- a surprisingly easy thing to stare at and wonder why the slider isn't working.replacehard-cuts the quad edges, so seams show. Feather the mask or run a color match (ComfyUI'sColor Match Imageis the right tool) so the pasted region sits in the surrounding light.- The warp is linear interpolation, so mapping a small source onto a big area comes out soft. Up-scale the source first if it's going to stretch.
The workflow shape people land on: map the design in, then take cropped_screen or screen_mask into an inpainting/detailing pass to restore reflections, shadows, or foreground that the paste covers - that's exactly what the pack's "add hands" example does. The mapper isn't the node that makes the scene convincing; it's the node that makes the placement exact, so you only have to fake the lighting, not the geometry.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| background_image | IMAGE | — | |
| source_image | IMAGE | — | |
| four_points | STRING | — | |
| blend_modeopt | COMBO | replace | 4 options: replace, overlay, multiply, screen |
| opacityopt | FLOAT | 1.000–1 | — |
| crop_to_screenopt | BOOLEAN | true | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| mapped_image | IMAGE | — |
| cropped_screen | IMAGE | — |
| screen_mask | MASK | — |