qualpal 2.3.0
Loading...
Searching...
No Matches
metrics.h
Go to the documentation of this file.
1
10#pragma once
11
12#include <cassert>
13#include <cmath>
14#include <qualpal/colors.h>
15
16namespace qualpal {
17
35namespace metrics {
36namespace detail {
37inline double
38cosd(double degrees)
39{
40 return std::cos(degrees * M_PI / 180.0);
41}
42
43inline double
44sind(double degrees)
45{
46 return std::sin(degrees * M_PI / 180.0);
47}
48
49inline double
50tand(double degrees)
51{
52 return std::tan(degrees * M_PI / 180.0);
53}
54
55inline double
56atan2d(double y, double x)
57{
58 double deg = std::atan2(y, x) * 180.0 / M_PI;
59 return (deg >= 0) ? deg : deg + 360.0;
60}
61
62inline double
63square(double x)
64{
65 return x * x;
66}
67} // namespace detail
68
69// Forward declarations
70class RGB;
71class HSL;
72class XYZ;
73class Lab;
74class DIN99d;
75
82enum class MetricType
83{
84 DIN99d,
85 CIE76,
87};
88
95class DIN99d
96{
97private:
98 bool use_power_transform;
99 double power;
100 double scale;
101
102public:
110 explicit DIN99d(bool use_power_transform = true,
111 double power = 0.74,
112 double scale = 1.28)
113 : use_power_transform(use_power_transform)
114 , power(power)
115 , scale(scale)
116 {
117 }
118
127 template<typename ColorType1, typename ColorType2>
128 double operator()(const ColorType1& c1, const ColorType2& c2) const
129 {
130 colors::DIN99d d1(c1), d2(c2);
131 double d = std::hypot(d1.l() - d2.l(), d1.a() - d2.a(), d1.b() - d2.b());
132
133 if (use_power_transform) {
134 return std::pow(d, power) * scale;
135 } else {
136 return d;
137 }
138 }
139};
140
147struct CIE76
148{
157 template<typename ColorType1, typename ColorType2>
158 double operator()(const ColorType1& c1, const ColorType2& c2) const
159 {
160 colors::Lab l1(c1), l2(c2);
161 return std::hypot(l1.l() - l2.l(), l1.a() - l2.a(), l1.b() - l2.b());
162 }
163};
164
172{
173private:
174 double K_L;
175 double K_C;
176 double K_H;
177
178public:
185 explicit CIEDE2000(double K_L = 1.0, double K_C = 1.0, double K_H = 1.0)
186 : K_L(K_L)
187 , K_C(K_C)
188 , K_H(K_H)
189 {
190 assert((K_L > 0 && K_C > 0 && K_H > 0) &&
191 "CIEDE2000 weighting factors must be positive");
192 }
193
202 template<typename ColorType1, typename ColorType2>
203 double operator()(const ColorType1& c1, const ColorType2& c2) const
204 {
205 using namespace detail;
206
207 colors::Lab x(c1), y(c2);
208
209 double L_hat_prime = (x.l() + y.l()) / 2.0;
210 double C1 = std::hypot(x.a(), x.b());
211 double C2 = std::hypot(y.a(), y.b());
212 double C_hat = (C1 + C2) / 2.0;
213 double G = 0.5 * (1 - std::sqrt(std::pow(C_hat, 7) /
214 (std::pow(C_hat, 7) + std::pow(25.0, 7))));
215 double a1_prime = x.a() * (1.0 + G);
216 double a2_prime = y.a() * (1.0 + G);
217 double C1_prime = std::hypot(a1_prime, x.b());
218 double C2_prime = std::hypot(a2_prime, y.b());
219 double C_hat_prime = (C1_prime + C2_prime) / 2.0;
220
221 double h1_prime = atan2d(x.b(), a1_prime);
222
223 if (h1_prime < 0) {
224 h1_prime += 360;
225 }
226
227 double h2_prime = atan2d(y.b(), a2_prime);
228
229 if (h2_prime < 0) {
230 h2_prime += 360;
231 }
232
233 double H_hat_prime = std::abs(h1_prime - h2_prime) > 180
234 ? (h1_prime + h2_prime + 360) / 2.0
235 : (h1_prime + h2_prime) / 2.0;
236
237 double T = 1.0 - 0.17 * cosd(H_hat_prime - 30) +
238 0.24 * cosd(2 * H_hat_prime) + 0.32 * cosd(3 * H_hat_prime + 6) -
239 0.20 * cosd(4 * H_hat_prime - 63);
240
241 double delta_h_prime = h2_prime - h1_prime;
242 if (std::abs(delta_h_prime) > 180) {
243 if (h2_prime <= h1_prime)
244 delta_h_prime += 360;
245 else
246 delta_h_prime -= 360;
247 }
248
249 double delta_L_prime = y.l() - x.l();
250 double delta_C_prime = C2_prime - C1_prime;
251
252 double delta_H_prime =
253 2 * std::sqrt(C1_prime * C2_prime) * sind(delta_h_prime / 2.0);
254 double S_L = 1 + (0.015 * std::pow(L_hat_prime - 50, 2)) /
255 std::sqrt(20 + std::pow(L_hat_prime - 50, 2));
256
257 double S_C = 1 + 0.045 * C_hat_prime;
258 double S_H = 1 + 0.015 * C_hat_prime * T;
259
260 double delta_theta = 30 * std::exp(-std::pow((H_hat_prime - 275) / 25, 2));
261
262 double R_C = 2 * std::sqrt(std::pow(C_hat_prime, 7) /
263 (std::pow(C_hat_prime, 7) + std::pow(25.0, 7)));
264
265 double R_T = -R_C * sind(2 * delta_theta);
266 double out = std::sqrt(square(delta_L_prime / (K_L * S_L)) +
267 square(delta_C_prime / (K_C * S_C)) +
268 square(delta_H_prime / (K_H * S_H)) +
269 R_T * (delta_C_prime / (K_C * S_C)) *
270 (delta_H_prime / (K_H * S_H)));
271
272 assert(out >= 0 && "CIEDE2000 color difference must be non-negative");
273 assert(std::isfinite(out) &&
274 "CIEDE2000 color difference must not be finite");
275
276 return out;
277 }
278};
279} // namespace metrics
280} // namespace qualpal
DIN99d color space representation.
Definition colors.h:356
double b() const
Get blue-yellow component.
Definition colors.h:425
double l() const
Get lightness component.
Definition colors.h:421
double a() const
Get green-red component.
Definition colors.h:423
Lab color space representation (CIE L*a*b*)
Definition colors.h:439
double b() const
Get blue-yellow component.
Definition colors.h:501
double l() const
Get lightness [0,100].
Definition colors.h:497
double a() const
Get green-red component.
Definition colors.h:499
CIEDE2000 (Delta E 2000) color difference.
Definition metrics.h:172
double operator()(const ColorType1 &c1, const ColorType2 &c2) const
Calculate CIEDE2000 color difference.
Definition metrics.h:203
CIEDE2000(double K_L=1.0, double K_C=1.0, double K_H=1.0)
Construct CIEDE2000 metric with optional weighting factors.
Definition metrics.h:185
DIN99d color difference with optional power transformation.
Definition metrics.h:96
double operator()(const ColorType1 &c1, const ColorType2 &c2) const
Calculate color difference between two colors.
Definition metrics.h:128
DIN99d(bool use_power_transform=true, double power=0.74, double scale=1.28)
Construct DIN99d metric with configurable parameters.
Definition metrics.h:110
Color representation classes.
MetricType
Supported color difference metrics for palette generation.
Definition metrics.h:83
Qualitative color palette generation library.
Definition analyze.h:19
CIE76 (Delta E 1976) color difference.
Definition metrics.h:148
double operator()(const ColorType1 &c1, const ColorType2 &c2) const
Calculate CIE76 color difference.
Definition metrics.h:158