ryantimpe / brickr

3D LEGO models and mosaics from images using R and #tidyverse
Other
413 stars 56 forks source link

consider color matching in CIE LAB space or CIE2000 #1

Closed dylanbeaudette closed 5 years ago

dylanbeaudette commented 5 years ago

First of all this is just amazing. Congratulations on doing what many lego fans often dream about doing.

I am not sure, but I suspect that the lego colors are likely in the sRGB colorspace. This is a convenient color space for displaying colors on a screen but not the most accurate space to perform color matching. Would you be interested in using the CIELAB color space, or even better CIE2000 color distance metric? The CIELAB space is based on (typical) human perception of color and matching done in this color space is usually more realistic. It may not matter when working with a small palette of highly saturated colors but it might be worth a try.

There are a couple of ways to convert colors in R, my favorites are grDevices::convertColor() and farver::convert_colour(). Note that each specify the source color space in a slightly different manner, RGB is typically used to describe a family of color spaces while sRGB is quite specific to uncalibrated computer screens, HTML colors, and so on.

Here is a rather verbose example, based on a color system (Munsell) and methods used in soil science and geology.

library(aqp)
library(farver)

# lego colors
# assuming these are sRGB / D65 colors
legos <- read.csv('https://github.com/ryantimpe/LEGOMosaics/raw/master/Colors/Lego_Colors.csv', stringsAsFactors = FALSE)

# convert
legos.sRGB <- legos[, c('R', 'G', 'B')] / 255
leogs.LAB <- convert_colour(legos.sRGB, from = 'rgb', to = 'lab', white_from = 'D65', white_to = 'D65')

# sort colors based on distances in CIE LAB spacec
previewColors(rgb(legos.sRGB))

# test conversion to Munsell
rgb2munsell(legos.sRGB)

# color to match, result is sRGB
x <- parseMunsell('10YR 3/4', return_triplets=TRUE)

# compare example color to all lego colors via CIE2000
d <- compare_colour(from=x, to=legos.sRGB, from_space='rgb', to_space = 'rgb', method='cie2000')

# sort lego colors based on CIE2000 distances from exmaple color
previewColors(rgb(legos.sRGB), col.order=order(d), method='manual')

# check closest (perceptual) color
idx <- which.min(d)
legos[idx, ]

# back-transform to Munsell
rgb2munsell(legos.sRGB[idx, ])

You might be able to guess why this would be interesting to earth scientists.

ryantimpe commented 5 years ago

I definitely like keeping the project restricted to R packages already used by most people (dplyr, purrr, etc) but will try this out when I get a chance. I can see this helping with shadows getting assigned to a completely new color and speeding up the functions.

dylanbeaudette commented 5 years ago

In that case, Euclidean distance in CIE LAB via grDevices::convertColor() would keep the dependencies to a minimum.

dylanbeaudette commented 5 years ago

Another idea: image resampling can be done using the raster package in about 1 line of code. Just a thought. Incidentally, I had to install the tidyverse package.

ryantimpe commented 5 years ago

Revisiting this...

ryantimpe commented 5 years ago

Thanks for this. Ended up using the compare_color() function in farver. CEI94 looks best in general, though depends on the composition of the image. Leaving the original euclidean distance calculation in there as an alternative.

This is updated on the other branch. Will likely merge in August or September.

dylanbeaudette commented 5 years ago

Thanks for considering.

I'm curious as to how "best" is defined--color matching is a tricky thing. I have found that CIE DE2000 has been the most universally "reasonable" in the realm of soil science and field description of soil color. Either metric will be far more "realistic" than Euclidean distance in sRGB.

ryantimpe commented 5 years ago

Here are a few comparisons. CIE2000 seems like it loses some of the depth of the image. Overall, I'm happy that these options fix the problems with whites turning into light blue and light pink.

colorspace_unicorn colorspace_bobcat colorspace_flower colorspace_me

dylanbeaudette commented 5 years ago

Nice! An excellent way to compare the results, thanks for the demo. I wonder if "depth" (contrast?) can be enhanced by using a 2-step process:

  1. reduce original colors to a limited palette of 8-16 colors, via k-means
  2. match legos to the reduced palette via CIE color difference

Beyond that, a simple dithering step might be useful.

Too much?