Density Filtering

After the iteration loop is performed many times, most of the buckets in the histogram will have been hit many times. This puts their color values far outside the allowed range for display, 0-255 (or 0-1 for normalized colors).

To bring these color values into the valid range, log scaling is applied. There are two types, basic log scaling or log scaling with density filtering. As stated earlier, the term density estimation is misleading, since no estimating of any kind takes place.

Basic log scaling is triggered by setting the maximum density filtering radius to zero. It is achieved by performing the following step on each histogram bucket:

scale = 2^zoom
scaledquality = quality * scale * scale
area = (finalwidth * finalheight) / (pixelsperunitx * pixelsperunity)
k2 = supersample^2 / (area * scaledquality * temporalfilter.sumfilt)
accumulator[index] = (brightness * log(1 + histogram[index].hitcount * k2)) / histogram[index].hitcount

This calculation is much more complex than the simplistic log(a)/a mentioned in the flam3 paper. Note the presence of the somewhat mysterious K2 variable. It is mentioned nowhere in the paper, and is completely undocumented in the flam3 code. Yet it plays a large role in how the final output image appears by adjusting the log scaling based on the supersample. Note that in Fractorium, the user may override the K2 value.

If the max density filtering radius is greater than zero, a much more advanced algorithm is used for filtering. As stated in the paper, it’s a Gaussian blur filter whose width is inversely proportional to the number of hits in a given bucket. This means that buckets which were hit infrequently will have a wide blur applied to the surrounding pixels. A bucket with many hits will have very little blur applied.

The result of these filtering operations is written to another buffer of identical size called the filtering buffer, or accumulator.