Prompting

Image editing with masks and references

Send one real photo, a mask, a reference mug and an instruction through gpt-image-1.5, then diff every result against the original. Eight recorded edits show a tight mask still letting 7 to 9 percent of the rest of the photo change, a loose mask letting the model rework the laptop, and pasting the masked region back as the only way to keep the rest exact.

Recorded edit
Run
Show
Loading 3D view

Four planesAn image edit stacks four planes: the photo, a mask painted where change is allowed, a reference picture and the instruction, all to swap one white mug and leave the desk alone.

Narrated with James Phoenix's AI voice.

Tight maskrun 1
Edit
76.6%
Mug area changed
9.3%
Rest of photo changed
Succulent40.2%
Most changed object
gpt-image-1.52026-09-11
Recorded with

Tight mask, 3.5% of the frame: 76.6% of the mug area changed, and so did 9.3% of the photo outside it, most in the succulent (40.2% of its pixels).

An image edit sends a model more than a sentence. OpenAI's image edit endpoint takes the photo to change, an optional mask whose transparent pixels mark where change is allowed, optional reference images, and the instruction. The film stacks those four as glass planes on the left, joins them into the editor in the middle, and prints each recorded result onto the easel on the right, where every changed pixel is painted over it: green where the change was allowed, red where it was not.

Everything in the film is real. A source photo of a desk (a white mug, a closed laptop, a notebook and a succulent) and a reference picture of a blue enamel mug were generated first. Then eight edits were recorded on 11 September 2026 with `gpt-image-1.5` at 1536 by 1024 and quality high: two runs each of a tight mask round the mug, a loose mask over a fifth of the frame, no mask at all, and the tight mask with the reference mug as a second image. The instruction asked for the mug to be replaced and for everything else to stay exactly the same. Each result was diffed against the source in code, and every number on screen is a measured share of changed pixels.

Pick a recorded edit and a run while the film is paused, and switch between the result and its changed pixels. The slate reads two shares: how much of the mug area changed, which is the edit you asked for, and how much of the rest of the photo changed, which is drift. The inset above the easel zooms on one object before and after.

The surprise is how little the mask protects. With the tight mask, 7 to 9 percent of the photo outside it changed visibly, and at a faint threshold of 12 out of 255, half to 70 percent of it moved. The succulent came back with different leaves. The model redraws the whole image and the mask steers where it aims rather than fencing anything off. With no mask at all, the rest changed by 4 and 8 percent, no worse than with the tight mask. The reference mug made the new mug match what was wanted and drifted least, at 5 and 6 percent, but still not zero.

The loose mask is the failure mode. Given room, the model grew the mug and shrank the laptop that sat half inside the mask, with 53 percent of the laptop's pixels changed in run 2. Worse, 52 percent of that collateral change fell inside the mask, so a check that only asks whether change stayed inside the mask passes it. The check that catches it compares the result against what you meant to change, not against the permission you gave.

The practical rule: write down what must stay the same, diff every edit against the original, and when the rest has to be exact, paste the masked region back onto the original in code. That composite is the only row on the board with zero drift, and it costs nothing but a few lines after the call. Feather the seam if the lighting shifted, and diff again.

The honest caveats. A pixel diff is strict: a one-pixel shift of an edge counts as a change, so the visible share mixes real redrawing with small misalignment, and a perceptual metric such as SSIM would score these edits more kindly. The threshold of 40 is a choice, shown next to the faint one so you can see how much depends on it. Two runs per condition show the spread but not a distribution, and a different model, size or quality setting would drift differently. The numbers describe this photo and these edits, not image editing in general.

The maths

What counts as a changed pixel
c(x)  =  [maxk{r,g,b}Rˉk(x)Sˉk(x)    τ],τ=40c(x) \;=\; \Big[\, \max_{k \in \{r,g,b\}} \big|\, \bar R_k(x) - \bar S_k(x) \,\big| \;\ge\; \tau \,\Big], \qquad \tau = 40

S is the source photo and R the edited result, both 1536 by 1024, and the bars mean each channel difference was averaged over a 3 by 3 box so single-pixel noise does not count. A pixel is changed when any colour channel moved 40 or more out of 255. Choosing Changed pixels under Show paints c(x) over the result.

Where the change fell
mug=1MxMc(x),rest=1MˉxMc(x)\text{mug} = \frac{1}{|M|}\sum_{x \in M} c(x), \qquad \text{rest} = \frac{1}{|\bar M|}\sum_{x \notin M} c(x)

M is the mug area, the tight mask’s editable region (3.5 percent of the frame). The slate in front of the easel reads both shares. For the tight-mask edit in the film, mug is 76.6 percent and rest is 9.3 percent. The rest is the drift: change nobody asked for.

Why a mask check is not an intent check
ppass  =  {xM,  xK,  c(x)}{xM,  c(x)}p_{\text{pass}} \;=\; \frac{\big|\{x \notin M,\; x \in K,\; c(x)\}\big|}{\big|\{x \notin M,\; c(x)\}\big|}

K is the mask actually sent. When K is the mug area, nothing outside the mug can hide inside it. When K is the loose mask over 22 percent of the frame, 51.7 percent of the collateral change in run 2 falls inside K, so a check against the mask scores it as intended. Pick Loose mask to see it.

Pasting the masked region back
R(x)  =  K(x)R(x)  +  (1K(x))S(x)R'(x) \;=\; K(x)\,R(x) \;+\; \big(1 - K(x)\big)\,S(x)

Keep the model’s pixels only where the mask allows, and the original everywhere else. Outside K, R′ equals S exactly, so the rest-of-photo share is 0.0 percent by construction. Pick Tight + paste back to see the result and its changed pixels.

Related terms

More visualisations

Building with language models?

These explainers come out of the work. If you want the same thinking applied to your own system, that is what I do.

See how I can help