Negative rgb values
EmilHvitfeldt opened this issue · 2 comments
Sometimes going from rgb to yxy and back gives negative values for rgb.
library(farver)
spectrum1 <- t(col2rgb(rainbow(10)))
spectrum2 <- farver::convert_colour(spectrum1, "rgb", "yxy")
spectrum3 <- farver::convert_colour(spectrum2, "yxy", "rgb")
plot(as.numeric(spectrum1 - spectrum3))
spectrum1
#> red green blue
#> [1,] 255 0 0
#> [2,] 255 153 0
#> [3,] 204 255 0
#> [4,] 51 255 0
#> [5,] 0 255 102
#> [6,] 0 255 255
#> [7,] 0 102 255
#> [8,] 51 0 255
#> [9,] 204 0 255
#> [10,] 255 0 153
spectrum3
#> [,1] [,2] [,3]
#> [1,] 2.550000e+02 4.342722e-04 -5.629177e-05
#> [2,] 2.550000e+02 1.530000e+02 -9.327647e-05
#> [3,] 2.040000e+02 2.550000e+02 -1.500950e-04
#> [4,] 5.100003e+01 2.550000e+02 -1.179680e-04
#> [5,] 1.552075e-04 2.550000e+02 1.020000e+02
#> [6,] 2.982680e-04 2.550000e+02 2.550000e+02
#> [7,] 1.826908e-04 1.020000e+02 2.550000e+02
#> [8,] 5.100004e+01 -4.230843e-05 2.550000e+02
#> [9,] 2.040000e+02 2.055405e-04 2.550000e+02
#> [10,] 2.550000e+02 4.162154e-04 1.530000e+02
It is fairly expected to get a little bit of noise, but it become troublesome when the noise leads to invalid numbers. Is this something you think farver
should handle internally or should be adjusted for by the individual user?
Yes, farver should def handle this, and I thought it did. Will get fixed
Okay cool!
furthermore after playing around a little bit more, it seems that some of the conversions it also seems to work regardless of the input being valid
library(farver)
spectrum1 <- t(col2rgb(rainbow(3))) - 1000
spectrum2 <- farver::convert_colour(spectrum1, "rgb", "yxy")
spectrum3 <- farver::convert_colour(spectrum2, "yxy", "rgb")
spectrum1
#> red green blue
#> [1,] -745 -1000 -1000
#> [2,] -1000 -745 -1000
#> [3,] -1000 -1000 -745
spectrum3
#> [,1] [,2] [,3]
#> [1,] -745.0000 -1000.0001 -1000
#> [2,] -999.9999 -745.0001 -1000
#> [3,] -999.9999 -1000.0002 -745
spectrum2 <- farver::convert_colour(spectrum1, "rgb", "hsl")
spectrum3 <- farver::convert_colour(spectrum2, "hsl", "rgb")
spectrum1
#> red green blue
#> [1,] -745 -1000 -1000
#> [2,] -1000 -745 -1000
#> [3,] -1000 -1000 -745
spectrum3
#> [,1] [,2] [,3]
#> [1,] -745 -1000 -1000
#> [2,] -1000 -745 -1000
#> [3,] -1000 -1000 -745
spectrum2 <- farver::convert_colour(spectrum1, "rgb", "hsv")
spectrum3 <- farver::convert_colour(spectrum2, "hsv", "rgb")
spectrum1
#> red green blue
#> [1,] -745 -1000 -1000
#> [2,] -1000 -745 -1000
#> [3,] -1000 -1000 -745
spectrum3
#> [,1] [,2] [,3]
#> [1,] -745 -745 -745
#> [2,] -745 -745 -745
#> [3,] -745 -745 -745
with the rgb->hsl->rgb being exact. you might want to validate input too.
Using a very bruteforce approach I got to the following
library(magrittr)
all_colors <- expand.grid(red = 0:255, blue = 0:255, green = 0:255) %>%
as.matrix()
check <- function(colors, space) {
all_colors_out <- farver::convert_colour(colors, "rgb", space)
all_colors_back <- farver::convert_colour(all_colors_out, space, "rgb")
data.frame(
space = space,
n_na = sum(is.na(all_colors_back)),
n_under_0 = sum(all_colors_back < 0, na.rm = TRUE),
n_over_255 = sum(all_colors_back > 255, na.rm = TRUE),
stringsAsFactors = FALSE
)
}
all_spaces <- c("cmy", "cmyk", "hsl", "hsb", "hsv", "lab", "hunterlab", "lch",
"luv", "rgb", "xyz", "yxy")
purrr::map_df(all_spaces, ~ check(all_colors, .x))
#> space n_na n_under_0 n_over_255
#> 1 cmy 0 0 0
#> 2 cmyk 0 0 0
#> 3 hsl 0 0 5238
#> 4 hsb 0 0 0
#> 5 hsv 0 0 0
#> 6 lab 0 77711 119907
#> 7 hunterlab 0 77711 119907
#> 8 lch 0 77711 119907
#> 9 luv 3 77711 119907
#> 10 rgb 0 0 0
#> 11 xyz 0 77711 119907
#> 12 yxy 3 77711 119907
And a little exploration regarding rgb->hsl->rgb
library(magrittr)
all_colors <- expand.grid(red = 0:255, blue = 0:255, green = 0:255) %>%
as.matrix()
all_colors_out <- farver::convert_colour(all_colors, "rgb", "hsl")
all_colors_back <- farver::convert_colour(all_colors_out, "hsl", "rgb")
hsl_errors <- as.data.frame(cbind(all_colors, all_colors_back)) %>%
dplyr::filter(V4 > 255 | V5 > 255 | V6 > 255)
nrow(hsl_errors)
#> [1] 4729
hsl_errors %>%
dplyr::summarise(same = sum(red == blue & blue == green),
red_n = sum(red == 255),
blue_n = sum(red != 255 & blue == 255),
green_n = sum(red != 255 & blue != 255 & green == 255)
) %>%
print() %>%
sum()
#> same red_n blue_n green_n
#> 1 253 1497 1492 1488
#> [1] 4730
gives us that we get errors when
- red, green and blue have the same value (grayscale)
- either red, green or blue have 255 as a value.