Skincolor Index
A continuous skin color index, linear in RGB and anchored at pure white and pure black. The same color always gets the same number — in any dataset, from any image source.
The problem
Skin tone measures are used across economics, political science, health and computer vision. The instruments in common use either discretize the scale into a handful of categories, or rely on colorimetric operations designed for controlled laboratory conditions rather than for the narrow band of colors that human skin actually occupies.
We want a continuous index: a function that maps any RGB skin color to a number, with a geometric meaning in color space, stable enough to support matching, error analysis and causal work.
- • Be continuous, not categorical.
- • Order tones plausibly (light → dark) and stay stable.
- • Mean the same thing across samples — not be rescaled by whoever is in the data.
- • Be computable from any RGB triple, from any source.
The top strip is continuous, but each observation is filed into one of 10 boxes. Two nearly identical colors on a boundary land in different categories, and every distance inside a box is thrown away.
The direction of the projection is not the contribution
Observed skin colors do not fill the RGB cube. They lie along a narrow, elongated band — a near one-dimensional manifold. On a cloud shaped like that, almost any sensible way of collapsing three channels into one produces the same ordering.
We tested that directly. The fitted first principal component, the plain average of the three channels, inverted CIELab lightness, and even a PCA fitted inside CIELab all rank the observations essentially identically (pairwise Spearman ρ ≥ 0.992). Arguing about which direction to project on is arguing about nothing.
- ≡ PC1 fitted in RGB
- ≡ mean(R, G, B)
- ≡ −L* (inverted CIELab lightness)
- ≡ PC1 fitted in CIELab
The coordinate system, and the anchoring. Not which arrow you draw through the cloud, but what space you draw it in — and what the endpoints of the resulting scale mean. That is where CIELab, despite being perceptually principled in general, distorts the skin band in specific and measurable ways.
The RGB color space
Every possible color is a point in a 3D cube defined by the three channels. Skin tones occupy only a small, elongated region of that cube — not scattered at random, but clustered along a direction that runs from light to dark.
That geometric fact is what licenses a one-dimensional index. The projection axis captures 93% of the variance of the observed colors.
Voxelization: from photographs to geometry
We divide the RGB cube into cubic cells of side 4. Every cell holding at least 4 observations becomes a voxel, represented by its center. 668,897 observations collapse to 8,738 occupied voxels.
Because the object of study is the geometry of skin color, not the demography of who was photographed. Each voxel carries equal weight regardless of how many photographs landed in it, so a sample with more light-skinned subjects does not bend the axis toward light tones. The index is estimated on the voxel cloud and then applies to the entire RGB domain.
- Voxel side: 4 RGB units
- Minimum per voxel: T ≥ 4 observations
- Observations: 668,897
- Occupied voxels: 8,738
Each point is a voxel of real, observed skin color. The band is thin and oblique: this is the empirical fact the whole index rests on. Nothing here is simulated or interpolated — sparse regions are shown sparse.
- • Drag: rotate
- • Scroll: zoom
- • Right-click: pan
Each point is an observed voxel, colored by its own color. The diagonal structure is the one-dimensionality, seen edge-on.
The index: linear in RGB, anchored at white and black
The index is a linear projection of the RGB triple, normalized so that pure white scores 0 and pure black scores 1. Those two anchors are theoretical extremes of the color space, not the extremes of our sample.
That distinction is the practical payload. An index normalized to the range of its own sample means something different in every dataset: add one very dark subject and everyone else's score shifts. Anchored at white and black, a given RGB triple always yields the same number — so scores are comparable across samples, studies and image sources.
- • Continuous: no categorical jumps
- • Transferable: the same color → the same number, in any sample
- • Interpretable: 0 = pure white, 1 = pure black
- • Portable: computable from any RGB triple
MU = [0.802543, 0.586535, 0.503217] W = [0.572383, 0.575555, 0.584049] WHITE = 0.641139 BLACK = -1.090849 raw = W · ([r, g, b] / 255 - MU) index = (WHITE - raw) / (WHITE - BLACK)
Center by the reference means, project onto the loadings, rescale by the two anchors. The fitted parameters are published with the paper; you do not need our photographs to use the index.
Why not CIELab?
CIELab is perceptually uniform — globally. But skin occupies a narrow, oblique sliver of it, and two operations that are routine in CIELab break down precisely there. This is the argument of the paper, and it is falsifiable.
Assigning a color to its nearest Monk swatch is standard practice. Do it in CIELab and the Voronoi cell of MST 3 collapses to a sliver holding 0.48% of observed voxels, while its neighbor MST 2 swells to 8.77%. Do it in RGB, on the same swatches and the same voxels, and the categories recover coherent shares.
| CIELab | RGB | |
|---|---|---|
| MST 2 | 8.77% | 1.22% |
| MST 3 | 0.48% | 0.93% |
| MST 4 | 2.29% | 9.17% |
Same swatches, same voxels. Only the distance metric changes.
Explore both partitions side by side →This one needs no data at all. Take the ten official Monk swatches and sort them: they increase monotonically in RGB brightness, but not in CIELab lightness — MST 3 is lighter than MST 2 in L*. A scale that is ordered in one space and disordered in another is a warning about the space, not about the scale.
| MST | Hex | RGB brightness | L* |
|---|---|---|---|
1 | #f6ede4 | 0.071 | 94.1 |
2 | #f3e7db | 0.094 | 92.2 |
3 | #f7ead0 | 0.099 | 93.3 |
4 | #eadaba | 0.166 | 87.5 |
5 | #d7bd96 | 0.276 | 78.0 |
6 | #a07e56 | 0.514 | 55.3 |
7 | #825c43 | 0.622 | 42.4 |
8 | #604134 | 0.722 | 30.6 |
9 | #3a312a | 0.805 | 21.2 |
10 | #292420 | 0.858 | 14.5 |
The light end, where ITA runs out of resolution
The Individual Typology Angle takes an arctangent, and at the light end of the skin band that arctangent saturates: genuinely distinct pale tones get squeezed into a narrow angular interval. This is not numerical instability — the derivative is finite — it is compression, and it is worst exactly where fine distinctions matter for fairness auditing.
Between the two lightest Monk categories, ITA° separates at Cohen's d = 0.013 (AUC 0.534 — coin-flip). The linear RGB index separates the same two categories at d = 2.90 (AUC 0.997).
Does it hold up?
The index is a definition, so it cannot be 'validated' in the usual sense — but its claims can be broken. We state the conditions under which they would be.
The photograph extractor (YCbCr skin mask + KDE mode) agrees with human annotation at Spearman ρ = 0.972.
Transferred unchanged to ISSA — an independent dataset with instrument-measured skin color — the index reproduces measured ITA° at ρ ≈ −0.99.
The paper commits in advance to what would refute it: a disjunctive, three-armed criterion, stated before the tests were run.
This is a measurement paper. The index is a brightness coordinate: it does not capture undertone, and it is not a proxy for race, ethnicity or identity. What it offers is a number that means the same thing tomorrow as it does today.
Kauê Lopes de Moraes · Carlos Cavalcante · Humberto Laudares