2024-12-01 15:16:30 -05:00
|
|
|
---
|
|
|
|
slug: 2024/11/playing-with-fire-log-density
|
2024-12-02 22:36:25 -05:00
|
|
|
title: "Playing with fire: Log-density and color"
|
2024-12-01 15:16:30 -05:00
|
|
|
date: 2024-11-15 14:00:00
|
|
|
|
authors: [bspeice]
|
|
|
|
tags: []
|
|
|
|
---
|
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
So far, our `plot()` function has been fairly simple; map an input coordinate to a specific pixel,
|
|
|
|
and color in that pixel. This works well for simple function systems (like Sierpinski's Gasket),
|
2024-12-01 15:16:30 -05:00
|
|
|
but more complex systems (like our reference parameters) produce grainy images.
|
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
In this post, we'll refine the image quality and add color to really make things shine.
|
2024-12-01 15:16:30 -05:00
|
|
|
|
|
|
|
<!-- truncate -->
|
|
|
|
|
|
|
|
## Image histograms
|
|
|
|
|
2024-12-09 22:18:13 -05:00
|
|
|
:::note
|
|
|
|
This post covers sections 4 and 5 of the Fractal Flame Algorithm paper
|
|
|
|
:::
|
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
To start, it's worth demonstrating how much work is actually "wasted"
|
|
|
|
when we treat pixels as a binary "on" (opaque) or "off" (transparent).
|
2024-12-13 20:03:53 -05:00
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
We'll render the reference image again, but this time, track each time
|
|
|
|
we encounter each pixel during the chaos game. When the chaos game finishes,
|
|
|
|
find the pixel we encountered most frequently. Finally, "paint" the image
|
|
|
|
by setting each pixel's transparency to ratio of times encountered
|
|
|
|
divided by the maximum value:
|
2024-12-01 15:16:30 -05:00
|
|
|
|
|
|
|
import CodeBlock from "@theme/CodeBlock";
|
|
|
|
|
2024-12-01 21:57:10 -05:00
|
|
|
import paintLinearSource from "!!raw-loader!./paintLinear"
|
|
|
|
|
|
|
|
<CodeBlock language="typescript">{paintLinearSource}</CodeBlock>
|
2024-12-01 18:17:36 -05:00
|
|
|
|
2024-12-08 22:50:46 -05:00
|
|
|
import {SquareCanvas} from "../src/Canvas";
|
2024-12-01 18:17:36 -05:00
|
|
|
import FlameHistogram from "./FlameHistogram";
|
2024-12-01 21:57:10 -05:00
|
|
|
import {paintLinear} from "./paintLinear";
|
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
<SquareCanvas><FlameHistogram quality={15} paint={paintLinear}/></SquareCanvas>
|
2024-12-01 21:57:10 -05:00
|
|
|
|
|
|
|
## Log display
|
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
While using a histogram to paint the image improves the quality,
|
|
|
|
it also leads to some parts vanishing entirely.
|
|
|
|
In the reference parameters, the outer circle
|
2024-12-13 20:03:53 -05:00
|
|
|
is preserved, but the interior appears to be missing!
|
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
To fix this, we'll introduce the second major innovation of the fractal flame algorithm: [tone mapping](https://en.wikipedia.org/wiki/Tone_mapping).
|
|
|
|
This is a technique used in computer graphics to compensate for differences in how
|
|
|
|
computers represent color, and how color is perceived by people.
|
2024-12-13 20:03:53 -05:00
|
|
|
|
|
|
|
As a concrete example, high dynamic range (HDR) photography uses this technique to capture
|
2024-12-13 23:28:35 -05:00
|
|
|
nice images of scenes with wide brightness ranges. To take a picture of something dark,
|
|
|
|
you need a long exposure time. However, long exposures can lead to images that "wash out" and become pure white.
|
|
|
|
By taking multiple pictures using different exposure times, we can combine them to create
|
2024-12-13 20:03:53 -05:00
|
|
|
a final image where everything is visible.
|
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
In fractal flames, this "tone map" is accomplished by scaling brightness according to the _logarithm_
|
|
|
|
of how many times we encounter a pixel. This way, "dark spots" (pixels the chaos game visits infrequently)
|
|
|
|
will still be visible, and "bright spots" (pixels the chaos game visits frequently) won't wash out.
|
2024-12-13 20:03:53 -05:00
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
<details>
|
|
|
|
<summary>Log-scale vibrancy is also why fractal flames appear to be 3D...</summary>
|
|
|
|
|
|
|
|
As explained in the Fractal Flame paper:
|
|
|
|
|
|
|
|
> Where one branch of the fractal crosses another, one may appear to occlude the other
|
|
|
|
> if their densities are different enough because the lesser density is inconsequential in sum.
|
|
|
|
> For example, branches of densities 1000 and 100 might have brightnesses of 30 and 20.
|
|
|
|
> Where they cross the density is 1100, whose brightness is 30.4, which is
|
|
|
|
> hardly distinguishable from 30.
|
|
|
|
</details>
|
2024-12-13 20:03:53 -05:00
|
|
|
|
2024-12-08 15:35:27 -05:00
|
|
|
import paintLogarithmicSource from "!!raw-loader!./paintLogarithmic"
|
|
|
|
|
|
|
|
<CodeBlock language="typescript">{paintLogarithmicSource}</CodeBlock>
|
|
|
|
|
2024-12-01 21:57:10 -05:00
|
|
|
import {paintLogarithmic} from './paintLogarithmic'
|
2024-12-01 18:17:36 -05:00
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
<SquareCanvas><FlameHistogram quality={15} paint={paintLogarithmic}/></SquareCanvas>
|
2024-12-02 22:36:25 -05:00
|
|
|
|
|
|
|
## Color
|
|
|
|
|
2024-12-13 23:28:35 -05:00
|
|
|
Finally, we'll spice things up with the last innovation introduced by
|
|
|
|
the fractal flame algorithm: color. By including a color coordinate
|
|
|
|
in the chaos game, we can illustrate the transforms that are responsible
|
|
|
|
for each part of an image.
|
|
|
|
|
|
|
|
### Palette
|
|
|
|
|
|
|
|
Our first step is to define a color palette for the image. Fractal flames
|
|
|
|
typically use a palette of 256 colors that transition smoothly
|
|
|
|
from one to another. In the diagram below, each color in our palette is plotted
|
|
|
|
on a small strip. Putting the strips side by side shows the palette for our image:
|
|
|
|
|
|
|
|
import * as params from "../src/params"
|
|
|
|
import {PaletteBar} from "./FlameColor"
|
|
|
|
|
|
|
|
<PaletteBar height="40" palette={params.palette}/>
|
|
|
|
|
|
|
|
### Color coordinate
|
|
|
|
|
2024-12-08 15:35:27 -05:00
|
|
|
import paintColorSource from "!!raw-loader!./paintColor"
|
|
|
|
|
|
|
|
<CodeBlock language="typescript">{paintColorSource}</CodeBlock>
|
|
|
|
|
2024-12-02 22:36:25 -05:00
|
|
|
import FlameColor from "./FlameColor";
|
|
|
|
|
2024-12-08 22:50:46 -05:00
|
|
|
<SquareCanvas><FlameColor quality={15}/></SquareCanvas>
|