Nodes/koo-nodes-pack/KoO Tile Merger
ComfyUI Node

KoO Tile Merger

Stitching Tiles Back Together Without a Grid of Seams

By kooailab·Created 15 days ago·Updated 4 days ago· 0
KoO Tile Merger
  • tiles
  • image
◄metadata—►
◄blend_mode▾►
◄color_matchtrue►

Tiled upscaling is easy to start and annoying to finish. You chop a 2K image into 512px squares, push them through a sampler, and then you're standing in front of a pile of tiles with a 4×4 grid burned into the result - tile eleven is two shades darker than tile twelve, and every join is a hard edge.

KoOTileMerger does the last ten percent. It reassembles the tiles into one image using a feathered weight ramp and, optionally, per-tile colour statistics matched to what's already on the canvas. It's the back half of a pair, and it only works with metadata the KoO Tile Splitter produced.

Why this exists

Tiling is the "arbitrary output size on limited VRAM" branch of upscaling: overlapping crops, diffusion on each, blend the overlaps. Every implementation lives or dies on that blend. Ultimate SD Upscale gets recommended for exactly this, and the most common complaint in every thread about it is visible seams.

A generative sampler also shifts brightness and hue slightly per tile - different noise, different distribution, not a bug. Paste and you see it. Cross-fade and you mostly don't. Cross-fade and match colour and you really don't.

How the merge works

It's a weighted accumulation, in source order.

The node reads the metadata JSON - original size, padded size, tile size, overlap, feather, channel count, and each tile's x/y position - allocates an empty canvas at the padded size plus a parallel weight accumulator, then walks the tiles.

For each it builds a mask: full weight in the middle, ramping down over the feather width recorded in the metadata, shaped linearly or as a raised cosine (the cosine eases off at both ends, so the join is less perceptible). Tile × mask goes into the canvas; the mask goes into the accumulator. At the end, canvas ÷ weight gives a normalized average - that's what makes overlaps blend instead of double-exposing.

color_match is the extra bit. Before a tile is accumulated, the node compares it against whatever's already composited in its footprint: mean and standard deviation per RGB channel. It shifts and scales the incoming tile to match. The first tile is untouched; everything after gets pulled toward what's established. That ordering is why a very large grid can show a slight gradient instead of hard steps, which is a much easier thing to live with.

Finally the canvas is cropped to the original width and height, discarding the splitter's padding.

Inputs and outputs

tiles is an IMAGE batch - the whole stack at once, not one at a time. Order matters absolutely.

metadata is a STRING with a forced input. You can't type it or paste a path; it has to come from the splitter's metadata socket. If you lost it, re-run the splitter.

blend_mode is linear, cosine or none. Cosine is the smoother of the two; linear is fine and does not pretend otherwise. none is hard-paste mode - later tiles overwrite earlier ones inside their footprint, no feathering and no colour matching. Useful only as a diagnostic when you want to see exactly where the boundaries are.

color_match toggles the statistics matching. Default on. It only touches the first three channels, and it's skipped entirely when blend_mode is none.

The single output is image: one image, batch size one. Into a preview, a save, or another splitter if you're going up again.

Install

Manager, searching koo-nodes-pack (publisher KoO.Ai; registry availability depends on moderation approval per the README). Otherwise:

cd ComfyUI/custom_nodes
git clone https://github.com/kevintronchin-blip/koo-nodes-pack

Restart, then hard-refresh the browser. Nothing to download: requirements.txt lists only torch, numpy, Pillow and aiohttp, all of which ComfyUI provides.

Things that go wrong, and why

"tile count mismatch: metadata expects 20, got 18." The metadata describes a specific batch. If your sampler dropped, duplicated or reordered tiles, the merge refuses rather than producing a mystery image. That's the good kind of error. Re-split and keep the batch intact.

"tile size mismatch" means an upscale node slipped into the middle of the chain. Coordinates in the metadata are padded-image pixels, so the merger wants tiles at exactly tile_size. Resize after the merge, not between split and merge.

Faint seams anyway. Colour matching equalizes brightness, not content. If your sampler invented a different window on each tile - too few steps, a prompt that reads differently per crop - no blend fixes that. The cure is upstream: fewer tiles, more overlap, more steps.

And because the category name will mislead somebody: this is not Ultimate SD Upscale. No ControlNet, no built-in sampling loop - you wire splitter → sampler → merger yourself, and in return you get a merge stage you can see and control.

CategoryKoO/Magnific

Inputs (4)

NameTypeDefaultDescription
tilesIMAGE—
metadataSTRING—
blend_modeCOMBO3 options: linear, cosine, none
color_matchBOOLEANtrue—

Outputs (1)

NameTypeDescription
imageIMAGE—