[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