Skip to content

Commit 2196b92

Browse files
committed
Add charts for colordiff to docs and Use docstrings for metrics
1 parent 9c08ccb commit 2196b92

File tree

4 files changed

+270
-46
lines changed

4 files changed

+270
-46
lines changed

docs/colordiffcharts.jl

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
2+
module ColorDiffCharts
3+
4+
using Colors
5+
6+
struct ColorDiffChartSVG <: Main.SVG
7+
buf::IOBuffer
8+
end
9+
10+
# julia_green, julia_red, julia_purple
11+
const c = Lab.([colorant"#389826", colorant"#CB3C33", colorant"#9558B2"])
12+
13+
function ColorDiffChartSVG(metric::Colors.DifferenceMetric)
14+
io = IOBuffer()
15+
16+
id = nameof(typeof(metric))
17+
18+
d12 = colordiff(c[1], c[2], metric=metric)
19+
d23 = colordiff(c[2], c[3], metric=metric)
20+
d31 = colordiff(c[3], c[1], metric=metric)
21+
22+
dn = 2*d31^2 - d23^2 + 2*d12^2
23+
ds0 = -(d31-d23-d12) * (d31-d23+d12) * (d31+d23-d12) * (d31+d23+d12)
24+
# `ds0` should be non-negative in metric systems.
25+
# However, DE_CMC is not metric but quasimetric.
26+
ds = max(ds0, 0)
27+
28+
x = [0,
29+
-sqrt(ds/dn)/2,
30+
sqrt(ds/dn)/2]
31+
32+
y = [-sqrt(dn) / 3,
33+
(( -d31^2 - d23^2 + 5*d12^2) * sqrt(dn)) / 6dn,
34+
((5*d31^2 - d23^2 - d12^2) * sqrt(dn)) / 6dn]
35+
36+
# verification
37+
if ds0 >= 0
38+
d12 hypot(x[1] - x[2], y[1] - y[2]) || error("distance mismatch: d12")
39+
d23 hypot(x[2] - x[3], y[2] - y[3]) || error("distance mismatch: d23")
40+
d31 hypot(x[3] - x[1], y[3] - y[1]) || error("distance mismatch: d31")
41+
end
42+
43+
scale = 7.5 / abs(y[1])
44+
45+
sx = scale .* x
46+
sy = scale .* y
47+
r = scale * 20
48+
49+
mx12, my12 = (sx[1] + sx[2]) * 0.5, (sy[1] + sy[2]) * 0.5
50+
mx23, my23 = (sx[2] + sx[3]) * 0.5, (sy[2] + sy[3]) * 0.5
51+
mx31, my31 = (sx[3] + sx[1]) * 0.5, (sy[3] + sy[1]) * 0.5
52+
53+
a = atan(sy[2] - sy[3], sx[2] - sx[3])
54+
dy23, dx23 = 8 .* sincos(a)
55+
56+
simplify(x) = replace(string(round(x, sigdigits=3)), r"\.0+$"=>"")
57+
rd12, rd23, rd31 = simplify.((d12, d23, d31))
58+
59+
write(io,
60+
"""
61+
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
62+
viewBox="-15 -12 30 30" width="30mm" height="30mm"
63+
stroke="none" stroke-linejoin="round"
64+
style="display:inline; margin-left:2em; margin-bottom:2em">
65+
<defs>
66+
<marker id="marker_s_$id" orient="auto" style="overflow:visible">
67+
<path d="M 7,-30 l -7,4 7,4 M 0,-26 h 9 M 0,-3 v -27"
68+
style="fill:none;stroke:currentColor;stroke-opacity:0.7;" />
69+
</marker>
70+
<marker id="marker_e_$id" orient="auto" style="overflow:visible">
71+
<path d="M -7,-30 l 7,4 -7,4 M 0,-26 h -9 M 0,-3 v -27"
72+
style="fill:none;stroke:currentColor;stroke-opacity:0.7;" />
73+
</marker>
74+
</defs>
75+
<g>
76+
<circle cx="$(sx[3])" cy="$(sy[3])" fill="#$(hex(c[3]))" r="$r" />
77+
<circle cx="$(sx[2])" cy="$(sy[2])" fill="#$(hex(c[2]))" r="$r" />
78+
<circle cx="$(sx[1])" cy="$(sy[1])" fill="#$(hex(c[1]))" r="$r" />
79+
</g>
80+
<g style="stroke:currentColor;stroke-width:0.2;stroke-opacity:0.4;
81+
marker-start:url(#marker_s_$id);marker-end:url(#marker_e_$id)">
82+
<path d="M$(sx[3]),$(sy[3]) L$(sx[2]),$(sy[2])"/>
83+
<path d="M$(sx[2]),$(sy[2]) L$(sx[1]),$(sy[1])"/>
84+
<path d="M$(sx[1]),$(sy[1]) L$(sx[3]),$(sy[3])"/>
85+
</g>
86+
<g fill="currentColor" style="font-size:2.8px;">
87+
<text x="$(mx12-3)" y="$my12" text-anchor="end">$rd12</text>
88+
<text x="$(mx23+dy23)" y="$(my23-dx23+1)" text-anchor="middle">$rd23</text>
89+
<text x="$(mx31+3)" y="$my31" text-anchor="start">$rd31</text>
90+
<text x="-14" y="17" style="font-size:2.5px;">$id</text>
91+
</g>
92+
</svg>""")
93+
ColorDiffChartSVG(io)
94+
end
95+
96+
end

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ function Base.show(io::IO, mime::MIME"image/svg+xml", svg::SVG)
77
end
88

