Nodes/ComfyUi-MpiNodes/Mpi Grade Back
ComfyUI Node

Mpi Grade Back

Chained Edits Drift Orange — This Grades Them Back

By MadPonyInteractive·Created about a year ago·Updated 4 days ago· 4
Mpi Grade Back
  • original
  • edited
  • image
◄enabledtrue►
◄max_shift4.0►

The problem nobody warns you about

Edit models re-render the entire picture. Every pixel, every pass. That's the deal you accept for "change the shirt and nothing else" - and it's why people who came up on masked inpainting still grumble: unmasked regions come back close to identical, not identical. One edit, nobody notices. Chain five on the same image and the drift has compounded into something quietly warmer, more saturated, no longer matching the plate it sits in.

That's the hole MpiGradeBack fills. Give it the picture the edit was made from and the edit's output, and it undoes the colour nudge while leaving the actual change alone. An added object keeps its own colours - the non-obvious part, and the reason this isn't just "color match to a reference".

How it works

A robust per-channel linear fit, not a palette copy. Over the whole frame it solves original ≈ gain × edited + offset for each of R, G and B - a least-squares line between paired pixels - then applies that map to the edit.

Two things make it more than a regression. Gain is clamped to a sane range (0.2–5), so an absurd fit can't invert the image. And after the initial fit it re-solves three times, each pass dropping pixels whose residual is more than 2.5 standard deviations off in any channel. What the edit changed - a new object, a repainted wall - is exactly those outliers, so it's excluded from the fit instead of dragging the grade toward itself, and keeps its own colours.

Then a guard: it measures the mean correction it applied, in /255, and compares it to max_shift. Under the limit the graded image ships; over it, the edit passes through untouched, because a correction that large isn't drift - it's the night-time or warmer look you asked for. It prints what it measured, too:

[MpiGradeBack] shift 2.41/255 -> graded back

That log line is how you tune max_shift: run it once, read the shifts, decide.

The inputs that matter

All four are required; you only touch two.

  • original - the picture the edit was made from. Framing must match; a different size gets resampled bilinearly onto the edit's, which is a rescue, not a feature. Feed the actual edit input, not a downscale you made for comparison.
  • edited - the edit model's output.
  • enabled - off passes the edit through untouched. Handy as a switch per run instead of a rewire.
  • max_shift (default 4, range 0–255, step 0.1) - the mean correction, in /255, above which the change is assumed intentional and kept. Lower it to be stricter; raise it when you deliberately restyled. At 0 the grading is effectively off.

One output: image - into Preview Image, Save Image, or the next edit. The batch behaves sensibly for once: it fits per frame, and a single-image original is held for the whole batch, so you can grade a run of edits against one plate.

Where it goes in a workflow

Put one at every hop rather than one at the end:

Load Image → Edit → MpiGradeBack(original=Load Image, edited=edit out) → Edit → MpiGradeBack(...)

Each stage compares against what it was made from, so drift never accumulates - you correct a small nudge instead of a large one.

If what you have is a masked composite - a re-render pasted back into a region - this is the wrong node. That's MpiGradeMatch, same pack, fitting on a ring around the mask instead of the whole frame. MpiInpaintHeal is a third, different thing: it moves a fill toward its surroundings, precisely what you don't want for an added object.

Install

No downloads, no pip requirements - the pack runs on what ComfyUI already has. ComfyUI Manager, search ComfyUi-MpiNodes (publisher mad-pony-interactive), or:

cd ComfyUI/custom_nodes
git clone https://github.com/MadPonyInteractive/ComfyUi-MpiNodes
# then restart ComfyUI

Both this and MpiGradeMatch landed in pack version 1.2.20, so update an older checkout before hunting for it. It lives under MpiNodes/ImgOps.

Where people get burned

It can only undo a linear grade. Per-channel gain and offset. A hue rotation, a film-look curve, a contrast S-push - those aren't linear maps, so the node pulls part of them back and leaves the rest. Drift corrector, not a LUT.

A drastic edit defeats the fit. If the edit changed most of the frame - new background, night-time relight - then "the pixels that didn't change" are a minority and there's nothing clean left to fit on. That's what max_shift catches, and why you'll sometimes see "kept (over max_shift)" and think the node did nothing. It did: it decided you meant it.

Grading against the wrong framing. The original is resampled to the edit's size, so a 1024 crop against a 2048 plate works - but nothing checks framing, and a different crop of the same shot gives a confident, wrong fit.

Expecting it to move a fill into place. Colour agreement between a regenerated patch and its surroundings is MpiInpaintHeal. This one needs a paired original of the same shot.

CategoryMpiNodes/ImgOps

Inputs (4)

NameTypeDefaultDescription
originalIMAGEThe picture the edit was made from: the grade reference.
editedIMAGEThe edit's output, same framing as the original.
enabledBOOLEANtrueOff passes the edit through untouched.
max_shiftFLOAT4.00–255Mean correction (/255) above which the change is taken as asked for and kept.

Outputs (1)

NameTypeDescription
imageIMAGE—