Element Tile Merge
Where tiled upscales get their seams, or lose them
- tile_images
- grid
- tile_sources
- original_image
- IMAGE
Seams are the tax on tiled upscaling. Two tiles sampled independently will disagree slightly - a brightness step, a colour shift, a texture that stops dead at an invisible line - and your eye finds it instantly even when you can't name it. Element Tile Merge is the node that decides how gracefully that disagreement gets hidden. It's the back half of the split workflow: Element Tile Split (or a sampler run over its outputs) gives you decoded tiles, this puts them on one canvas.
If you're using Element Tiled Upscale, you already have a merged image and don't need this. Anyone running the split → KSampler → decode chain needs it, and so does anyone who wants to re-blend the same tiles with different settings without resampling.
How it works
It doesn't do anything clever with content. It builds a weight map per tile - a 2-D ramp made from two axis ramps, with the fade width on each internal edge scaled by feather - then accumulates tile × weight and weight onto a full-size canvas and divides at the end. Outer edges of the image get replicated rather than faded, because there's no neighbour there to blend with. The result is a weighted average, and anywhere two tiles overlap you get a smooth crossfade instead of a hard cut.
It does need honesty about geometry: tile_images must be the decoded tiles in the order the grid was built, and grid must come from that same run. The grid carries each tile's rect and fade widths, so a stale one puts tiles in the wrong place - the classic "why is my image scrambled into rectangles" failure.
What you set
feather runs 0 to 1, default 1. This is the width of the crossfade as a fraction of the overlap, so 1 means use the whole overlap as a ramp. Turn it down and the transition gets tighter - feather at 0 gives you hard-edged tiles, which is exactly what you want if you're compositing something deliberate and awful everywhere else. For an upscale, leave it at 1.
tile_sources is the optional one people miss. Feed it the source crops - Element Tile Split's tile_sources output is built for precisely this - and Merge can compare each generated tile against what that region used to look like. That's the input for the next parameter, and without it colour matching does nothing.
color_match_strength at 0 is off, which is the default. Above 0 it does a channel-wise mean/std transfer per tile toward the corresponding source crop: tone and colour get pulled back to the original while the generated detail stays. The author applies it more strongly near tile edges than in the tile's centre, which is the right instinct - that's where mismatches show. This is the fix for the FLUX.2 klein problem of a slight colour cast on upscales, and it's cheap insurance generally. Push it too far and you'll flatten the contrast the model just added, so 0.3–0.6 is a saner range than 1.0.
Output
One thing: IMAGE, the assembled canvas. Save it, or feed it into a final sharpening pass, or back into a second, gentler tiled run if you're the type who does that.
Install
Manager → ComfyUI-Element_TileEdit. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/supElement/ComfyUI-Element_TileUpscale
Restart. Nothing to install beyond ComfyUI itself - the pack has no requirements.txt and declares no runtime dependencies.
Where it bites
Feather blend is a cosmetic fix, not a consistency fix. If two tiles genuinely disagree about what's in the frame - different nose, different shirt, different window - crossfading just means the disagreement fades in and out over 96 pixels instead of stopping dead. This is the reason tile upscaling on plain models needs something like ControlNet Tile to keep tiles honest, and the reason this pack bothers with reference latents in the first place. Merge can only smooth what the sampler already agreed on.
Second, the colour-match path is doing per-tile statistics, so it inherits the usual limits of that trick: a tile that's almost entirely one colour - sky, wall, shadow - is exactly where mean/std transfer is least reliable, and a heavy color_match_strength there can go flat or banded. If one region looks wrong after a pass with colour matching on, set it to 0 and compare before you blame the sampler.
Third: because tile order is load-bearing and the grid travels on a typeless custom socket, hand-rewiring is where things break. Reuse a cached decode from an older run and you'll get a scrambled canvas nobody debugs correctly the first time.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| tile_images | IMAGE | — | |
| grid | ELEMENT_TILE_GRID | — | |
| feather | FLOAT | 1.000–1 | — |
| color_match_strength | FLOAT | 0.400–1 | — |
| tile_sourcesopt | IMAGE | ... | |
| original_imageopt | IMAGE | ... | |
| high_low_freqopt | BOOLEAN | false | Enable high-low frequency fusion: use feathered weights to smooth the transition for low frequencies, and competitive weights to preserve details for high frequencies—preventing details in overlapping regions from being flattened out through averaging. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |