[R] measuring distances between colours?

Martin Maechler maechler at stat.math.ethz.ch
Fri May 31 09:09:55 CEST 2013


>>>>> John Fox <jfox at mcmaster.ca>
>>>>>     on Thu, 30 May 2013 09:58:18 -0400 writes:

    > Dear Martin,
    >> -----Original Message----- From: Martin Maechler
    >> [mailto:maechler at stat.math.ethz.ch] Sent: Thursday, May
    >> 30, 2013 9:18 AM To: John Fox Cc: r-help at r-project.org
    >> Subject: Re: [R] measuring distances between colours?
    >> 
    >> Dear John,
    >> 
    >> >>>>> John Fox <jfox at mcmaster.ca> >>>>> on Thu, 30 May
    >> 2013 08:13:19 -0400 writes:
    >> 
    >> > Dear r-helpers, > I'm interested in locating the named
    >> colour that's "closest" to an arbitrary RGB colour.
    >> 
    >> Hmm, maybe I was not really marketing well enough what I
    >> had added for R 3.0.0 :

    > Or I didn't look carefully enough! I think that I would
    > have found nearRcolor() had it been a function in R rather
    > than in a demo, but I didn't think to try demo(color).

Yes, of course.  The problem with introducing  nearRcolor()
as a standard function is that -- for back compatibility reasons --
one should rather choose all the defaults "right" in the sense
that we cannot easily *change* the defaults later.
But I agree that demos are probably too much hidden,
and we (?) should probably consider adding some of these
functions to grDevices so they are seen and used.

    > This provides the solution that I was looking for, in that
    > there's a criterion for acceptable proximity for colour
    > matches. I see that the default comparison is in the HSV
    > colour space, so I suppose that Marius judged that to be
    > best, at least for close colours. Is that right?

actually, his original used only RGB distance, and I've added
the whole idea of "distance with respect to color space", and I
did chose  HSV  as clearly more sensical than RGB.
I remember having thought about choosing Lab / Luv as default,
but do no longer remember via I ended up staying with  HSV.

Martin

    > Thank you, John



    >> -----------------------------------------------------------------------
    >> -
    >> r61127 | maechler | 2012-11-17 20:00:58 +0100 (Sat, 17
    >> Nov 2012) | 1 line
    >> 
    >> new option colors(distinct=TRUE); new demo(colors) &
    >> demo(hclColors)
    >> -----------------------------------------------------------------------
    >> -
    >> 
    >> demo(colors) contains a few niceties, some originating
    >> from ------------ Marius Hofert, notably for you the
    >> function nearRcolor()
    >> 
    >> which has the nice extra that you can specify the color
    >> *space* in which to measure nearness.
    >> 
    >> 
    >> ##' Find close R colors() to a given color {original by
    >> Marius Hofert) ##' using Euclidean norm in (HSV / RGB /
    >> ...) color space nearRcolor <- function(rgb, cSpace =
    >> c("hsv", "rgb255", "Luv", "Lab"), dist = switch(cSpace,
    >> "hsv" = 0.10, "rgb255" = 30, "Luv" = 15, "Lab" = 12)) {
    >> if(is.character(rgb)) rgb <- col2rgb(rgb)
    >> stopifnot(length(rgb <- as.vector(rgb)) == 3) Rcol <-
    >> col2rgb(.cc <- colors()) uniqC <- !duplicated(t(Rcol)) #
    >> gray9 == grey9 (etc) Rcol <- Rcol[, uniqC] ; .cc <-
    >> .cc[uniqC] cSpace <- match.arg(cSpace) convRGB2 <-
    >> function(Rgb, to) t(convertColor(t(Rgb), from="sRGB",
    >> to=to, scale.in=255)) ## the transformation, rgb{0..255}
    >> --> cSpace : TransF <- switch(cSpace, "rgb255" =
    >> identity, "hsv" = rgb2hsv, "Luv" = function(RGB)
    >> convRGB2(RGB, "Luv"), "Lab" = function(RGB) convRGB2(RGB,
    >> "Lab")) d <- sqrt(colSums((TransF(Rcol) -
    >> as.vector(TransF(rgb)))^2)) iS <- sort.list(d[near <- d
    >> <= dist])# sorted: closest first setNames(.cc[near][iS],
    >> format(d[near][iS], digits=3)) }
    >> 
    >> 
    >> You should use the full
    >> 
    >> demo(colors)
    >> 
    >> or browse
    >> 
    >> https://svn.r-
    >> project.org/R/trunk/src/library/grDevices/demo/colors.R
    >> 
    >> to also get a few nice examples..
    >> 
    >> Martin
    >> 
    >> 
    >> 
    >> 
    >> > The best that I've been able to come up is the
    >> following, which uses HSV colours for the comparison:
    >> 
    >> >
    >> > r2c <- function(){ > hexnumerals <- 0:15 >
    >> names(hexnumerals) <- c(0:9, LETTERS[1:6]) > hex2decimal
    >> <- function(hexnums){ > hexnums <- strsplit(hexnums, "")
    >> > decimals <- matrix(0, 3, length(hexnums)) > decimals[1,
    >> ] <- sapply(hexnums, function(x) >
    >> sum(hexnumerals[x[1:2]] * c(16, 1))) > decimals[2, ] <-
    >> sapply(hexnums, function(x) > sum(hexnumerals[x[3:4]] *
    >> c(16, 1))) > decimals[3, ] <- sapply(hexnums, function(x)
    >> > sum(hexnumerals[x[5:6]] * c(16, 1))) > decimals > } >
    >> colors <- colors() > hsv <- rgb2hsv(col2rgb(colors)) >
    >> function(cols){ > cols <- sub("^#", "", toupper(cols)) >
    >> dec.cols <- rgb2hsv(hex2decimal(cols)) >
    >> colors[apply(dec.cols, 2, function(dec.col) >
    >> which.min(colSums((hsv - dec.col)^2)))] > } > }
    >> >
    >> > rgb2col <- r2c()
    >> >
    >> > I've programmed this with a closure so that hsv gets
    >> computed only once.
    >> >
    >> > Examples:
    >> >
    >> > > rgb2col(c("AA0000", "002200", "000099", "333300",
    >> "BB00BB", "#005555")) > [1] "darkred" "darkgreen" "blue4"
    >> "darkgreen" "magenta3" "darkgreen" > >
    >> rgb2col(c("AAAA00", "#00AAAA")) > [1] "darkgoldenrod"
    >> "cyan4"
    >> >
    >> > Some of these colour matches, e.g., "#005555" ->
    >> "darkgreen" seem poor to me. Even if the approach is
    >> sound, I'd like to be able to detect that there is no
    >> sufficiently close match in the vector of named
    >> colours. That is, can I establish a maximum acceptable
    >> distance in the HSV (or some other) colour space?
    >> >
    >> > I vaguely recall a paper or discussion concerning
    >> colour representation in R but can't locate it.
    >> >
    >> > Any suggestions would be appreciated.
    >> >
    >> > John
    >> >
    >> > ------------------------------------------------
    >> > John Fox > Sen. William McMaster Prof. of Social
    >> Statistics > Department of Sociology > McMaster
    >> University > Hamilton, Ontario, Canada >
    >> http://socserv.mcmaster.ca/jfox/



More information about the R-help mailing list