Dear John, >>>>> John Fox <j...@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 : ------------------------------------------------------------------------ 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/ ______________________________________________ R-help@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.