99
include("crosssectionalcharts.jl")
10+
include("colordiffcharts.jl")
1011
include("colormaps.jl")
1112
include("namedcolorcharts.jl")
1213

docs/src/colordifferences.md

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,84 @@
11
# Color Differences
22

3-
The `colordiff` function gives an approximate value for the difference between two colors.
3+
The [`colordiff`](@ref) function gives an approximate value for the difference between two colors.
44

55
```jldoctest example; setup = :(using Colors)
6-
julia> colordiff(colorant"red", parse(Colorant, HSV(360, 0.75, 1)))
7-
8.178248292426845
6+
julia> colordiff(colorant"red", colorant"darkred")
7+
23.754149863643036
8+
9+
julia> colordiff(colorant"red", colorant"blue")
10+
52.88136782250768
11+
12+
julia> colordiff(HSV(0, 0.75, 0.5), HSL(0, 0.75, 0.5))
13+
19.48591066257135
814
```
915

10-
`colordiff(a::Color, b::Color; metric::DifferenceMetric=DE_2000())`
16+
```julia
17+
colordiff(a::Color, b::Color; metric=DE_2000())
18+
```
1119

1220
Evaluate the [CIEDE2000](http://en.wikipedia.org/wiki/Color_difference#CIEDE2000) color difference formula by default. This gives an approximate measure of the perceptual difference between two colors to a typical viewer. A larger number is returned for increasingly distinguishable colors.
1321

14-
Options for `DifferenceMetric` are as follows:
15-
16-
| Option | Action |
17-
| ---------- | ------- |
18-
|`DE_2000(kl::Float64, kc::Float64, kh::Float64)` | Specify the color difference using the recommended CIEDE2000 equation, with weighting parameters `kl`, `kc`, and `kh` as provided for in the recommendation.|
19-
|`DE_2000()` | - when not provided, these parameters default to 1. |
20-
|`DE_94(kl::Float64, kc::Float64, kh::Float64)` | Specify the color difference using the recommended CIEDE94 equation, with weighting parameters `kl`, `kc`, and `kh` as provided for in the recommendation. |
21-
|`DE_94()` | - hen not provided, these parameters default to 1. |
22-
|`DE_JPC79()` | Specify McDonald's "JP Coates Thread Company" color difference formula. |
23-
|`DE_CMC(kl::Float64, kc::Float64)` | Specify the color difference using the CMC equation, with weighting parameters `kl` and `kc`. |
24-
|`DE_CMC()` | - when not provided, these parameters default to 1. |
25-
|`DE_BFD(wp::XYZ, kl::Float64, kc::Float64)` | Specify the color difference using the BFD equation, with weighting parameters `kl` and `kc`. Additionally, a white point can be specified, because the BFD equation must convert between `XYZ` and `LAB` during the computation.|
26-
|`DE_BFD(kl::Float64, kc::Float64)` | |
27-
|`DE_BFD()` | - when not specified, the constants default to 1, and the white point defaults to CIED65. |
28-
|`DE_AB()` | Specify the original, Euclidean color difference equation. |
29-
|`DE_DIN99()` | Specify the Euclidean color difference equation applied in the `DIN99` uniform colorspace. |
30-
|`DE_DIN99d()` | Specify the Euclidean color difference equation applied in the `DIN99d` uniform colorspace. |
31-
|`DE_DIN99o()` | Specify the Euclidean color difference equation applied in the `DIN99o` uniform colorspace. |
22+
Options for `metric` are as follows:
23+
24+
| Metric | Summary |
25+
|:-------------------|:------------------------------------------------------------------------------|
26+
|[`DE_2000`](@ref) | The color difference using the recommended CIE Delta E 2000 equation. |
27+
|[`DE_94`](@ref) | The color difference using the recommended CIE Delta E 94 equation. |
28+
|[`DE_JPC79`](@ref) | McDonald's "JP Coates Thread Company" color difference formula. |
29+
|[`DE_CMC`](@ref) | The color difference using the CMC l:c equation. |
30+
|[`DE_BFD`](@ref) | The color difference using the BFD equation. |
31+
|[`DE_AB`](@ref) | The original ΔE*, Euclidean color difference equation in the `Lab` colorspace.|
32+
|[`DE_DIN99`](@ref) | The Euclidean color difference equation applied in the `DIN99` colorspace. |
33+
|[`DE_DIN99d`](@ref) | The Euclidean color difference equation applied in the `DIN99d` colorspace. |
34+
|[`DE_DIN99o`](@ref) | The Euclidean color difference equation applied in the `DIN99o` colorspace. |
35+
36+
37+
The following charts show the differences between the three colors for each
38+
metric with the default parameters:
39+
```@example diff
40+
using Colors # hide
41+
using Main: ColorDiffCharts # hide
42+
ColorDiffCharts.ColorDiffChartSVG(DE_2000()) # hide
43+
```
44+
```@example diff
45+
ColorDiffCharts.ColorDiffChartSVG(DE_94()) # hide
46+
```
47+
```@example diff
48+
ColorDiffCharts.ColorDiffChartSVG(DE_JPC79()) # hide
49+
```
50+
```@example diff
51+
ColorDiffCharts.ColorDiffChartSVG(DE_CMC()) # hide
52+
```
53+
```@example diff
54+
ColorDiffCharts.ColorDiffChartSVG(DE_BFD()) # hide
55+
```
56+
```@example diff
57+
ColorDiffCharts.ColorDiffChartSVG(DE_AB()) # hide
58+
```
59+
```@example diff
60+
ColorDiffCharts.ColorDiffChartSVG(DE_DIN99()) # hide
61+
```
62+
```@example diff
63+
ColorDiffCharts.ColorDiffChartSVG(DE_DIN99d()) # hide
64+
```
65+
```@example diff
66+
ColorDiffCharts.ColorDiffChartSVG(DE_DIN99o()) # hide
67+
```
68+
The difference in the size of circles in the charts above represents the
69+
difference in the scale. The radii of the circles are all 20 in their scale
70+
units, so larger circles mean that the metric returns smaller values. Therefore,
71+
we should not compare the color differences between different metrics.
3272

3373
```@docs
3474
colordiff
75+
DE_2000()
76+
DE_94()
77+
DE_JPC79()
78+
DE_CMC()
79+
DE_BFD()
80+
DE_AB()
81+
DE_DIN99()
82+
DE_DIN99d()
83+
DE_DIN99o()
3584
```

src/differences.jl

Lines changed: 102 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,132 @@ abstract type DifferenceMetric end
44

55
# TODO?: make the DifferenMetrics parametric, to preserve type-stability
66

7-
"CIE Delta E 2000 recommendation"
87
struct DE_2000 <: DifferenceMetric
98
kl::Float64
109
kc::Float64
1110
kh::Float64
12-
DE_2000(kl,kc,kh) = new(kl,kc,kh)
13-
DE_2000() = new(1,1,1)
1411
end
12+
"""
13+
DE_2000()
14+
DE_2000(kl, kc, kh)
15+
16+
Construct a metric of the CIE Delta E 2000 recommendation, with weighting
17+
parameters `kl`, `kc` and `kh` as provided for in the recommendation. When not
18+
provided, these parameters default to `1`.
19+
"""
20+
DE_2000() = DE_2000(1,1,1)
21+
1522

16-
"CIE Delta E 94 recommendation"
1723
struct DE_94 <: DifferenceMetric
1824
kl::Float64
1925
kc::Float64
2026
kh::Float64
21-
DE_94(kl,kc,kh) = new(kl,kc,kh)
22-
DE_94() = new(1,1,1)
2327
end
28+
"""
29+
DE_94()
30+
DE_94(kl, kc, kh)
31+
32+
Construct a metric of CIE Delta E 94 recommendation (1994), with weighting
33+
parameters `kl`, `kc` and `kh` as provided for in the recommendation. When not
34+
provided, these parameters default to `1`.
35+
The `DE_94` is more perceptually uniform than the [`DE_AB`](@ref), but has some
36+
non-uniformities resolved by the [`DE_2000`](@ref).
37+
"""
38+
DE_94() = DE_94(1,1,1)
39+
2440

25-
"McDonald \"JP Coates Thread Company\" formulation"
2641
struct DE_JPC79 <: DifferenceMetric
2742

2843
end
44+
"""
45+
DE_JPC79()
46+
47+
Construct a metric using McDonald's "JP Coates Thread Company" color difference
48+
formula.
49+
"""
50+
DE_JPC79()
51+
2952

30-
"CMC recommendation"
3153
struct DE_CMC <: DifferenceMetric
3254
kl::Float64
3355
kc::Float64
34-
DE_CMC(kl,kc) = new(kl,kc)
35-
DE_CMC() = new(1,1)
3656
end
57+
"""
58+
DE_CMC()
59+
DE_CMC(kl, kc)
60+
61+
Construct a metric using the CMC equation (CMC l:c), with weighting parameters
62+
`kl` and `kc`. When not provided, these parameters default to `1`.
63+
!!! note
64+
The `DE_CMC` is a quasimetric, i.e. violates symmetry. Therefore,
65+
`colordiff(a, b, metric=DE_CMC())` may not equal to
66+
`colordiff(b, a, metric=DE_CMC())`.
67+
"""
68+
DE_CMC() = DE_CMC(1,1)
69+
3770

38-
"BFD recommendation"
3971
struct DE_BFD <: DifferenceMetric
4072
wp::XYZ{Float64}
4173
kl::Float64
4274
kc::Float64
43-
DE_BFD(wp,kl,kc) = new(wp,kl,kc)
44-
DE_BFD() = new(WP_DEFAULT,1,1)
45-
DE_BFD(kl, kc) = new(WP_DEFAULT,kl, kc)
4675
end
76+
"""
77+
DE_BFD()
78+
DE_BFD([wp,] kl, kc)
79+
80+
Construct a metric using the BFD equation, with weighting parameters `kl` and
81+
`kc`. Additionally, a whitepoint `wp` can be specified, because the BFD equation
82+
must convert between `XYZ` and `Lab` during the computation. When not provided,
83+
`kl` and `kc` default to `1`, and `wp` defaults to CIE D65 (`Colors.WP_D65`).
84+
"""
85+
DE_BFD() = DE_BFD(WP_DEFAULT,1,1)
86+
DE_BFD(kl, kc) = DE_BFD(WP_DEFAULT,kl, kc)
87+
4788

48-
"The original CIE Delta E equation (Euclidian)"
4989
struct DE_AB <: DifferenceMetric
5090

5191
end
92+
"""
93+
DE_AB()
94+
95+
Construct a metric of the original CIE Delta E equation (ΔE*ab), or Euclidean
96+
color difference equation in the `Lab` (CIELAB) colorspace.
97+
"""
98+
DE_AB()
5299

53-
"DIN99 color difference (Euclidian)"
54100
struct DE_DIN99 <: DifferenceMetric
55101

56102
end
103+
"""
104+
DE_DIN99()
105+
106+
Construct a metric using Euclidean color difference equation applied in the
107+
`DIN99` colorspace.
108+
"""
109+
DE_DIN99()
57110

58-
"DIN99d color difference (Euclidian)"
59111
struct DE_DIN99d <: DifferenceMetric
60112

61113
end
114+
"""
115+
DE_DIN99d()
116+
117+
Construct a metric using Euclidean color difference equation applied in the
118+
`DIN99d` colorspace.
119+
"""
120+
DE_DIN99d()
62121

63-
"DIN99o color difference (Euclidian)"
64122
struct DE_DIN99o <: DifferenceMetric
65123

66124
end
125+
"""
126+
DE_DIN99o()
127+
128+
Construct a metric using Euclidean color difference equation applied in the
129+
`DIN99o` colorspace.
130+
"""
131+
DE_DIN99o()
132+
67133

68134
# Compute the mean of two hue angles
69135
function mean_hue(h1, h2)
@@ -403,12 +469,24 @@ end
403469

404470
# Default to Delta E 2000
405471
"""
406-
colordiff(a, b; metric::DifferenceMetric=DE_2000())
407-
408-
Compute an approximate measure of the perceptual difference between
409-
colors `a` and `b`. Optionally, a `metric` may be supplied, chosen
410-
among `DE_2000` (the default), `DE_94`, `DE_JPC79`, `DE_CMC`,
411-
`DE_BFD`, `DE_AB`, `DE_DIN99`, `DE_DIN99d`, `DE_DIN99o`.
472+
colordiff(a, b; metric=DE_2000())
473+
474+
Compute an approximate measure of the perceptual difference between colors `a`
475+
and `b`. Optionally, a `metric` may be supplied, chosen among [`DE_2000`](@ref)
476+
(the default), [`DE_94`](@ref), [`DE_JPC79`](@ref), [`DE_CMC`](@ref),
477+
[`DE_BFD`](@ref), [`DE_AB`](@ref), [`DE_DIN99`](@ref), [`DE_DIN99d`](@ref) and
478+
[`DE_DIN99o`](@ref).
479+
480+
The return value is a non-negative number in a type depending on the colors and
481+
metric.
482+
483+
!!! note
484+
The supported metrics measure the difference within `Lab` or its variant
485+
colorspaces. When the input colors are not in the colorspace internally used
486+
by the metric, the colors (e.g. in `RGB`) are converted with the default
487+
whitepoint CIE D65 (`Colors.WP_D65`). If you want to use another whitepoint,
488+
convert the colors into the colorspace used by metric (e.g. `Lab` for
489+
[`DE_2000`](@ref)) in advance.
412490
"""
413491
colordiff(ai::Union{Number, Color},
414492
bi::Union{Number, Color};

0 commit comments

Comments
 (0)