A technical comment of our tiling pipeline, the decisions behind it, and where the gap with SeedVR2 actually comes from

Tested as of June 2026.
Diffusion models have a resolution ceiling, and most people building upscaling pipelines hit it before they fully understand what’s happening.
When you train a model on 512×512 images, that’s the world it learns to work in. Feed it a 4K photograph, and things start going wrong in ways that are hard to pinpoint at first: textures that repeat where they shouldn’t, details that look slightly off, and the overall image holding together on the surface but falling apart on closer inspection.
Tiling is how you work around this. Not a perfect fix, but the most practical one available.
The Resolution Wall
Most modern image generation models, including FLUX.1 and FLUX.2, are trained somewhere between 512×512 and 1024×1024. They handle higher resolutions better than older models did, but feeding them a 3000×4000-pixel photograph and expecting clean output is still asking too much.
For upscaling, this creates a specific bind. You have a source image. You want it at 2× or 4× the original size. You can’t run it through a diffusion model at full output resolution. So how do you actually get there?
You cut it into pieces.

How Tiling Works
The divide-and-conquer approach sounds almost too simple when you first hear it — and then you spend a week dealing with seams and color drift and realize there’s more going on.
Here’s the pipeline. You start by upscaling the source image with something conventional — Lanczos, basic ESRGAN, whatever gets you to the target resolution quickly. The result is large but flat: the right size, no real detail. Then you split that image into overlapping tiles, each small enough to sit comfortably within the diffusion model’s native range. Each tile goes through the model separately, which is where the actual texture and detail gets added. Then you stitch everything back together, blending the overlapping edges so the joins don’t show.
When it works well, you get something that reads as genuinely high-resolution — not a stretched original. Our pipeline for this benchmark is built on exactly this pattern, using the ComfyUI_Steudio implementation as the foundation.
The Model Inside the Loop
The tiling structure itself is fairly standard. What we changed — and what ended up mattering most — was which model sits inside that loop.
The default choice in pipelines like this is FLUX.1 Dev, running img2img. You hand it a tile, ask for a refined version, and it adds noise, denoises with guidance, and returns something sharper. The logic makes sense on paper. The issue shows up in practice.
img2img is not designed to preserve what it’s given. It’s designed to generate. The noisy intermediate representation it works with gives the model room to invent — and it takes that room. Across a single tile, the changes might look fine. Across dozens of tiles assembled into a full image, the accumulated reinventions start to show: colors that drifted from the original, highlights that contradict the source lighting, texture that the model decided should look different. For stock photography, where the whole point is delivering the original scene at higher quality, that’s a problem you can’t work around.
Why We Switched to FLUX.2 [klein]
FLUX.2 [klein] is an image editing model — and that’s a different thing than a generation model, even if the outputs can look similar from the outside.
Image editing models are trained to make specific changes while leaving everything else alone. The underlying training says: here is the source, respect it, modify only what’s asked. Generation models are trained to produce something good from a noisy starting point where the source is a suggestion, not a constraint. When you swap one for the other inside a tiling loop, you feel the difference immediately. The editing model stays close to the original. It adds detail where detail belongs. It doesn’t decide the sky should be a slightly different shade of blue.
We replaced FLUX.1 Dev with FLUX.2 [klein] in the tile-processing step, kept everything else the same, and the outputs got noticeably more faithful while still showing real improvement in sharpness and texture. That’s exactly what an upscaling pipeline should do. As a bonus, FLUX.2 [klein] runs in 4 inference steps, which adds up to a real time difference when you’re chaining through tile after tile.
Color Matching: The Unglamorous Part That Actually Matters
Here’s something that doesn’t appear in architecture diagrams but quietly accounts for a big chunk of perceived quality: color drift between tiles.
Even a well-behaved image editing model introduces subtle variation from tile to tile. The color temperature shifts slightly. Saturation creeps up or down. Over a single tile, you’d never notice. Over a full assembled image with gradients like skies, skin tones, or smooth surfaces, that variation turns into visible banding. The joins become visible not because the shapes don’t align, but because the tones don’t.
The fix is to measure the color distribution of each output tile and match it back to its original before stitching. It’s a histogram correction, not a clever algorithm. But without it, the seams find their way back in. With it, the assembled image holds together tonally from one edge to the other.

Where We Landed vs. SeedVR2
Honestly: behind.
Our pipeline outperformed the FLUX.1 Dev baseline. Against SeedVR2, it didn’t compete. The benchmark numbers tell the story plainly — SeedVR2 won on naturalness (91% vs. 1%), edge sharpness (83% vs. 5%), detail recovery (76% vs. 5%). Full results and methodology are in the benchmark. More faithful than raw img2img, yes. But not in the same league as a model built from the ground up for exactly this task.
SeedVR2 is a video restoration model by ByteDance, trained specifically on recovering detail in degraded footage and images. It has seen what detail recovery is supposed to look like — millions of times over, at the level of individual training examples. Our pipeline uses an image editing model that was optimized for a broader job and then pointed at upscaling. Related tasks, but not the same one.
There’s one exception that’s genuinely worth flagging. On AI-generated texture close-ups, where there is no original detail to recover in the first place, our pipeline occasionally came out ahead.. SeedVR2 is a restoration model: when there’s nothing real to restore, it loses its anchor. An image editing model that’s comfortable generating plausible detail handles that gap differently. It’s a narrow case, but it’s a real one, and it points at something meaningful about when restoration logic helps and when it doesn’t.
It’s a narrow case, but it’s a real one, and it points at something meaningful about when restoration logic helps and when it doesn’t. If you’re thinking about where either model fits into an actual content pipeline, we covered that separately.
What a LoRA Could Change
The gap is real, but it’s not structural.
FLUX.2 [klein] was never trained on upscaling data. It’s a capable image editing model doing a job it’s well-suited for but wasn’t specifically prepared for. It has never been shown a paired example of low-resolution tile in, high-resolution recovery out. That gap in training is exactly where a LoRA fine-tune would land.
A LoRA trained on paired upscaling examples would give the model a clear picture of what it’s actually being asked to do: add detail, preserve the source, stay close to the original. Image editing models tend to respond well to this kind of targeted adaptation because their base behavior already points in the right direction. You’re not fighting the model. You’re just giving it a more specific job description.
We haven’t run that experiment yet. But given how well LoRA adaptation has worked on similar tasks like inpainting, texture recovery, and controlled detail synthesis, the expectation is meaningful improvement.
The tiling architecture is solid and the color matching is working. The model inside the loop is what still has room to move.