Blur, SharpenTuring Patterns

how it works

In 1952, in The Chemical Basis of Morphogenesis, Alan Turing proposed a mechanism for how structure can emerge spontaneously in a developing embryo, the same math later used to explain skin patternsClose-up of a leopard's rosettes. If you have two chemicals which react with each other while diffusing at different rates (an activator that amplifies itself while spreading slowly, and an inhibitor that suppresses it while spreading fast), a uniform mixture will spontaneously break into spots or stripes. Turns out that with an image, if you blur a little, sharpen a lot, and repeat a bunch of times, you can generate these patterns.

Images as waves

A grayscale image can be written as a sum of overlapping waves. This is Fourier's theorem. In an image of random noise, you have waves of every size in roughly equal amounts.

Waves are the right lens to understand this, because blur and sharpen act on each wave independently. So if we understand how the whole loop impacts one wave, we can understand how it affects the whole image.

We can define a single wave of frequency kk as the function

u(x)=cos(kx)u(x) = \cos(kx)

which repeats every λ=2π/k\lambda = 2\pi/k pixels. Small kk means broad waves, large kk means fine detail.

k = 0.10λ ≈ 63 pxλk = 0.60λ ≈ 10.5 pxλk = 1.50λ ≈ 4.2 pxλsumall three0306090120x (pixels)
The sum of these three waves is the image.

Everything here is one-dimensional, but in 2D the explanation still holds, you just have kk as the length of the wave vector. So, what do blur and sharpen do to a single wave?

Blur and sharpen are volume knobs

Blur gives you back the same wave tuned down, and it quiets small waves more than big ones. When you blur a photo, the small details are washed out first, and only a heavy blur wipes out large regions.

Specifically, you can blur an image uu with a Gaussian of width σb\sigma_b which replaces each pixel with a bell-curve-weighted average (a convolution) of its neighborhood:

(Gσbu)(x)=Gσb(y)u(xy)dy.(G_{\sigma_b} * u)(x) = \int_{-\infty}^{\infty} G_{\sigma_b}(y)\, u(x-y)\, dy.

With:

Multiply the pair, add up the results for every yy, and the total is the new value at xx.

u × G(G ∗ u)(x): the blurred imageu: the imageG: the bell curve centered on xu(x−y)G(y)yx−yx
The summed blue minus red area is the blurred value at that point x.

With our image as a single wave, u(x)=cos(kx)u(x) = \cos(kx), the integral becomes:

(Gσbu)(x)=Gσb(y)cos(k(xy))dy.(G_{\sigma_b} * u)(x) = \int_{-\infty}^{\infty} G_{\sigma_b}(y)\, \cos\big(k(x-y)\big)\, dy.

If you expand the cosine with the addition formula, then pull everything that doesn't depend on yy out of the integral:

(Gσbu)(x)=Gσb(y)cos(k(xy))dy=Gσb(y)[coskxcosky+sinkxsinky]dy=coskxGσb(y)coskydy  +  sinkxGσb(y)sinkydy.\begin{aligned} (G_{\sigma_b} * u)(x) &= \int_{-\infty}^{\infty} G_{\sigma_b}(y)\, \cos\big(k(x-y)\big)\, dy \\[6pt] &= \int_{-\infty}^{\infty} G_{\sigma_b}(y)\,\big[\cos kx \cos ky + \sin kx \sin ky\big]\, dy \\[6pt] &= \cos kx \int_{-\infty}^{\infty} G_{\sigma_b}(y) \cos ky\, dy \; + \; \sin kx \int_{-\infty}^{\infty} G_{\sigma_b}(y) \sin ky\, dy. \end{aligned}

The second integral cancels out, because the bell curve GG is symmetric while the sine is antisymmetric, so every contribution at +y+y cancels its mirror at y-y, hence:

Gσb(y)sin(ky)dy=0.\int_{-\infty}^{\infty} G_{\sigma_b}(y) \sin(ky)\, dy = 0.

Knowing that the Fourier transform of a Gaussian is a Gaussian:

Gσb(y)cos(ky)dy=eσb2k2/2.\int_{-\infty}^{\infty} G_{\sigma_b}(y) \cos(ky)\, dy = e^{-\sigma_b^2 k^2 / 2}.

Put both back:

