PixelFixer

PixelFixer

Overview

I won’t be sharing the code or the Gizmo for this one, but I wanted to document how it works anyway.

During a school project we were getting a ton of fireflies in our renders. Fireflies are most common with path tracing, it’s just how the algorithm works, occasionally a ray gets unlucky with a light sample and one pixel ends up way hotter than it should be. The result is a little white or coloured speck flickering in and out over a few frames.

I was stacking multiple nodes and running everything through NeatVideo and you could still see warm pixels dancing around. Nothing was fully killing them. So I built something that could run as a pre-pass before NeatVideo and just handle all of it in one go.

One node. Drop it in. Dancing Bright pixels & fireflies gone.

Before, fireflies visible
Input, fireflies visible
After, cleaned
Output, cleaned in a single pass

The Algorithm

Finding What Doesn’t Belong

For each pixel, the tool collects all the surrounding pixels in a window, 3×3, 5×5, or 7×7 depending on how big the artifact is. Those get sorted by brightness and the median gets pulled out, the value sitting right in the middle of the sorted list.

The median is more reliable than averaging here. An average gets dragged toward any extreme value in the list. The median just ignores them. If the center pixel deviates too far from that median, it gets flagged.

The detection also checks red, green and blue separately. A weird pink or blue speck might not even look that bright in overall luminance but it’s clearly wrong. Checking each channel independently catches those.

Adapting to Local Content

A flat threshold doesn’t work because what counts as “too different” depends entirely on where you are in the image. A deviation on a flat grey wall is suspicious. The same deviation on a rough stone texture with lots of natural contrast is completely fine.

To fix this the tool computes the Median Absolute Deviation how spread out the neighbourhood values are around the median. Flat areas get a tight threshold. Textured areas get a loose one. It adapts automatically without you having to think about it.

Not Touching Real Detail

A pixel sitting on a hard edge genuinely looks different from some of its neighbours, the ones on the other side of the edge. That’s not broken data, that’s just the edge.

The tool checks whether a pixel is an outlier in every direction at once. A real firefly sticks out from above, below, left, right, and diagonally. An edge pixel only sticks out in one direction. That distinction is what keeps edges clean while still catching actual fireflies sitting on them.


Using Time

Temporal Checking

A firefly almost never survives more than a frame or two. Everything real around it stays consistent. So the tool reads two frames before and two frames after the current one and uses them to see if the bright pixel was there before/after if not it’s a firefly.

If the surrounding frames agree on what the pixel should look like but the current frame disagrees, the current frame loses. Frames one step away count more than frames two steps away.

This is what really killed the dancing warm pixels. Spatially they were hard to remove since no more data was there to be compared against. But temporally they stick out immediately.

Temporal
Frames ±1 and ±2 vote against the current pixel to confirm it's an outlier

Replacing the Pixel

When a pixel gets flagged it gets filled with a weighted blend of its neighbours closer pixels count more, and pixels that look like what the area should look like count more too. The brightest and darkest outliers in the neighbourhood get thrown out first so nearby fireflies don’t contaminate the fill.

It also blends in pixels from the neighbouring frames, leaning toward those since they tend to hold more natural texture than a purely spatial patch.


Parameters

ParameterDescription
Filter SizeSize of the sampling window, 3×3 / 5×5 / 7×7
Spatial SensitivityHow far a pixel needs to deviate to be flagged
Highlight ProtectionGives brighter pixels more tolerance before flagging
MAD MultiplierControls how adaptive the threshold is to local texture
Fix ModeTarget brights only, darks only, or both
Temporal DetectUses surrounding frames as additional evidence
Replace MethodSpatial fill, temporal fill, or a blend of both
Output ViewSwitch between result, confidence map, or binary mask

This is what I built for the project, settings might need tweaking depending on the render. This was just a quick render showing it’s potential i know it can handle severe renders with fireflies after using it on a plate which i cant share at the moment.