The Dressmaker

Make any photo perceptually ambiguous like #theDress — by collapsing its colours onto the CIE daylight axis

Quick Summary:

#theDress went viral because its colours vary along a single direction in colour space — the blue↔yellow daylight axis. Our visual system can't tell whether that variation comes from the dress or from the light falling on it, so each brain silently "subtracts" an assumed illuminant: subtract blue and you see white&gold; subtract yellow and you see blue&black. This tool reproduces that ambiguity for any image by forcing its chroma onto the daylight axis, then shows you both readings of the very same pixels.

How It Works (Intuitive)

1. Compute the CIE daylight locus direction in perceptual CIELUV colour (the line natural light travels as it goes from warm sunset to cool blue sky).
2. For every pixel, split its colour into the part along that daylight axis and the part across it (the red↔green part).
3. Remove the across-axis (red↔green) part. Red-green shifts are never caused by daylight, so the brain won't blame them on the light — keeping them would give the true colour away. Removing them is what makes the image ambiguous.
4. Pull the average colour toward neutral and gently desaturate, placing the palette in the "could be either light" zone.
5. Keep the original lightness so the subject stays recognisable.
6. To show the two readings, apply real von Kries / Bradford chromatic adaptation: assume a cool bluish light and discount it → White/Gold; assume a warm light and discount it → Blue/Black. Same pixels, two illuminant priors.

Algorithm Steps (Technical)
Daylight axis d (fixed, computed once):
  Sample CIE daylight locus at 4000 K (warm) and 20000 K (cool) via Judd's xy(T),
  convert each xy -> XYZ -> CIELUV (u*,v*) relative to D65, take the unit
  difference vector. Result d ~= (0.44, 0.90); orthogonal p = (-d_v, d_u).

Per pixel (entire image treated as object):
  1. sRGB -> linear -> XYZ (sRGB/D65 matrix) -> CIELUV (L*,u*,v*).
  2. along = (u*,v*) . d         across = (u*,v*) . p
  3. across' = across * (1 - axisLock)      // suppress red-green -> ambiguity
  4. along' = (along - meanAlong*centerPull) * desat   // recenter + soften
  5. (u_map,v_map) = along'*d + across'*p ; L_map = L*  (lightness preserved)
  6. Blend: Luv_out = Luv_orig + intensity*(Luv_map - Luv_orig)
  7. Luv -> XYZ -> linear sRGB -> gamma -> 8-bit (clipped).

Two readings (color-constancy demonstration), applied to the ambiguous result:
  M_read = M(XYZ->sRGB) . CAT_Bradford(assumedWhite -> D65) . M(sRGB->XYZ)
  White/Gold  = assume cool 15000 K light, discount it (image warms).
  Blue/Black  = assume warm  4000 K light, discount it (image cools).
      
FAQ & Tips
  • Which panel is "the" result? The highlighted #theDress (ambiguous) panel — that single image is the bistable one to share. The White/Gold and Blue/Black panels just reveal the two ways a brain can resolve it.
  • Axis lock? How strongly red↔green chroma is removed. 100% = pure daylight axis (maximum ambiguity); lower keeps more original colour and is easier to disambiguate.
  • Effect intensity? 0% = original photo; 100% = full daylight-axis mapping.
  • Why CIELUV? Its u*,v* plane is roughly perceptually uniform, so the daylight locus is close to a straight line and projection stays meaningful.
  • Best inputs? Photos with clear light/dark structure and a couple of colour regions (clothing, objects) — like the original dress.
  • Will everyone flip? No — that's the point. As with the real dress, the split depends on each viewer's assumptions about the light; the tool just maximises the ambiguity.
80%
90%
Ready – load an image.

Original Image

The Dress

#theDress (ambiguous)

White / Gold

If your brain assumes cool light

Blue / Black

If your brain assumes warm light