What an image description generator actually writes: nine slots, 95 words, one line
It does not look at your picture and describe it. It measures a 192 × 192 grid, compares each number against fixed thresholds, and fills nine slots from a vocabulary it can never step outside — 95 entries in total.
An AI image describer writes nine fixed phrases, one per slot, each chosen by comparing a single measured number against a hard-coded threshold, then adds up to four colour names. That is the whole output. The vocabulary behind it is closed: 95 entries taken from the source of this site’s writer — 42 phrases in the describer, 18 template fragments in the formatter, 35 colour names. We pushed 81 generated prompts, 1,937 words, back through that list: not one word came from anywhere else.
That is the useful thing to know about an image describer. It is not a summariser that occasionally misses. It is a nine-position switchboard, and every position has a number behind it that you can read back.
Here is a real output, from a 640 × 360 night photograph of fireworks, at the longest setting:
widescreen 16:9 composition, dark, low-key lighting, dominant palette of navy, grey, slate, silver, vivid, saturated colour, cool blue colour temperature, medium contrast, highly detailed with intricate texture, light falling on the centre with darker edges, brighter upper half, moody and dramatic atmosphere --ar 16:9
Nine slots, nine numbers. The same code, run 200 times on the same file, produced one description — no variation at all. Below: what the vocabulary is, where each phrase flips, and what the describer is structurally unable to say.
The vocabulary is closed at 95 entries
The writer is a chain of if/else comparisons over measured numbers, and every string it can emit is written literally in the source. Collect them all and you get the complete set of things this describer is able to say:
| Source | Entries | What it covers |
|---|---|---|
src/describe.js | 42 | Eight framings, four exposures, three contrasts, four saturation states, five colour temperatures, three detail levels, three lighting distributions, two verticals, four moods, one subject, four hue hints, one fallback (“mixed tones”) |
src/compose.js | 18 | Fixed template fragments: “composition”, “dominant palette of”, “masterpiece, best quality,”, “The dominant colours are”, the model names, the length names |
src/palette.js | 35 | Named colours from black to cream, found by nearest-neighbour distance |
| Total, de-duplicated | 95 | Nothing outside this set can appear in any output |
We checked that claim rather than asserting it: 81 prompts (three real images × four target formats × three length settings, plus every synthetic sweep below) were split into words and matched against the vocabulary. 1,937 words, zero misses.
Which of those entries get used, and how often, is a separate question: counted across 480 lines from forty real photographs, 13,736 word tokens came from 98 distinct words, and not one popularity or recency word appeared in any of them. For that ranking — and for why a trend cannot come out of a closed vocabulary — see what this tool can and cannot rank when you ask it for a trending photo prompt.
The consequence is worth stating plainly. A describer with a closed vocabulary of adjectives, colour names and geometric ratios cannot name an object, a person, a place, a time of day, an art style, a camera, a lens, or the text in your screenshot — not because it failed to spot them, but because those words do not exist in it. If you are waiting for the description to mention “a dog”, no amount of cropping will produce it.
Nine slots, one number each
Each slot is decided by exactly one comparison, or in two cases by a ratio between two regions. Value column is the real night photograph above:
| Slot | Decided by | Thresholds | Measured | Phrase it chose |
|---|---|---|---|---|
| framing | aspect ratio | 2.2 / 1.7 / 1.4 / 1.15 / 0.9 / 0.7 / 0.55 | 1.7778 | widescreen 16:9 |
| exposure | mean luminance | 175 / 130 / 80 | 34.51 | dark, low-key lighting |
| contrast | std dev of luminance | 68 / 38 | 46.93 | medium contrast |
| saturation | mono ratio, then mean saturation | 0.85; 0.45 / 0.22 | 0.0117 | vivid, saturated colour |
| temperature | mean R − mean B | ±14 / ±5 | −43.93 | cool blue colour temperature |
| detail | mean gradient | 15 / 7 | 22.50 | highly detailed with intricate texture |
| distribution | centre vs border, ×1.18 | 1.18 | 60.25 / 29.58 | light falling on the centre with darker edges |
| vertical | top vs bottom, ×1.2 | 1.2 | 43.23 / 25.50 | brighter upper half |
| mood | luminance, contrast, temperature | 150 / 95 / 68 / ±5 | 34.51 | moody and dramatic atmosphere |
| palette | merged colour buckets | top 4 of 5 | — | navy, grey, slate, silver |
Mood is the only slot that reads three numbers, and the only one whose thresholds (“95”, “150”) sit inside another slot’s bands rather than on their edges. That has a measurable consequence, shown further down.
Where exactly the wording flips
Every comparison in the writer is a plain >, with one exception: framing uses >=. So a value sitting precisely on a threshold falls to the lower phrase almost everywhere, and to the higher one for aspect ratio. We fed the writer values just below, exactly on, and just above each line:
| Line | Just below | Exactly on | Just above |
|---|---|---|---|
| meanL = 80 | 79.99 → dark, low-key | 80 → dark, low-key | 80.01 → moderate, slightly dim |
| meanL = 130 | 129.99 → moderate | 130 → moderate | 130.01 → well-lit, balanced |
| meanL = 175 | 174.99 → well-lit | 175 → well-lit | 175.01 → bright, high-key |
| stdL = 38 | 37.99 → soft, low contrast | 38 → soft, low contrast | 38.01 → medium contrast |
| stdL = 68 | 67.99 → medium | 68 → medium | 68.01 → high contrast |
| edge = 7 | 6.99 → clean and minimal | 7 → clean and minimal | 7.01 → moderate detail |
| edge = 15 | 14.99 → moderate | 15 → moderate | 15.01 → highly detailed |
| monoRatio = 0.85 | 0.849 → moderately saturated | 0.85 → moderately saturated | 0.851 → monochrome, black and white |
| meanSat = 0.45 | 0.449 → moderately saturated | 0.45 → moderately saturated | 0.451 → vivid, saturated |
| centre / border = 1.18 | 117.99 → evenly lit | 118 → evenly lit | 118.01 → light on the centre |
| top / bottom = 1.2 | 119.99 → (no phrase) | 120 → (no phrase) | 120.01 → brighter upper half |
| ar = 2.2 | 2.19 → widescreen 16:9 | 2.2 → ultra-wide panoramic | 2.21 → ultra-wide panoramic |
That table is also a diagnosis tool. If the writer calls your photo “dark, low-key lighting”, you know the measured mean luminance is 80 or lower, not roughly 80 — the number is exact at the boundary.
Four things we pushed through it on real pixels
Numbers fed straight to the writer prove the branches; synthetic 192 × 192 images prove the measurements behave the same way on actual pixel data. Four of them are worth reporting:
| What we built | What it measured | What it wrote |
|---|---|---|
| Two flat halves, 90 / 166 | stdL = 38.00 exactly | soft, low contrast — the strict > holds on real pixels too |
| Vertical stripes, ±14, period 8 | edge = 6.78 | clean and minimal, smooth surfaces — visible texture, still under the 7 line |
| 10% of pixels vivid red, rest grey | monoRatio = 0.8999 | monochrome, black and white, and subject = “black and white photograph” |
| 15% of pixels vivid red, rest grey | monoRatio = 0.8499 | muted, desaturated tones — subject slot goes back to empty |
| Grey with R − B = +6 | monoRatio = 1.00, dt = +6 | “monochrome, black and white” and “slightly warm tone”, in the same prompt |
| Bright centre 128, border 100 | ratio 1.28 | light falling on the centre with darker edges |
| Centre 118, border 100 | ratio 1.18 | evenly lit — the phrase disappears at the line |
Two of those deserve a second look. The first: an image with 10% of its pixels vividly red is still described as a black and white photograph. The mono test counts pixels whose HSV saturation is under 0.10, and it takes more than 85% of them to trigger the monochrome branch — so a largely grey picture with a pop of colour gets the monochrome phrase, and the subject slot fills in with “black and white photograph”. Push the coloured share to 15% and both disappear at once.
The second is the mirror image of it. On the way up, “vivid, saturated colour” needs a mean HSV saturation above 0.45, and a grey pixel contributes zero. We raised the share of fully saturated pixels one point at a time: at 81% the mean is 0.4457 and the phrase is still “moderately saturated”; at 82% it reads 0.4512 and the phrase becomes “vivid”. More than four fifths of the frame has to be strongly coloured before the describer will call the image vivid.
The R − B = +6 row shows something else about the design: the slots are independent. Nothing reconciles them, so a grey image with a slight warm cast is reported as monochrome and warm in the same sentence. That is not a bug in the measurement — both numbers are right — it is what you get when nine separate comparisons never consult each other.
Read the description backwards
Because each phrase comes from a band, you can take any output and recover the range its numbers must have fallen in. We verified each band at both endpoints:
| Phrase | Number | Range it guarantees |
|---|---|---|
| dark, low-key lighting | mean L | 0 – 80 |
| moderate, slightly dim lighting | mean L | 80 – 130 |
| well-lit, balanced exposure | mean L | 130 – 175 |
| bright, high-key lighting | mean L | 175 – 255 |
| soft, low contrast | std dev L | 0 – 38 |
| medium contrast | std dev L | 38 – 68 |
| high contrast | std dev L | 68 – 127.5 |
| clean and minimal, smooth surfaces | edge | 0 – 7 |
| moderate detail and texture | edge | 7 – 15 |
| highly detailed with intricate texture | edge | above 15 |
| cool blue colour temperature | mean R − B | below −14 |
| neutral colour temperature | mean R − B | −5 – +5 |
| warm golden colour temperature | mean R − B | above +14 |
So “moderate detail and texture” is not a vague compliment. It means the mean gradient across the 192 × 192 grid landed between 7 and 15 — and that a nudge in either direction, a crop or a blur, will move it.
How many different descriptions exist
Multiply the options per slot and the nine slots look like they span 207,360 combinations. They do not, because mood is not a free slot: it reads the same luminance, contrast and temperature that already decided three other slots. Splitting those three numbers into their finest bands gives 90 combinations, and only 76 of them produce a distinct (exposure, contrast, temperature, mood) four-tuple. Mood is fully determined once you know the other three, so:
76 distinct four-tuples x 4 saturation x 3 detail x 3 distribution x 3 vertical x 8 framing = 65,664 reachable descriptions, out of 207,360 nominal (31.67%)
Two thirds of the nominal space is unreachable. A dark, low-contrast, warm image, for instance, can only ever be “moody and dramatic” — there is no combination of the other eight slots that will let it be “bright and uplifting”. Worth knowing before you re-roll the output hoping for a different mood: on the same file, there is nothing to re-roll. Two hundred runs produced one description.
What it will never say
Three limits follow from the design, and they are the ones that matter when you are deciding whether to trust an output:
- No nouns. The 95-entry vocabulary contains no object, animal, place, person or material words. The only thing close to a subject is one literal string, “black and white photograph”, which is filled in solely when the mono ratio passes 0.85 — on all three of our real test images the slot was empty. For what the finished line looks like once you supply that noun yourself, measured across forty photographs, see what the best AI prompts for images actually contain.
- No text and no faces. Nothing in the measurement pass reads glyphs, edges arranged as characters, or any structure finer than a gradient. A screenshot is measured exactly like a photograph of the same brightness distribution.
- No style, camera or medium. No lens, film, artist, render engine or art movement appears in the vocabulary, so none can appear in the output.
None of these are failures to fix. They are the reason the output is stable: the describer reports what it can measure and stays silent about the rest, instead of filling the gap with a guess that sounds right.
Which number decides which word
Nine measured numbers are read thirteen times to fill the ten slots and the subject line. Four of them are read twice — mean luminance, its standard deviation, the red–blue difference and the monochrome share — and the other five once each. To see what that is worth to you, we moved one number at a time to each of its other bands, left the other eight at their measured values, and rebuilt all twelve lines (four formats × three lengths) for each of forty real photographs: 720 moves, 8,640 rebuilt lines.
| Number | Bands | Slots it moves (share of its moves) | Slots changed | Lines changed of 12 | Words changed |
|---|---|---|---|---|---|
| mean luminance | 4 | exposure 100%, mood 65% | 2 | 12 | 8 |
| std dev of luminance | 3 | contrast 100%, mood 33.8% | 1 | 4 | 4 |
| monochrome share | 2 | subject 100%, saturation 100% | 2 | 12 | 79 |
| mean saturation | 3 | saturation 90% | 1 | 10 | 0 |
| mean R − mean B | 5 | temperature 100%, mood 41.3% | 1 | 10 | 10 |
| mean gradient | 3 | detail 100% | 1 | 8 | 8 |
| centre over border | 3 | distribution 100% | 1 | 5 | 20 |
| top over bottom | 3 | vertical 100% | 1 | 2 | 6 |
Two rows deserve a second look. The monochrome share is the most expensive number in the table and the only one that always moves two slots: the same comparison fills the saturation phrase and switches the subject line on, so a single move costs a median of 79 words across the twelve lines, on all forty photographs. At the other end, mean saturation changed a median of ten lines and zero words — all three saturation phrases are three words long, so swapping one for another never changes the length of the sentence, however much it changes what it says.
Here is that asymmetry on one real file, a 640 × 360 photograph that measures a monochrome share of 1.00 and a mean saturation of 0.00:
p58, longest setting, Midjourney — as measured: black and white photograph, widescreen 16:9 composition, dominant palette of grey, slate, silver, white, well-lit, balanced exposure, monochrome, black and white, neutral colour temperature, medium contrast, highly detailed with intricate texture, evenly lit, balanced, natural atmosphere --ar 16:9 mean saturation moved to 0.60, everything else unchanged: black and white photograph, widescreen 16:9 composition, dominant palette of grey, slate, silver, white, well-lit, balanced exposure, monochrome, black and white, neutral colour temperature, medium contrast, highly detailed with intricate texture, evenly lit, balanced, natural atmosphere --ar 16:9 (byte-identical: 8 of the 80 saturation moves changed nothing at all) monochrome share moved to 0.40, mean saturation left at 0.00: widescreen 16:9 composition, well-lit, balanced exposure, dominant palette of grey, slate, silver, white, muted, desaturated tones, neutral colour temperature, medium contrast, highly detailed with intricate texture, evenly lit, balanced, natural atmosphere --ar 16:9
The writer tests the monochrome share before mean saturation, so on a picture that is already over 0.85 no saturation value can reach the phrase. It is the one place in the table where a number has a veto rather than a vote — and those 8 dead moves all come from the four photographs that are already monochrome.
Now read the same experiment from the other end: for each slot, how many of the eight numbers can move its wording on your picture. Structurally mood reads three numbers and saturation reads two, but what you actually get depends on the photograph.
| Slot | Moved by | Handles (median) | Range |
|---|---|---|---|
| framing | nothing here — its number is the file’s own aspect ratio | 0 | 0 |
| exposure | mean luminance, 40 of 40 | 1 | 1 |
| saturation | monochrome share 40 of 40, mean saturation 36 of 40 | 2 | 1–2 |
| temperature | mean R − mean B, 40 of 40 | 1 | 1 |
| contrast | std dev of luminance, 40 of 40 | 1 | 1 |
| detail | mean gradient, 40 of 40 | 1 | 1 |
| distribution | centre over border, 40 of 40 | 1 | 1 |
| vertical | top over bottom, 40 of 40 | 1 | 1 |
| mood | mean luminance 38 of 40, mean R − mean B 26 of 40, std dev of luminance 23 of 40 | 2 | 1–3 |
| subject | monochrome share, 40 of 40 | 1 | 1 |
| palette | nothing — it is read off merged colour buckets, not off any of the nine numbers | 0 | 0 |
Mood is the only slot with three handles, and they are not equal: mean luminance worked on 38 of the forty photographs, the red–blue difference on 26, and contrast on 23. On the median photograph two of the three move it, and on all forty at least one does. Two slots have no handle at all. Framing is decided by the file’s pixel dimensions, and every photograph in this batch is 16:9, so it never moved once in 720 attempts; the palette comes from colour buckets rather than from any measured number. For those two, no measurement you can nudge will help — you change the file, or you change the words.
That is the practical shape of it: nine numbers, thirteen reads, one lever per word — except mood, which has three, and framing and palette, which have none. When a phrase reads wrong, the lever is the number behind it, not the sentence around it.
Photo to prompt: forty photos, forty lines, eight switches and one colour list
Forty different photographs, run through a photo to prompt tool, produce forty different lines: all 780 pairs differ somewhere. The difference is not spread evenly. Eight of the nine slots are three-to-five-position switches, and the only fine-grained slot is the colour list — 37 different colour combinations across the forty files, built from just 20 of the 35 names in the table. In 9 of those 780 pairs two unrelated photographs came out with the same phrase in eight slots and differed in exactly one.
| Slot | Positions used | Most common phrase | Files | Share |
|---|---|---|---|---|
| framing | 1 | widescreen 16:9 | 40 | 100% |
| exposure | 4 | moderate, slightly dim lighting | 16 | 40% |
| contrast | 3 | medium contrast | 28 | 70% |
| saturation | 4 | moderately saturated colour | 17 | 42.5% |
| temperature | 5 | warm golden colour temperature | 12 | 30% |
| detail | 3 | highly detailed with intricate texture | 22 | 55% |
| distribution | 3 | evenly lit | 21 | 52.5% |
| vertical | 3 | brighter upper half | 22 | 55% |
| mood | 4 | moody and dramatic atmosphere | 16 | 40% |
| colour list | 37 | charcoal, slate, grey, silver | 4 | 10% |
One row is flat and it is worth saying why rather than hiding it: every one of the forty source files is a 16:9 frame, so framing had one position to be in and took it. Feed the same code a 3:4 phone photo and that row becomes the only one that moves — the aspect ratio is read off the file, not off the scene. The other eight rows are the ones that carry information about the picture.
Because those eight rows are coarse, two photographs that look nothing alike can land on the same words. Counted across all 780 pairs, this is how many of the nine slots changed:
| Slots that differ | Pairs | Share of 780 |
|---|---|---|
| 1 | 9 | 1.2% |
| 2 | 25 | 3.2% |
| 3 | 76 | 9.7% |
| 4 | 129 | 16.5% |
| 5 | 202 | 25.9% |
| 6 | 192 | 24.6% |
| 7 | 111 | 14.2% |
| 8 | 36 | 4.6% |
Of the nine pairs that differ in a single slot, four differ only in the vertical phrase, three only in the lighting distribution and two only in colour temperature. Here is the pair that differs in temperature, both files at the longest setting, Midjourney shape:
p476 (640 × 360, mean luminance 64.33, gradient 17.95): widescreen 16:9 composition, dark, low-key lighting, dominant palette of charcoal, brown, cream, grey, muted, desaturated tones, warm golden colour temperature, medium contrast, highly detailed with intricate texture, light falling on the centre with darker edges, brighter upper half, moody and dramatic atmosphere --ar 16:9 q969 (800 × 450, mean luminance 72.75, gradient 19.92): widescreen 16:9 composition, dark, low-key lighting, dominant palette of black, slate, charcoal, tan, muted, desaturated tones, neutral colour temperature, medium contrast, highly detailed with intricate texture, light falling on the centre with darker edges, brighter upper half, moody and dramatic atmosphere --ar 16:9
Nine phrases are identical. Two photographs, two different colour lists, and one switch flipped: the red–blue difference fell from +15.10, past the +14 line, to +2.87 inside the ±5 band, and the phrase went from warm golden to neutral. Nothing else in either line knows the two pictures are different.
The colour list is the only part of the line that is not a switch, and it is where most of the visible variety comes from. Twenty names did all the work across forty files: charcoal on 26, grey on 24, silver on 20, slate on 18, tan on 17, black on 8, brown on 7, white on 7. Five names were used by exactly one file each. That is also the honest limit of what an ai photo describer can tell two pictures apart by — a row of colour names is the finest instrument in the box, and it is still only four words long.
If you are going picture to prompt the other way round, the same table applies in reverse: change a colour name and you change the line by one to four words; change any of the eight switches and you change exactly one phrase, because each is decided by a single comparison. The aspect ratio is the exception — it is arithmetic, not a switch, and on a 3:4 phone photo it is the first thing to check.
Three things worth doing with that:
- Read the colour list first. It is the only slot with more than five positions — 37 combinations against three to five for every switch — so if two outputs look the same to you, the difference is almost certainly in the four colour names.
- Count the switches you disagree with. Eight slots, one threshold each, and the measured value behind every one of them is in the table above — if the line says medium contrast and you think it is high, the number to look at is the standard deviation, not the wording.
- Check the ratio before anything else on a vertical photo. framing is a phrase; the actual
--arvalue is computed separately and can disagree with it.
How to use that when the description is wrong
When a phrase reads wrong, the fix is upstream of the writer, because the writer has no opinion — it only has thresholds:
- Find the number first. Map the phrase back through the table above, and you know which measurement to attack. “Clean and minimal” on a busy texture means the gradient measurement landed under 7, usually because the 192 × 192 grid averaged the detail away.
- Crop before you re-run. Cropping changes the measurements, which changes the phrases; editing the phrases by hand does not change anything downstream.
- Overwrite, do not argue. If a phrase is wrong for your picture, replace that one phrase with your own words and leave the neighbouring ones alone — they are still arithmetic on your file.
- Add the noun yourself. The describer will never supply the subject. Your prompt needs it at the front, and that is the one part of the output you always have to write.
For what each measured field is and how it is computed, see what an image to prompt tool measures. For the order to work in when a phrase is wrong, see fixing a wrong image to prompt output; for turning a picture into something you can paste, see how to generate a prompt from an image; and for the pictures where this approach breaks down, see which images it handles badly.