Nothing
##########################################
## manual conversion between sRGB and RGB
srgb2rgb <- function(x) {
a <- 0.055
ifelse(x <= 0.04045,
x/12.92,
((x + a)/(1+a))^2.4)
}
rgb2srgb <- function(x) {
a <- 0.055
ifelse(x <= 0.0031308,
12.92*x,
(1+a)*x^(1/2.4) - a)
}
##########################################
## Transformation matrices
## convert RGB to XYZ space (CIE uses 4-digit approxiomations)
RGB2XYZ <- matrix(c(0.4124, 0.3576, 0.1805,
0.2126, 0.7152, 0.0722,
0.0193, 0.1192, 0.9505),
3, 3, byrow=TRUE)
XYZ2RGB <- round(solve(RGB2XYZ), 4)
## they also write (X, Y, Z)^t = M * (R, G, B)^t
## equal energy; rows sum to 1
eeXYZ2LMS <- matrix(c( 0.38971, 0.68898, -0.07868,
-0.22981, 1.18340, 0.04641,
0, 0, 1), 3, 3, byrow=TRUE)
eeLMS2XYZ <- round(solve(eeXYZ2LMS), 5)
## normalized to D65 daylight illumination
d65XYZ2LMS <- matrix(c( 0.4002, 0.7076, -0.0808,
-0.2263, 1.1653, 0.0457,
0, 0, 1), 3, 3, byrow=TRUE)
d65LMS2XYZ <- round(solve(d65XYZ2LMS), 5)
##########################################
## We assume that teh default behavior is to convert
## sRGB coordinates to (erqual energy) LMS coordinates
forward <- function(x) {
srgb2rgb(x) %*% t(RGB2XYZ) %*% t(eeXYZ2LMS)
}
## the round trip isn't completely symmetric, since we
## have to truncate to get back into the 0-1 limitations
## of visible space
backward <- function(x) {
y <- rgb2srgb(x %*% t(eeLMS2XYZ) %*% t(XYZ2RGB) )
y[y < 0] <- 0
y[y > 1] <- 1
y
}
##########################################
## Color deficit transformation matrices
## Deuteranope (most common form of red/green color deficit)
lms2lmsd <- matrix(c(1, 0, 0,
0.494207, 0, 1.24827,
0, 0, 1), 3, 3, byrow=TRUE)
## Protanope (another form of red/green color deficit)
lms2lmsp <- matrix(c(0, 2.02344, -2.52581,
0, 1, 0,
0, 0, 1), 3, 3, byrow=TRUE)
## Transformation matrix for Tritanope (a blue/yellow deficit - very rare)
lms2lmst <- matrix(c(1, 0, 0,
0, 1, 0,
-0.395913, 0.801109, 0), 3, 3, byrow=TRUE)
##########################################
colorDeficit <- function(rgb,
target = c("deuteranope", "protanope", "tritanope")) {
### handle different kinds of inputs
## start with a class from 'colorspace'
if (returnObject <- inherits(rgb, "sRGB")) {
obj <- rgb
rgb <- rgb@coords
}
## character strings are assumed to be hexadecimnal colors
if (returnHex <- is.character(rgb)) {
obj <- hex2RGB(rgb)
rgb <- obj@coords
}
### What kind of transformation do we want?
target <- match.arg(target)
xform <- switch(target,
deuteranope = lms2lmsd,
protanope = lms2lmsp,
tritanope = lms2lmst
)
### MAIN ALGORITHM
deficit <- backward(forward(rgb) %*% t(xform))
### Give the user what (s)he wants.
if (returnHex | returnObject) {
obj@coords <- deficit
deficit <- obj
}
if (returnHex) deficit <- hex(deficit)
deficit
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.