(Gσbu)(x)=coskxeσb2k2/2  +  sinkx0=B(k)cos(kx),B(k)=eσb2k2/2.\begin{aligned} (G_{\sigma_b} * u)(x) &= \cos kx \cdot e^{-\sigma_b^2 k^2/2} \; + \; \sin kx \cdot 0 \\[6pt] &= B(k) \cos(kx), \qquad B(k) = e^{-\sigma_b^2 k^2/2}. \end{aligned}

A frequency of k=0k = 0 means a flat wave, all one brightness. There B(0)=e0=1B(0) = e^0 = 1, so the wave comes back unchanged. On the other hand, a big kk means fine detail, and as σb2k2/2-\sigma_b^2 k^2 / 2 grows, B(k)B(k) collapses toward zero. The finer the detail, the more completely the blur erases it.

Sharpening is the opposite knob. Unsharp masking (the standard sharpen), with radius σs\sigma_s and strength α\alpha, takes the image, subtracts a blurred copy (the difference between the two is basically the small details), and adds α\alpha times the detail back:

the detailuGσsuu - G_{\sigma_s} * u
blurred copyGσsuG_{\sigma_s} * u
sharpen(u)\text{sharpen}(u)==uu++α\alpha(\big(uu-GσsuG_{\sigma_s} * u)\big)
the resultsharpen(u)\text{sharpen}(u)
the imageuu
α × detailα(uGσsu)\alpha\,(u - G_{\sigma_s} * u)

With our single wave and the previous blur result for the inner term:

sharpen(coskx)=S(k)cos(kx),S(k)=1+α(1eσs2k2/2).\text{sharpen}(\cos kx) = S(k)\cos(kx), \qquad S(k) = 1 + \alpha\big(1 - e^{-\sigma_s^2 k^2/2}\big).

Since a flat wave is identical to its own blurred copy, S(0)=1S(0) = 1 leaves it unchanged. However, fine details don't survive blurring and the difference is the wave itself, so S(k)S(k) rises to its ceiling of 1+α1 + \alpha.

blur B(k)sharpen S(k)
00.511.522.500.511.52wave frequency kgain
Blur and sharpen gain at different frequencies k, for σb = 1, σs = 3 and α = 1.0.

Blur then sharpen

Both operations are linear: applied to a sum of waves, they act on each wave individually. So one round of blur-then-sharpen multiplies each wave's amplitude by a single number H(k)H(k), the transfer function of one round.

