qualpal 3.3.0
Loading...
Searching...
No Matches
metrics.h
Go to the documentation of this file.
1
13#pragma once
14
15#include <cassert>
16#include <cmath>
17#include <qualpal/colors.h>
18
19namespace qualpal {
20
38namespace metrics {
39namespace detail {
40inline double
41cosd(double degrees)
42{
43 return std::cos(degrees * M_PI / 180.0);
44}
45
46inline double
47sind(double degrees)
48{
49 return std::sin(degrees * M_PI / 180.0);
50}
51
52inline double
53tand(double degrees)
54{
55 return std::tan(degrees * M_PI / 180.0);
56}
57
58inline double
59atan2d(double y, double x)
60{
61 double deg = std::atan2(y, x) * 180.0 / M_PI;
62 return (deg >= 0) ? deg : deg + 360.0;
63}
64
65inline double
66square(double x)
67{
68 return x * x;
69}
70} // namespace detail
71
72// Forward declarations
73class RGB;
74class HSL;
75class XYZ;
76class Lab;
77class DIN99d;
78
90enum class MetricType
91{
92 DIN99d,
93 CIE76,
95};
96
113{
114private:
115 bool use_power_transform;
116 double power;
117 double scale;
118
119public:
127 explicit DIN99d(bool use_power_transform = true,
128 double power = 0.74,
129 double scale = 1.28)
130 : use_power_transform(use_power_transform)
131 , power(power)
132 , scale(scale)
133 {
134 }
135
144 template<typename ColorType1, typename ColorType2>
145 double operator()(const ColorType1& c1, const ColorType2& c2) const
146 {
147 colors::DIN99d d1(c1), d2(c2);
148 double d = std::hypot(d1.l() - d2.l(), d1.a() - d2.a(), d1.b() - d2.b());
149
150 if (use_power_transform) {
151 return std::pow(d, power) * scale;
152 } else {
153 return d;
154 }
155 }
156};
157
169struct CIE76
170{
179 template<typename ColorType1, typename ColorType2>
180 double operator()(const ColorType1& c1, const ColorType2& c2) const
181 {
182 colors::Lab l1(c1), l2(c2);
183 return std::hypot(l1.l() - l2.l(), l1.a() - l2.a(), l1.b() - l2.b());
184 }
185};
186
206{
207private:
208 double K_L;
209 double K_C;
210 double K_H;
211
212public:
219 explicit CIEDE2000(double K_L = 1.0, double K_C = 1.0, double K_H = 1.0)
220 : K_L(K_L)
221 , K_C(K_C)
222 , K_H(K_H)
223 {
224 assert((K_L > 0 && K_C > 0 && K_H > 0) &&
225 "CIEDE2000 weighting factors must be positive");
226 }
227
236 template<typename ColorType1, typename ColorType2>
237 double operator()(const ColorType1& c1, const ColorType2& c2) const
238 {
239 using namespace detail;
240
241 colors::Lab x(c1), y(c2);
242
243 double L_hat_prime = (x.l() + y.l()) / 2.0;
244 double C1 = std::hypot(x.a(), x.b());
245 double C2 = std::hypot(y.a(), y.b());
246 double C_hat = (C1 + C2) / 2.0;
247 double G = 0.5 * (1 - std::sqrt(std::pow(C_hat, 7) /
248 (std::pow(C_hat, 7) + std::pow(25.0, 7))));
249 double a1_prime = x.a() * (1.0 + G);
250 double a2_prime = y.a() * (1.0 + G);
251 double C1_prime = std::hypot(a1_prime, x.b());
252 double C2_prime = std::hypot(a2_prime, y.b());
253 double C_hat_prime = (C1_prime + C2_prime) / 2.0;
254
255 double h1_prime = atan2d(x.b(), a1_prime);
256
257 if (h1_prime < 0) {
258 h1_prime += 360;
259 }
260
261 double h2_prime = atan2d(y.b(), a2_prime);
262
263 if (h2_prime < 0) {
264 h2_prime += 360;
265 }
266
267 double H_hat_prime = std::abs(h1_prime - h2_prime) > 180
268 ? (h1_prime + h2_prime + 360) / 2.0
269 : (h1_prime + h2_prime) / 2.0;
270
271 double T = 1.0 - 0.17 * cosd(H_hat_prime - 30) +
272 0.24 * cosd(2 * H_hat_prime) + 0.32 * cosd(3 * H_hat_prime + 6) -
273 0.20 * cosd(4 * H_hat_prime - 63);
274
275 double delta_h_prime = h2_prime - h1_prime;
276 if (std::abs(delta_h_prime) > 180) {
277 if (h2_prime <= h1_prime)
278 delta_h_prime += 360;
279 else
280 delta_h_prime -= 360;
281 }
282
283 double delta_L_prime = y.l() - x.l();
284 double delta_C_prime = C2_prime - C1_prime;
285
286 double delta_H_prime =
287 2 * std::sqrt(C1_prime * C2_prime) * sind(delta_h_prime / 2.0);
288 double S_L = 1 + (0.015 * std::pow(L_hat_prime - 50, 2)) /
289 std::sqrt(20 + std::pow(L_hat_prime - 50, 2));
290
291 double S_C = 1 + 0.045 * C_hat_prime;
292 double S_H = 1 + 0.015 * C_hat_prime * T;
293
294 double delta_theta = 30 * std::exp(-std::pow((H_hat_prime - 275) / 25, 2));
295
296 double R_C = 2 * std::sqrt(std::pow(C_hat_prime, 7) /
297 (std::pow(C_hat_prime, 7) + std::pow(25.0, 7)));
298
299 double R_T = -R_C * sind(2 * delta_theta);
300 double out = std::sqrt(square(delta_L_prime / (K_L * S_L)) +
301 square(delta_C_prime / (K_C * S_C)) +
302 square(delta_H_prime / (K_H * S_H)) +
303 R_T * (delta_C_prime / (K_C * S_C)) *
304 (delta_H_prime / (K_H * S_H)));
305
306 assert(out >= 0 && "CIEDE2000 color difference must be non-negative");
307 assert(std::isfinite(out) &&
308 "CIEDE2000 color difference must not be finite");
309
310 return out;
311 }
312};
313} // namespace metrics
314} // namespace qualpal
DIN99d color space representation.
Definition colors.h:405
double b() const
Get blue-yellow component.
Definition colors.h:474
double l() const
Get lightness component.
Definition colors.h:470
double a() const
Get green-red component.
Definition colors.h:472
Lab color space representation (CIE L*a*b*).
Definition colors.h:493
double b() const
Get blue-yellow component.
Definition colors.h:555
double l() const
Get lightness [0,100].
Definition colors.h:551
double a() const
Get green-red component.
Definition colors.h:553
CIEDE2000 (Delta E 2000) color difference metric.
Definition metrics.h:206
double operator()(const ColorType1 &c1, const ColorType2 &c2) const
Calculate CIEDE2000 color difference.
Definition metrics.h:237
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:219
DIN99d color difference metric with optional power transformation.
Definition metrics.h:113
double operator()(const ColorType1 &c1, const ColorType2 &c2) const
Calculate color difference between two colors.
Definition metrics.h:145
DIN99d(bool use_power_transform=true, double power=0.74, double scale=1.28)
Construct DIN99d metric with configurable parameters.
Definition metrics.h:127
Color representation classes.
MetricType
Supported color difference metrics for palette generation and analysis.
Definition metrics.h:91
Qualitative color palette generation library.
Definition analyze.h:21
CIE76 (Delta E 1976) color difference metric.
Definition metrics.h:170
double operator()(const ColorType1 &c1, const ColorType2 &c2) const
Calculate CIE76 color difference.
Definition metrics.h:180