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)
k1 = (brightness * 268) / 256
k2 = supersample^2 / (area * scaledquality * temporalfilter.sumfilt)
accumulator[index] = (k1 * 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 k1 and k2 variables. They are mentioned nowhere in the paper, and are completely undocumented in the flam3 code, yet play a large role in how the final output image appears. k1 is intended to be the brightness multiplied by a magic number. k2 helps adjust the log scaling based on the supersample.

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.