H(k)  =  B(k)S(k)  =  eσb2k2/2[1+α(1eσs2k2/2)].H(k) \;=\; \textcolor{#2a78d6}{B(k)}\,\textcolor{#eb6834}{S(k)} \;=\; \textcolor{#2a78d6}{e^{-\sigma_b^2 k^2/2}}\,\textcolor{#eb6834}{\Big[1 + \alpha\big(1 - e^{-\sigma_s^2 k^2/2}\big)\Big]}.

We can see three regimes as kk varies in the following curve:

k* ≈ 0.60big waves don't change, H ≈ 1medium waves grow, H > 1small waves die, H → 000.511.522.500.511.5wave frequency kgain per round (H)

Near k=0k=0, with ex1xe^{-x} \approx 1 - x:

H(k)(1σb2k22)(1+ασs2k22)1+k22(ασs2σb2).H(k) \approx \Big(1 - \tfrac{\sigma_b^2 k^2}{2}\Big)\Big(1 + \tfrac{\alpha \sigma_s^2 k^2}{2}\Big) \approx 1 + \frac{k^2}{2}\big(\alpha\sigma_s^2 - \sigma_b^2\big).

The curve rises above 11 as we leave k=0k=0 exactly when

ασs2>σb2\alpha\,\sigma_s^2 > \sigma_b^2

In other words, when the sharpen reaches further than the blur destroys. HH eventually falls to zero at large kk, as the blur's exponential beats the sharpen's bounded 1+α1+\alpha. So the curve rises above 1, peaks, and falls.

Which wave wins? We can maximize lnH\ln H (same peak as HH, easier derivative):

lnH(k)=σb2k22+lnS(k).\ln H(k) = -\frac{\sigma_b^2 k^2}{2} + \ln S(k).

Setting the derivative to zero, and with q=eσs2k2/2q = e^{-\sigma_s^2 k^2/2}:

ασs2q=σb2(1+ααq),\alpha\,\sigma_s^2\, q = \sigma_b^2\,(1 + \alpha - \alpha q),

Solving for kk:

q  =  eσs2k2/2  =  σb2(1+α)α(σb2+σs2)σs2k22  =  lnσb2(1+α)α(σb2+σs2)  =  lnα(σb2+σs2)σb2(1+α)k  =  1σs2lnα(σb2+σs2)σb2(1+α).\begin{aligned} q \;=\; e^{-\sigma_s^2 k^2/2} \;&=\; \frac{\sigma_b^2 (1+\alpha)}{\alpha(\sigma_b^2 + \sigma_s^2)} \\[8pt] -\frac{\sigma_s^2 k^2}{2} \;&=\; \ln\frac{\sigma_b^2 (1+\alpha)}{\alpha(\sigma_b^2 + \sigma_s^2)} \;=\; -\ln\frac{\alpha(\sigma_b^2 + \sigma_s^2)}{\sigma_b^2 (1+\alpha)} \\[8pt] k^* \;&=\; \frac{1}{\sigma_s}\sqrt{2\ln\frac{\alpha(\sigma_b^2 + \sigma_s^2)}{\sigma_b^2(1+\alpha)}}. \end{aligned}

In words: the winning wavelength is set by the sharpen radius σs\sigma_s, adjusted by a logarithm of how decisively the sharpen beats the blur. With our concrete setting σb=1\sigma_b = 1, σs=3\sigma_s = 3, α=1\alpha = 1, we get k=132ln50.60k^* = \tfrac{1}{3}\sqrt{2\ln 5} \approx 0.60, with peak gain H(k)1.50H(k^*) \approx 1.50. The predicted pattern wavelength is λ=2π/k10.5\lambda^* = 2\pi/k^* \approx 10.5 pixels.

Fifty rounds of this

Each round multiplies by the same H(k)H(k), so after nn rounds the amplitude A0A_0 becomes A0H(k)nA_0\, H(k)^n. Fifty rounds at our settings:

Even the winner's near-neighbors lose. A ripple growing at ×1.45\times 1.45 per round instead of ×1.50\times 1.50 ends up (1.50/1.45)505(1.50/1.45)^{50} \approx 5 times quieter.

n = 1n = 5n = 20n = 50
k*n = 1n = 5n = 20n = 5000.250.50.7511.251.500.51wave frequency krelative amplitude
Amplitude after n rounds, relative to the winner's. Each curve is the gain curve raised to the n-th power (and rescaled so the peak is 1).

Whether a pattern appears depends on three parameters: the blur radius σb\sigma_b, the sharpen radius σs\sigma_s, and the sharpen strength α\alpha, specifically if ασs2>σb2\alpha\,\sigma_s^2 > \sigma_b^2. The final spot size is decided by these parameters, not by the input. Once again, since this is the crux: the spot size is a property of the filters, not the original photo.

You can try changing the parameters here to get a better feel for it:

round 0 / 60
start from:noise
k* ≈ 0.6000.511.522.5300.511.52ripple frequency k (π = a 2-pixel ripple)gain per round

α·σs² = 9.00 > σb² = 1.00: there is a hump. Its peak is at k* ≈ 0.60, so the winning ripple is about 10.5 px across, and it gains ×1.51 per round (a thousandfold in ≈ 17 rounds).

Clamping

Increasing the amplitude ×1.5\times 1.5 per round forever would turn brightness up to infinity, so each round ends by clipping every pixel to [0,1][0, 1]:

umin(max(u,0),1).u \mapsto \min(\max(u, 0),\, 1).

This stops the growth of the winning ripple when its crests are white and its troughs are black with feature size λ\lambda^* throughout.

n = 0n = 1n = 3n = 10n = 50060120180240x (pixels)
n rounds of the whole loop on a 240-pixel strip, with σb = 1, σs = 3, α = 1.

What about color photos?

If you ran a color image through the loop, you may have seen spots come out in reds, cyans, and magentas that weren't in the original photo.

A color image has a red, green, and blue channel. Blur, sharpen, and clamp all act on each channel separately. So what we've described for gray images runs three times in parallel, with the same gain curve H(k)H(k) for the three colors:

u^c,n(k)=H(k)nu^c,0(k),c{R,G,B}.\hat{u}_{c,n}(k) = H(k)^n\, \hat{u}_{c,0}(k), \qquad c \in \{R, G, B\}.

Same HH means same winning wavelength, which is why the spots are the same size for every color. But it doesn't mean same pattern, because the channels are different at the start.

With the clamp, each channel independently saturates at 00 or 11, so you get 23=82^3 = 8 outcomes: the corners of the RGB cube.

Back to Turing

In his original paper, Turing talks about two substances, reacting and diffusing at different rates. Our loop contains only one thing: the image. So where is the second substance?

It's actually inside the sharpen. If we look at the formula again:

sharpen(u)  =  u  +  α(uthe image    Gσsua blurred copy)\text{sharpen}(u) \;=\; u \;+\; \alpha\,\big(\underbrace{u}_{\text{the image}} \;-\; \overbrace{G_{\sigma_s} * u}^{\text{a blurred copy}}\big)

There are two pictures in that formula: the image itself, and a blurred copy of it. The operation subtracts the blurred one from the sharp one. The sharp image is the activator. The blurred copy is the inhibitor; created, used, and thrown away at each step. Unlike a real chemical, this inhibitor has no life of its own so the analogy is more structural than literal.

A round is one blur and one sharpen, but we can rewrite using the fact that sharpen contains a blur inside it too. Two blurs in a row is actually one wider blur, since Gaussian widths add in quadrature: GaGb=Ga2+b2G_a * G_b = G_{\sqrt{a^2+b^2}}. Collect terms:

round(u)  =  sharpen(blur(u))  =  sharpen(Gσbu)=  (Gσbu)  +  α[(Gσbu)    Gσs(Gσbu)]=  (1+α)Gσbu    αGσb2+σs2u=  Ku,K=(1+α)GσbαGσb2+σs2.\begin{aligned} \text{round}(u) \;&=\; \text{sharpen}\big(\text{blur}(u)\big) \;=\; \text{sharpen}\big(G_{\sigma_b} * u\big) \\[8pt] &=\; (G_{\sigma_b} * u) \;+\; \alpha\Big[(G_{\sigma_b} * u) \;-\; G_{\sigma_s} * (G_{\sigma_b} * u)\Big] \\[8pt] &=\; (1+\alpha)\, G_{\sigma_b} * u \;-\; \alpha\, G_{\sqrt{\sigma_b^2 + \sigma_s^2}} * u \\[8pt] &=\; K * u, \qquad K = (1+\alpha)\, G_{\sigma_b} - \alpha\, G_{\sqrt{\sigma_b^2 + \sigma_s^2}}. \end{aligned}

So the round can be written as one convolution, with a single kernel KK. It's a narrow positive bell minus a wide negative one: a difference of Gaussians, the classic Mexican-hat shape. Each pixel will reinforce its close neighbors and suppress a wider surrounding. In other words, short-range activation, long-range inhibition, which is Turing's proposal.

activator (1+α)·G(σb)inhibitor −α·G(√(σb²+σs²))kernel K = sum
short-range activationlong-range inhibition-12-8-40481200.20.40.60.8distance x (pixels)weight

And we get the same output using two successive blurs:

blur then sharpen
blur narrow then blur wide
round 0

I find it interesting that the type and size of the patterns that appear, the chemical wave-length as Turing called it, is determined by the dynamics of the system and not the starting conditions. In his paper he uses an oscillator analogy: the circuit fixes the frequency, amplitude, and waveform, while "the phase of the oscillation alone is determined by the disturbance." If we swap phase with position we have our image case, where the original image only explains the position of the patterns.

Another cool instance of this loop runs inside your head. Your visual cortex is wired like KK: each patch of neurons excites its close neighbours and inhibits a wider ring. Ermentrout and Cowan showed in 1979 what happens when that patch's gain is pushed up, by certain drugs or even flickering light: the blank state loses to a preferred wavelength, and stripes and hexagons of activity grow out of neural noise. People see tunnels and spirals rather than stripes because the cortex lays the image out in its own coordinates. So cortical stripes viewed back through that warp look like tunnels, funnels, and spirals, the classic geometry of hallucinations.

I find it interesting that this kind of thing doesn't depend on the substrate. Chemicals, neurons, pixels, they're different stuff but when short-range activation meets long-range inhibition, the same spots and stripes emerge, at a scale set by the dynamics. Maybe the pattern lives somewhere upstream of the systems that instantiate it, and each of them merely tunes in. Or maybe the three systems just share a mechanism, and math is how we describe mechanisms, so the same description was bound to show up. I wonder.