colordistance
Most of the worked examples in the colordistance
vignettes use RGB space for simplicity and speed. As discussed in the color spaces vignette, however, you’ll often want to use CIELab color space when possible. This vignette will work through an entire CIELab analysis on the Heliconius butterfly example that comes with the package.
The convertColor
function in the grDevices
package allows RGB pixels to be approximately converted into CIELab color space using reference white. The reference white provides information about how a highly reflective (white) surface would look under these lighting conditions, which then allows other colors to be interpreted relative to that white. In the “Luminance” (L) axis of CIELab space, this white would be the 100 on the 0-100 scale.
(A note on this from Ocean Optics: “There is no bound of 100 anywhere. In other words, ‘100 for the brightest white’ is all relative unless you mean ‘the brightest white that is possible in the entire universe’.”)
The supported standard CIE reference whites are:
This example will use the “D65” reference white, since it’s usually the default for color conversion.
The loadImage
function will convert pixels to CIELab space if the CIELab
flag is set to TRUE
. Because the RGB to CIELab conversion is so slow, colordistance
functions that perform CIELab conversions default to converting a random subset of pixels, specified with the sample.size
argument.
# Get a list of all the images in the examples folder
image_folders <- dir(system.file("extdata/Heliconius", package = "colordistance"), full.names = T)
image_paths <- sapply(image_folders, colordistance::getImagePaths)
dim(image_paths) <- NULL
# Read in the first image with CIELab pixels
H1 <- colordistance::loadImage(image_paths[1], lower = rep(0.8, 3), upper = rep(1, 3),
CIELab = TRUE, ref.white = "D65", sample.size = 10000)
#> From reference white:
#> To reference white: D65
#> Converting 10000 randomly selected pixel(s) from sRGB color space to Lab color space
The pixels are stored in the filtered.lab.2d
element:
head(H1$filtered.lab.2d)
#> L a.x b
#> 1 41.51080 22.1694039 41.09355
#> 2 71.33491 12.1888931 65.84336
#> 3 55.62188 18.9508402 48.11196
#> 4 64.66218 25.3264809 65.06182
#> 5 66.33077 25.7331876 66.69854
#> 6 76.37665 -0.3039349 7.83746
They can be visualized using the plotPixels
function, specifying color.space = "lab"
:
Like RGB and HSV, colordistance
provides both a histogram binning method and a K-means clustering method for grouping colors together. Note that the histogram binning method uses a different function, getLabHist
rather than getImageHist
.
The major differences with getLabHist
are that it requires the specification of a reference white, and that it gives you the option of setting the ranges for the a and b channels of CIELab space. Unlike RGB, where each channel invariably ranges from 0 to 1, the a and b channels of CIELab are theoretically unbounded. They are usually between -128 and 127, but depending on the reference white may have much narrower ranges than this. There’s no real harm in having boundaries that fall well outside the actual range of the data, but it does have a small impact on both speed and precision.
par(mfrow = c(1, 2))
# Setting boundaries
lab_hist <- colordistance::getLabHist(image_paths[1], bins = 3,
sample.size = 10000, ref.white = "D65", bin.avg = TRUE,
plotting = TRUE, lower = rep(0.8, 3), upper = rep(1, 3),
a.bounds = c(-100, 100), b.bounds = c(-100, 100))
#> Accuracy of CIE Lab color space depends on specification of an appropriate white reference. See 'Color spaces' vignette for more information.
#> From reference white:
#> To reference white: D65
#> Converting 10000 randomly selected pixel(s) from sRGB color space to Lab color space
#> Using 3^3 = 27 total bins
# Leaving default boundaries (minor difference)
lab_hist <- colordistance::getLabHist(image_paths[1], bins = 3,
sample.size = 10000, ref.white = "D65", bin.avg = TRUE,
plotting = TRUE, lower = rep(0.8, 3), upper = rep(1, 3))
#> Accuracy of CIE Lab color space depends on specification of an appropriate white reference. See 'Color spaces' vignette for more information.
#> From reference white:
#> To reference white: D65
#> Converting 10000 randomly selected pixel(s) from sRGB color space to Lab color space
#> Using 3^3 = 27 total bins
getKMeanClusters
works almost exactly the same:
Once you have CIELab clusters, everything proceeds more or less the same as with RGB color space.
# Generate clusters
par(mfrow = c(2, 4))
lab_hist_list <- colordistance::getLabHistList(image_paths, bins = 2, sample.size = 10000,
ref.white = "D65", lower = rep(0.8, 3), upper = rep(1, 3),
plotting = TRUE, pausing = FALSE)
#> Accuracy of CIE Lab color space depends on specification of an appropriate white reference. See 'Color spaces' vignette for more information.
#> Using 2^3 = 8 total bins
#>
|
| | 0%
#>
|
|======== | 12%
#>
|
|================ | 25%
#>
|
|======================== | 38%
#>
|
|================================ | 50%
#>
|
|========================================= | 62%
#>
|
|================================================= | 75%
#>
|
|========================================================= | 88%
#>
|
|=================================================================| 100%
# Get distance matrix
par(mfrow = c(1,1))
lab_dist_matrix <- colordistance::getColorDistanceMatrix(lab_hist_list, plotting = TRUE)
The major difference is in your ability to interpret these results. Unlike in RGB space, where you have a well-defined maximum color distance using EMD (the cost of moving all pixels the farthest possible linear distance in a cube with sides of length 1 = \(\sqrt{3}\)), there is no absolute upper limit to the color distance in CIELab space. However, the results can still be interpreted relative to each other. You can also determine reasonable upper limits given a certain reference white, since you’re starting with RGB pixels, which can only occupy a subset of CIELab space.