Skip to content

measuring distances between colours?

2 messages · John Fox, Michael Friendly

#
Hi Michael,

Thanks for the Wikipedia tip -- I'd looked there but didn't find this
article. The article explains that the Lab colour space was formulated to
provide uniform perceptual differences between colours, with a JND of
approximately of 2.3. Ken Knoblauch made a similar point. The article goes
on to describe relatively complicated adjustments meant to improve the LAV
distance metric, which are probably overkill for my application.

I've programmed Lab colour matching as follows, using Euclidean distances
and adapting Kevin Wright's modification of my original code. I used
convertColor(), which Martin Maechler pointed out to me.

----------- snip --------------

r2c <- function(){
    all.names <- colors()
    all.lab <- t(convertColor(t(col2rgb(all.names)), from="sRGB", to="Lab",
scale.in=255))
    find.near <- function(x.lab) {
        sq.dist <- colSums((all.lab - x.lab)^2)
        rbind(all.names[which.min(sq.dist)], min(sq.dist))
    }
    function(cols.hex, near=2.3){
        cols.lab <- t(convertColor(t(col2rgb(cols.hex)), from="sRGB",
to="Lab", scale.in=255))
        cols.near <- apply(cols.lab, 2, find.near)
        ifelse(cols.near[2, ] < near^2, cols.near[1, ], cols.hex)
    }
}

rgb2col <- r2c()

----------- snip --------------

A bit of experimentation suggests that this works better than using (as I
did previously) direct RGB distances, matching more colours to names and
providing (to my eye, with my monitor) perceptually closer matches, though
sometimes with (again to my eye) perceptible differences. Here's an
illustration, adapting one of Kevin's examples:

----------- snip --------------

cols <- c("#010101", "#EEEEEE", "#AA0000", "#00AA00", "#0000AA", "#AAAA00",
"#AA00AA", "#00AAAA")
(nms <- rgb2col(cols))
pie(rep(1, 2*length(cols)), labels=c(cols, nms), col=c(cols, nms))

----------- snip --------------

Thanks again to everyone who responded to my original, na?ve, question.

Best,
 John
#
Hi John
I agree that the Lab representation is the best so far for the goal of 
perceptually
similar colors, and the approximate JND of
2.3 on the distance scale in this space is a useful, non-arbitrary 
criterion.

FWIW, your demo might better show the hex and color names adjacently, 
for direct
comparison.

cols <- c("#010101", "#EEEEEE", "#AA0000", "#00AA00", "#0000AA", "#AAAA00",
"#AA00AA", "#00AAAA")
(nms <- rgb2col(cols))
pie(rep(1, 2*length(cols)), labels=c(rbind(cols, nms)), 
col=c(rbind(cols, nms)))

-Michael
On 6/1/2013 11:31 AM, John Fox wrote: