Tile Merge
Put the tiles back with no seam and no dark edges
- tiles
- tile_plan
- image
- info
What it does
This is the other half of the round trip. Tile Split handed you a tile-major batch, you pushed it through whatever refiner you wanted, and now this node reassembles it into one clip - in float32, weighted by the plan's windows, with the accumulated weight divided out.
The float32 part is not showing off. Blend the same job in fp16 and you get brightness banding in the overlap bands, which is one of those artefacts that looks like a model problem and is actually an arithmetic problem. And the divide-by-accumulated-weight is what stops the frame edges coming out dark: at the rim there is no neighbouring tile to complement the fade, so the windows cannot sum to 1 there. Rather than special-casing the border - or pretending the problem does not exist - the merge accumulates weight and normalises, so the picture comes out at the right level everywhere.
Inputs and outputs
tiles and tile_plan are required, and the plan must be the same plan Tile Split used. A different plan puts the tiles back in the wrong places, and the node refuses rather than producing a subtly scrambled frame.
scale is the optional one and it earns its place: it is how much the refiner enlarged each tile, 0–8. Left at 0, the node works it out from the tiles themselves - which is correct whenever every tile scaled by the same clean factor. Set it explicitly when the ratio is not a round number.
Outputs are image (the reassembled clip) and info: tiles × frames merged, the output resolution, the scale it used, and a note about the float32 weighting. Read info on your first run - the scale number it reports is the fastest way to find out that your refiner quietly resized something.
Why "no seam" is a claim you can check
The cosine windows are complementary halves: as one tile fades out over the overlap, the next fades in, and the two sum to exactly 1 for every pixel in the band. Not approximately - identically, which is why the pack's own tests pin that identity rather than trusting the algebra. linear blending does not have the property, and that is the difference between a seam you can see and one you cannot.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git
Manager → "CustomNodePacks" is equivalent. Restart and look for:
[C2C] CustomNodePacks: 142 nodes loaded (...) - 0 failed
Nothing here needs a model or a GPU-specific dependency; the pack's shared three packages are all the tiling family touches. Install them by hand rather than running the requirements file over ComfyUI's torch:
pip list | grep -i "opencv\|scipy\|safetensors"
pip install opencv-python>=4.7.0 scipy>=1.10.0 safetensors>=0.4.0
Where people get burned
- Count mismatch. "N images came back but the plan has M tiles, which does not divide evenly." Something in the middle changed how many images there are - a trim, a batch-slice, a node that dropped a frame. Fix the middle, do not fight the merge.
- Aspect changed. If the two axes came back at different ratios (say 1.5x wide, 1.4x tall), the merge raises instead of guessing. Either make the refiner preserve aspect or state
scaleyourself. - Wrong plan. Using a plan from a different resolution is the single easiest way to get a wrong-but-plausible image. The plan is a value; pass the same one to both ends.
- A stitched result is not a faithful one. Merging removes seams, not differences: if tile A was refined more aggressively than tile B, the blend hides the edge and leaves the disagreement. If you want the model's detail without letting anything move, the pack's Identity Lock node in the same family exists for exactly that - keep the plate's low frequencies, take only the high ones.
- Static is fine, crawling is not. Because one plan is reused for the whole clip, the seams do not move between frames. If you do see crawling, you have ended up with two different plans somewhere in the graph - the pack's own doc calls this out as the reason the plan is a passed value rather than something each node recomputes.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| tiles | IMAGE | — | |
| tile_plan | TILE_PLAN | — | |
| scaleopt | FLOAT | 0.000–8 | How much the refiner enlarged each tile. 0 means work it out from the tiles themselves, which is right when every tile scaled by the same clean factor. Set it explicitly if the ratio is not a round number. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| info | STRING | — |