Nodes/comfyui-OreX/⛓️‍💥 Image Tile Stitch (OreX)
ComfyUI Node

⛓️‍💥 Image Tile Stitch (OreX)

Gluing your upscaled tiles back together without a visible grid

By orex2121·Created 2 years ago·Updated 7 days ago· 59
⛓️‍💥 Image Tile Stitch (OreX)
  • images
  • dac_data
  • image

Image Tile Stitch is the second half of a tiled upscaling workflow, and it does the one job that matters: take the tiles a model just re-rendered and put them back into a single image with the seams blended instead of showing. You'd reach for it when your upscale - a 4x ESRGAN, SeedVR2, a diffusion pass with ControlNet Tile, a detailer - can only handle a window smaller than your target resolution. Tiling is still the standard answer when VRAM is the wall: as our upscaling notes put it, it buys "arbitrary output size on 6GB," and the tile condition is what stops the tiles diverging.

Honest framing first: if you don't need it, don't. Tiling is a workaround, it's slower than one pass over the whole image, and on a modern card the built-in tiled paths in modern upscale nodes (SeedVR2's, for one) have eaten a lot of this niche.

What it pairs with

It only works with ⛓️‍💥 Image Tile Split (OreX), the same pack's splitter. Split does the thinking: it calculates a target resolution from your source aspect ratio, upscales (optionally with an upscale model from ComfyUI/models/upscale_models), cuts the result into overlapping tiles, and hands out a TILE(S) list. You drop whatever you like in the middle - a KSampler, an upscale model, a face detailer - then feed the results back to Stitch.

That's the whole reason it's two nodes instead of one (Ultimate SD Upscale does both halves internally): the middle is yours.

How it actually works

Stitch doesn't guess anything. It reads the layout map passed in dac_data - upscaled width and height, pixel overlaps, grid size, tile order - and rebuilds the exact coordinate list the splitter generated, which is why the last row and column get pinned to the far edge instead of running off the canvas.

For each tile it builds a grayscale mask in PIL: solid 255 in the middle, with the shared overlap regions inset by a quarter of the overlap width and height, then blurred before use - a Box blur for overlaps 64px or narrower, a Gaussian blur for wider ones. Then it composites:

output[:, y:y+tile_height, x:x+tile_width, :] *= 1 - mask
output[:, y:y+tile_height, x:x+tile_width, :] += tile * mask

That's a running weighted average: in the strip where two tiles meet, the left tile fades out as the right one fades in, and wider overlaps get the smoother falloff. The canvas keeps the dtype, device and channel count of the incoming tiles, so a 4-channel stream stays 4-channel.

Inputs and outputs

Only two inputs, and you don't set either by hand.

  • images (IMAGE) - the processed tiles. This input is list-native (INPUT_IS_LIST), so you wire the splitter's TILE(S) output (or a Load Image Batch style list) straight in; ComfyUI passes the whole list and the node stacks it. Order matters - the list must arrive in the order the splitter emitted it, because the coordinates are re-derived, not stored per tile.
  • dac_data (DAC_DATA) - the layout map, wired straight from the splitter's dac_data output. Never edit or re-route it; it's what the two nodes agree on.

The single output is image (IMAGE) - one stitched tensor, ready for Save Image, a final resize, or another pass.

Install

ComfyUI Manager → search the pack title (Orex Nodes, publisher orex), or by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/orex2121/comfyui-OreX
# restart ComfyUI

The tile nodes need nothing beyond numpy, torch and Pillow, but the pack's requirements.txt is a kitchen sink - mediapipe, modelscope, opencv-contrib-python, pymatting, lmstudio, audiotsm, plus an open-ended transformers>=4.43.2. If you only want the tile pair, install Pillow by hand and skip the file; if Manager pulled everything in and your environment got weird, that's why. The README also tells existing users to delete the folder from custom_nodes and install fresh rather than updating over the top.

Common issues

"Image Tile Stitch expected N tiles, but received M." This is the failure you'll actually hit: the count coming back doesn't match grid_x * grid_y. Usual causes are a node in the middle changing the count (a batching node that merged tiles into one image, a detailer that dropped frames), or the splitter's tile widget left on a single-tile number. tile = 0 means all tiles, which is what Stitch wants.

Seams are still visible. The blend is a feather, not a magic eraser. If the tiles genuinely diverged in content - different noise seeds, no tile ControlNet holding each one to the source - you get a soft-edged patchwork. Fix it upstream, not here.

It won't connect to Steudio's Divide and Conquer. It won't, and it shouldn't: dac_data is this pack's own private type, the same context-type lock-in every pack that invents a data bus takes on. The file header credits Steudio's Divide and Conquer as the origin - and says GPLv3, which is the one to believe when pyproject.toml says MIT.

CategoryOreX/Image

Inputs (2)

NameTypeDefaultDescription
imagesIMAGE—
dac_dataDAC_DATA—

Outputs (1)

NameTypeDescription
imageIMAGE—