Measure softening and colour creep across AI edit passes in Pillow

Test the no-drift claim on your own photos: edge sharpness and a white-patch colour reading for each pass of an edit chain, in short Python with Pillow.

5 min readSume
All posts

To check whether repeated edits degrade a picture, measure two things on every pass: how sharp the edges are and what colour a patch that should stay white has become. Ideogram's page for 4.5 promises that "the tenth pass looks as clean as the first, with no creeping color shift", and Black Forest Labs says its Flux 3 Image leaves untouched pixels unchanged across steps. Both are vendor claims; the script below gives you your own numbers from your own chain.

What the script measures

Pick a patch that no edit is meant to touch, such as a white wall corner or a grey card. Save every pass as PNG so the measurement is not about JPEG compression.

  • Sharpness: the mean of a Pillow FIND_EDGES filter over the grayscale image, shown as a ratio to the original. A soft image has fewer strong edges, so the ratio falls.
  • Colour creep: the mean red, green and blue of a patch you choose over a white or grey area. A drift toward cream or blue shows as the three numbers separating.

The code

Run it as python drift.py original.png pass1.png pass2.png. It needs only Pillow.

import sys
from PIL import Image, ImageFilter, ImageStat

def sharpness(path):
    gray = Image.open(path).convert("L")
    return ImageStat.Stat(gray.filter(ImageFilter.FIND_EDGES)).mean[0]

def patch_rgb(path, box):  # box = (left, top, right, bottom) over a white area
    patch = Image.open(path).convert("RGB").crop(box)
    return tuple(round(v, 1) for v in ImageStat.Stat(patch).mean)

def report(paths, box):
    base = sharpness(paths[0])
    for i, p in enumerate(paths):
        print(f"pass {i}: sharpness {sharpness(p) / base:.3f} of original, "
              f"white patch RGB {patch_rgb(p, box)}")

if __name__ == "__main__":
    # python drift.py original.png pass1.png pass2.png
    report(sys.argv[1:], (10, 10, 60, 60))

Reading the numbers

A ratio near 1.000 across passes means the edit chain holds sharpness. A steady fall, say 0.98, 0.95, 0.91, is the softening that Morphic's page describes as what happens when a model redraws the frame each round. Edge energy also changes when an edit adds an object with edges of its own, so measure a crop that contains no change if you want a clean read.

What each reading means for a chain (read 2026-10-07)
ReadingLooks likeWhat to try
Sharpness ratio falls each passThe model redraws the whole frameEdit a crop and stitch it back
White patch RGB values separateColour cast building upReset from the original; re-run fewer passes
Both steadyThe chain holdsKeep the model; verify on more photos
Jump on one pass onlyOne bad editRe-run that pass, not the chain

Make it a habit

Plot the sharpness ratio by pass number for each model; three lines on one chart tell the story faster than a table. Keep the numbers in a CSV, one row per model, photo and pass, so a later model can be added without redoing the old ones. Record the prompt text and the date next to each row; a model that is silently updated behind the same id will show up as a change in a row you have not touched.

Run the same script on five photos for each model you are considering, with the same prompts, and keep the outputs. It costs little: five photos through three passes on Ideogram 4.5 is 15 images, $0.5625 at the low tier on Sume at $0.0375 each. For measuring what changed outside the edit area, use the pixel diff recipe; for the file-format side of drift, see saving PNG between passes.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume