Internal Similarity Score - a palette metric


One of reasons a palette is of limited usability is that it has colours that are too similar in context of their structure. In particular, it means that there is some pair of colours such that the colour distance between them is much smaller than the mean distance between colours in the palette.
I suggest a metric that would allow detecting such cases with computation.
Suppose we have a colour distance function d. For a palette of size n>=2, mean_d and min_d would be mean and minimal pairwise colour distances. Then Internal Similarity Score is defined the following way:
ISS := (mean_d/min_d) / n^(2/3)


While the mean_d/min_d is the part one wants to keep limited, we need to keep in mind that with greater number of colours there is the same volume to position them, and min_d will be systematically lower while mean_d suitable for art would be quite stable. To compensate this effect, the ratio is multiplied by a rough estimate of expected minimal pairwise distance between n random points in a unit cube, which also gives a reasonable asymptotic estimate for non-cubical perceptual colour spaces.

If mean_d = min_d, ISS = 1/n^(2/3). It will also be the case for n=2.
If all the colours are multiplied by a non-zero constant, ISS is intact.

Choice of distance function

It is desirable to choose a colour distance function that would reflect perception well.
Tests were made with CAM16 Jab and basic euclidean RGB distances. While their outputs generally correlated, there were many palettes that had considerably different ISS.
The results also looked much more stable with CAM16, but are also ~acceptable with RGB.


Two data sources were tested. One is a dump of Lospec moderated palette database (labelled as all) and the other is (labelled as rejected), which contains a mix of rejected and accepted Lospec palettes that seemed poor to moderators of rejected. A few number of palettes with extreme values were omitted in some graphs to make them legible.
ISS comparison shows that many of rejected palettes have considarably higher ISS values:
Typical ISS-CAM16 values for palettes from all range from 0.4 to 1.9.

Very nice work! I'd love to be able to read this score on every palette page.

Nice that you've experimented with different color spaces for distance.

Also, I'm curious now, what is the best spread palette? And would it be possible to generate the best possible palette(s) with the distances as close to the mean as possible?

@hapiel, thank you!
According to my data, a month ago the palette with the lowest ISS on Lospec was, with ISS around 0.39.
Concerning generating palettes to minimise internal similarity, I doubt it's something that should be done. When ISS is too high, the palette quality suffers, but once you're in the safe zone, you have some degrees of freedom to shape the atmosphere, and there is no task more important. Moreover, ISS is just one metric and you should consider many to understand the palette better.

Oh yes, I understand its not beneficial to the quality of the palette at the extreme level, but I'd still be curious!

I'm very surprised that the Resurrect 32 is the lowest, it does not hold full black, so the distances could be much bigger if it were stretched to include that, right? Also, from glancing over it many colors do seem similar, but that might be just my eyes playing tricks.

By the way, an alternative for calculating distance would be to use DawnBringer's weighed formula, which is adjusted to brightness perception.

To quote a message he sent me:

Brightness is key! Brightness is the most dominant dimension and property of a color. That's why it's usually very helpful to add a brightness-weight into a colormatching procedure, especially if you're seeking perceptual correctness.

This is my own (current) formula for calculating preceptual brightness of a color, color distances and color matching.

brightness = math.sqrt((r*0.26)^2 + (g*0.55)^2 + (b*0.19)^2) * 1.5690256395005606
-- # Color Distance (hardcoded gammma correction of 2.0)

-- Returns Normalized result (0..255, 255 is the distance black to white)
-- Dawn3.0 weights = 0.26,0.55,0.19
function db.getColorDistance_weightNorm(r1,g1,b1,r2,g2,b2,rw,gw,bw)
 return ( (rw*rw*(r1-r2)*(r1-r2) + gw*gw*(g1-g2)*(g1-g2) + bw*bw*(b1-b2)*(b1-b2)) / (rw*rw + gw*gw + bw*bw) )^0.5

This stuff should also be in the DB toolbox for Grafx2

Well, I'll look into that later.

Lospec is a moderated resource relying on submissions, so many palettes that could have lower ISS might be rejected or not submitted for various reasons.
And yes, if many colours are similar, it may result in ISS being low. In any case, they seem to be spread more or less well in the analysis.

Indeed, DawnBringer's weighted brightness can be used to improve RGB distance, which wasn't really designed to be perceptual. But is it so important for modern uniform colour spaces like CAM16UCS?

Minimising ISS can be restated the following way. We have n spheres of specified radius min_d/2 (which can be fixed as we can scale everything as we desire) and we need to position them to minimise mean pairwise distance between their centers. Then the problem is quite close to sphere packing (minimising the radius of the minimal sphere containing all of those), and solutions to sphere packing seem to be at least good approximations for minimising ISS, if not exact solutions.

Analytics and metrics on color palettes is something I'm interested in, so It is cool to see you work on this.

I didn't catch the motivation you laid out.

it means that there is some pair of colours such that the colour distance between them is much smaller than the mean distance between colours in the palette.

From this, it sounds that your measurement is meant to filter for palettes where there exists a pair of visually close colors. Is that the purpose, or are you aiming to measure the general internal similarity palette? If the latter, my thinking is that the formula is too sensitive to the minimum pairwise distance.

Indeed, the initial motivation was to filter palettes with very close colour pairs.

For a less sensitive version, you could use minimal kNN distance instead of minimal pairwise distance. Let's see an example:

k=2, n=3. Let's say the colours are A, B and C. d(A, B) is nearly zero and d(B, C) = d(A, C) = d >> 0. min_kNN ~ d/2, mean_d ~ d * 2/3. Then kISS ~ 0.64, which is a low score (while the usual ISS will be astronomically large).

Considering kISS for different k together could be sufficient. Maybe just use maximum of kISS for k in {1, 2, 3, 4}? I'll test it later.