Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
deltaE.c
Go to the documentation of this file.
1/*
2 * This file is part of darktable,
3 * Copyright (C) 2016 johannes hanika.
4 * Copyright (C) 2016 Tobias Ellinghaus.
5 * Copyright (C) 2020 Pascal Obry.
6 * Copyright (C) 2021 Ralf Brown.
7 * Copyright (C) 2022 Martin Baƙinka.
8 *
9 * darktable is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * darktable is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with darktable. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "deltaE.h"
24
25#ifndef _XOPEN_SOURCE
26#define _XOPEN_SOURCE 600
27#endif
28
29#include <math.h>
30
31
32#define DEG2RAD(deg) (deg * M_PI / 180.0)
33#define RAD2DEG(rad) (rad * 180.0 / M_PI)
34
35// http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE76.html
37{
38 float dE = 0.0;
39 for(int i = 0; i < 3; i++)
40 {
41 float difference = Lab0[i] - Lab1[i];
42 dE += difference * difference;
43 }
44 return sqrtf(dE);
45}
46
47// http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html
49{
50 float L_ip = (Lab0[0] + Lab1[0]) * 0.5;
51 float C1 = sqrtf(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
52 float C2 = sqrtf(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
53 float C_i = (C1 + C2) * 0.5;
54 float G = (1.0 - sqrtf(powf(C_i, 7) / (powf(C_i, 7) + powf(25, 7)))) * 0.5;
55 float a1_p = Lab0[1] * (1 + G);
56 float a2_p = Lab1[1] * (1 + G);
57 float C1_p = sqrtf(a1_p * a1_p + Lab0[2] * Lab0[2]);
58 float C2_p = sqrtf(a2_p * a2_p + Lab1[2] * Lab1[2]);
59 float C_ip = (C1_p + C2_p) * 0.5;
60 float h1_p = RAD2DEG(atan2f(Lab0[2], a1_p));
61 if(h1_p < 0) h1_p += 360.0;
62 float h2_p = RAD2DEG(atan2f(Lab1[2], a2_p));
63 if(h2_p < 0) h2_p += 360.0;
64 float H_ip;
65 if(fabsf(h1_p - h2_p) > 180.0)
66 H_ip = (h1_p + h2_p + 360.0) * 0.5;
67 else
68 H_ip = (h1_p + h2_p) * 0.5;
69 float T = 1.0 - 0.17 * cosf(DEG2RAD(H_ip - 30.0)) + 0.24 * cosf(DEG2RAD(2.0 * H_ip))
70 + 0.32 * cosf(DEG2RAD(3.0 * H_ip + 6.0)) - 0.20 * cosf(DEG2RAD(4.0 * H_ip - 63.0));
71 float dh_p = h2_p - h1_p;
72 if(fabsf(dh_p) > 180.0)
73 {
74 if(h2_p <= h1_p)
75 dh_p += 360.0;
76 else
77 dh_p -= 360.0;
78 }
79 float dL_p = Lab1[0] - Lab0[0];
80 float dC_p = C2_p - C1_p;
81 float dH_p = 2.0 * sqrtf(C1_p * C2_p) * sinf(DEG2RAD(dh_p * 0.5));
82 float SL = 1.0 + ((0.015 * (L_ip - 50.0) * (L_ip - 50.0)) / sqrtf(20.0 + (L_ip - 50.0) * (L_ip - 50.0)));
83 float SC = 1.0 + 0.045 * C_ip;
84 float SH = 1.0 + 0.015 * C_ip * T;
85 float dtheta = 30.0 * expf(-1.0 * ((H_ip - 275.0) / 25.0) * ((H_ip - 275.0) / 25.0));
86 float RC = 2.0 * sqrtf(powf(C_ip, 7) / (powf(C_ip, 7) + powf(25, 7)));
87 float RT = -1.0 * RC * sinf(DEG2RAD(2.0 * dtheta));
88 float KL = 1.0;
89 float KC = 1.0;
90 float KH = 1.0;
91
92 float dE = sqrtf((dL_p / (KL * SL)) * (dL_p / (KL * SL)) + (dC_p / (KC * SC)) * (dC_p / (KC * SC))
93 + (dH_p / (KH * SH)) * (dH_p / (KH * SH)) + RT * (dC_p / (KC * SC)) * (dH_p / (KH * SH)));
94 return dE;
95}
96
97// clang-format off
98// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
99// vim: shiftwidth=2 expandtab tabstop=2 cindent
100// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
101// clang-format on
102
float dt_colorspaces_deltaE_1976(dt_aligned_pixel_t Lab0, dt_aligned_pixel_t Lab1)
Definition deltaE.c:36
float dt_colorspaces_deltaE_2000(dt_aligned_pixel_t Lab0, dt_aligned_pixel_t Lab1)
Definition deltaE.c:48
#define DEG2RAD(deg)
Definition deltaE.c:32
#define RAD2DEG(rad)
Definition deltaE.c:33
float dt_aligned_pixel_t[4]