GreenBG Remover

Why does a keyed GIF leave an "echo" around the subject?

It is not a ghost of the previous frame. We parsed the GIF this page writes rather than assuming, and every frame carries disposal method 2, restore to background, with a single transparent colour index; across 1,938,421 pixels that should have been pure background, not one carried anything over from an earlier frame. The echo is the edge: GIF has exactly one transparent index, so alpha is one bit, and on our 12-frame clip zero pixels kept a partial value. The soft rim is replaced by a hard one that re-decides every frame — measured as a step of 1.000 where the true alpha only moved 0.644.

What the echo is not

The question this is named after comes from someone who had removed a chroma key green background by hand, one frame at a time, and was left with a ghost. The obvious suspect is GIF frame handling: if each new frame is drawn over the previous one instead of over a cleared canvas, then everything the new frame leaves transparent shows the frame before it, and a moving subject drags a trail.

So we read the file instead of guessing. The GIF this page writes has 12 frames on a 640x360 canvas, and every one of them carries a graphic control extension with disposal method 2 — restore to background — along with a transparent colour index of 255. Not one of the 12 frames is full-canvas: each is a 310x325 rectangle that slides across, which is frame differencing, not accumulation.

Then we measured it. Decoding both the GIF and the equivalent APNG and compositing them over flat grey, zero of 1,938,421 pixels that should have been pure background showed anything at all. Both formats left the background exactly as it was. Whatever the echo is, it is not a frame left lying around.

One transparent index

GIF has no alpha channel. Transparency is a single palette entry flagged as invisible, so a pixel is either fully there or fully gone, and there is no third state for the pixels that make a cutout look soft.

Read back off the decoded clip, APNG returned 161,536 pixels at alpha 0, 68,402 at 255, and 462 in between. The GIF returned 161,774 and 68,626 — and 0 in between. Every partially transparent pixel in the picture had been destroyed.

Across the 5,592 rim pixels in the clip, 47.2% were forced fully opaque and 52.8% fully clear, a mean alpha error of 0.224 against APNG's 0.002. The cut lands exactly at half: not one pixel disagreed with the true 50% contour, measured over an outline 1,204 pixels long.

What one bit does to the edge

The rim is where a cutout is won or lost, and what is stored there matters. The keyer writes alpha and leaves the colour channels alone, so a rim pixel still holds a blend of subject and screen — we measured it at (46, 141, 91), a green excess of 50.1 over the larger of red and blue.

Forcing that rim to binary removes the blend and leaves two populations instead. Rim pixels forced opaque composited with a green excess of 48.6 where the correct blend is 37.5. Rim pixels forced clear came out at 0.0 where the correct blend is 11.5. Nothing in between survived.

So the outline stops being a gradient and becomes a hard line: full-strength rim colour, including its green, sitting directly against bare background. That hard line is what reads as an echo, and it is the shape of the subject, so it travels with the subject.

Why it shimmers rather than sits still

The binary decision is made independently on every frame. We took the pixels that stay inside the rim from one frame to the next and measured how far the edge actually moves. In APNG the step was 0.645 against a true movement of 0.644 — a ratio of 1.0x, faithful to the motion.

In the GIF the step was 1.000: every one of those pixels jumped the entire way across, against a true movement of 0.644, a ratio of 1.6x. The edge does not slide between frames. It snaps.

That is the mechanism behind the ghost. With the subject moving 2.6 pixels per frame, the hard outline lands on a slightly different set of pixels each time, and each of those pixels blinks between full rim colour and bare background. A soft edge would have absorbed that motion; a one-bit edge has nowhere to put it.

The palette is shared by every frame

There is a second contributor, and it is not the alpha. The encoder behind this page builds one palette from the whole clip and applies it to all of it: parsed from the file, 0 of the 12 frames carry a local colour table, so a single 256-colour table serves every frame.

A thin band of subtle blends is the first thing a shared 256-colour table gives up. Isolating the colour term of the rim error gives 25.4, larger than the alpha term's 18.4, for a combined rim error of 18.7 against APNG's 0.4. The worst single pixel in the GIF was 42.9 levels away from what it should have been, against 1.0 for APNG.

Adding palette colours can only help that half. The alpha half is one bit regardless of how many colours you allow, and that is the half that makes the edge snap.

What to export instead

The format table behind this page already flags GIF as not keeping alpha, and the measurement agrees with it: 18.7 rim error, zero partial pixels, worst pixel 42.9. APNG on the same clip measured 0.4, kept 462 partial pixels, and tracked the motion at 1.0x. MOV with qtrle and MKV with ffv1 carry real alpha as well.

GIF does buy you size — 104,012 bytes against APNG's 203,329 on this clip — and it plays everywhere without a plugin. That is a real trade, and for flat artwork it is a good one.

For a keyed subject it is not. If you have to ship GIF, expect the edge to be hard and to shimmer, and check it against the background you will actually publish on, because that is the only place the artefact is visible. Anything with hair, fur, smoke or motion blur needs a format that can store a partial pixel.

Related questions

Is the echo a leftover from the previous frame?

No. Every frame in the file we parsed carries disposal method 2, restore to background, with a single transparent index of 255, and none of the 12 frames is full-canvas. Composited over flat grey, zero of 1,938,421 background pixels carried anything over from an earlier frame.

Will a bigger palette fix it?

Only partly. Isolating the error at the rim, the colour term measured 25.4 and the alpha term 18.4. More palette colours can reduce the colour half, but alpha stays one bit no matter how large the palette is, and that is the half that makes the edge snap between frames.

Why does the artefact look green rather than just jagged?

Because the keyer writes alpha and leaves the colour channels alone, so rim pixels still hold a blend of subject and screen, measured at (46, 141, 91). When those pixels are forced fully opaque they show that green at full strength: green excess 48.6 against 37.5 for the correct blend.

Which format should I use for a keyed subject with movement?

APNG measured a rim error of 0.4 against GIF's 18.7, kept 462 partial pixels against zero, and followed the motion at 1.0x against 1.6x. MOV with qtrle and MKV with ffv1 also carry real alpha. Use GIF only when the size saving matters more than the edge.

Open the green screen remover