Реализация CIEDE2000 на Fortran

Версия функции: v1.0.0
Статистика сайта
Количество посещений367
Количество просмотренных файлов215 + 321

На этой странице представлена эталонная реализация формулы цветовой разницы CIEDE2000 на Fortran. Если вы хотите получить точное совпадение со сторонними реализациями до 10 знаков после запятой, вам может потребоваться внести некоторые изменения в исходный код, в частности, закомментировать и разкомментировать несколько строк, которые могут быть применены автоматически по ссылке ниже.

Диаграмма полной формулы CIEDE2000 с компонентами L*a*b* и корректировками

Функция ΔE2000 в Fortran

Рассмотрим более распространенную и академическую (Sharma, 2005) из двух формулировок.

! This function written in Fortran is not affiliated with the CIE (International Commission on Illumination),
! and is released into the public domain. It is provided "as is" without any warranty, express or implied.

module ciede_2000_module
  use iso_fortran_env, only: real64
  implicit none
  private
  public :: ciede_2000
  real(kind=real64), parameter :: M_PI = 3.14159265358979323846264338328_real64
    ! k_l, k_c, k_h are parametric factors to be adjusted according to
    ! different viewing parameters such as textures, backgrounds...
  real(kind=real64), parameter :: k_l = 1.0_real64, k_c = 1.0_real64, k_h = 1.0_real64
contains
  ! The classic CIE ΔE2000 implementation, which operates on two L*a*b* colors, and returns their difference.
  ! "l" ranges from 0 to 100, while "a" and "b" are unbounded and commonly clamped to the range of -128 to 127.
  function ciede_2000(l_1, a_1, b_1, l_2, a_2, b_2) result(delta_e)
    implicit none
    real(kind=real64), intent(in) :: l_1, a_1, b_1, l_2, a_2, b_2
    real(kind=real64) :: n, c_1, c_2, h_1, h_2, h_m, h_d, p, r_t, l, t, h, c, delta_e
    ! Working in Fortran with the CIEDE2000 color-difference formula.
    n = (sqrt(a_1 * a_1 + b_1 * b_1) + sqrt(a_2 * a_2 + b_2 * b_2)) * 0.5_real64
    n = n * n * n * n * n * n * n
    ! A factor involving chroma raised to the power of 7 designed to make
    ! the influence of chroma on the total color difference more accurate.
    n = 1.0_real64 + 0.5_real64 * (1.0_real64 - sqrt(n / (n + 6103515625.0_real64)))
    ! Application of the chroma correction factor.
    c_1 = sqrt(a_1 * a_1 * n * n + b_1 * b_1)
    c_2 = sqrt(a_2 * a_2 * n * n + b_2 * b_2)
    ! atan2 is preferred over atan because it accurately computes the angle of
    ! a point (x, y) in all quadrants, handling the signs of both coordinates.
    h_1 = atan2(b_1, a_1 * n)
    h_2 = atan2(b_2, a_2 * n)
    if (h_1 < 0.0_real64) h_1 = h_1 + 2.0_real64 * M_PI
    if (h_2 < 0.0_real64) h_2 = h_2 + 2.0_real64 * M_PI
    n = abs(h_2 - h_1)
    ! Cross-implementation consistent rounding.
    if (M_PI - 0.00000000000001_real64 < n .and. n < M_PI + 0.00000000000001_real64) n = M_PI
    ! When the hue angles lie in different quadrants, the straightforward
    ! average can produce a mean that incorrectly suggests a hue angle in
    ! the wrong quadrant, the next lines handle this issue.
    h_m = (h_1 + h_2) * 0.5_real64
    h_d = (h_2 - h_1) * 0.5_real64
    if (M_PI < n) then
      h_d = h_d + M_PI
      ! 📜 Sharma’s formulation doesn’t use the next line, but the one after it,
      ! and these two variants differ by ±0.0003 on the final color differences.
      h_m = h_m + M_PI
      ! h_m = h_m + MERGE(M_PI, -M_PI, h_m < M_PI)
    endif
    p = 36.0_real64 * h_m - 55.0_real64 * M_PI
    n = (c_1 + c_2) * 0.5_real64
    n = n * n * n * n * n * n * n
    ! The hue rotation correction term is designed to account for the
    ! non-linear behavior of hue differences in the blue region.
    r_t = -2.0_real64 * sqrt(n / (n + 6103515625.0_real64)) &
                        * sin(M_PI / 3.0_real64 * exp(p * p / (-25.0_real64 * M_PI * M_PI)))
    n = (l_1 + l_2) * 0.5_real64
    n = (n - 50.0_real64) * (n - 50.0_real64)
    ! Lightness.
    l = (l_2 - l_1) / (k_l * (1.0_real64 + 0.015_real64 * n / sqrt(20.0_real64 + n)))
    ! These coefficients adjust the impact of different harmonic
    ! components on the hue difference calculation.
    t = 1.0_real64   + 0.24_real64 * sin(2.0_real64 * h_m + M_PI / 2.0_real64) &
                     + 0.32_real64 * sin(3.0_real64 * h_m + 8.0_real64 * M_PI / 15.0_real64) &
                     - 0.17_real64 * sin(h_m + M_PI / 3.0_real64) &
                     - 0.20_real64 * sin(4.0_real64 * h_m + 3.0_real64 * M_PI / 20.0_real64)
    n = c_1 + c_2
    ! Hue.
    h = 2.0_real64 * sqrt(c_1 * c_2) * sin(h_d) / (k_h * (1.0_real64 + 0.0075_real64 * n * t))
    ! Chroma.
    c = (c_2 - c_1) / (k_c * (1.0_real64 + 0.0225_real64 * n))
    ! Returning the square root ensures that dE00 accurately reflects the
    ! geometric distance in color space, which can range from 0 to around 185.
    delta_e = sqrt(l * l + h * h + c * c + c * h * r_t)
  end function ciede_2000
end module ciede_2000_module

! GitHub Project : https://github.com/michel-leonard/ciede2000-color-matching
!   Online Tests : https://michel-leonard.github.io/ciede2000-color-matching

! L1 = 68.5   a1 = 18.1   b1 = 3.6
! L2 = 70.2   a2 = 23.8   b2 = -4.0
! CIE ΔE00 = 6.1142357448 (Bruce Lindbloom, Netflix’s VMAF, ...)
! CIE ΔE00 = 6.1142186799 (Gaurav Sharma, OpenJDK, ...)
! Deviation between implementations ≈ 1.7e-5

! See the source code comments for easy switching between these two widely used ΔE*00 implementation variants.

Точность и надежность исходного кода

Разница между формулировками Шармы и Линдблума никогда не превышает ±0,0003 по финальному ΔE2000, что соответствует обычной разнице между двумя 32-битными реализациями и незаметно для невооружённого глаза. Наши 64-битные реализации, все согласованные между собой, гарантируют как минимум 10 правильных десятичных знаков, поэтому выбор одной формулы вместо другой в основном зависит от желаемой совместимости. Наиболее часто используется формула, которая по умолчанию отображается на этой странице (ее микродостоинство в том, что она основана на сообществе и при векторизации легче своего аналога).

Если вы обнаружили в исходном коде комментарий, который не соответствует другому языку, пожалуйста, сообщите об этом автору сайта, который изучит ваше предложение и включит его в исходный код.

Как преобразовать цвета RGB в L*a*b*?

Перейдите на страницу AWK, C, Dart, Java, JavaScript, Kotlin, Lua, PHP, Python, Ruby или Rust, где такой конвертер (с использованием осветителя D65) уже реализован в дополнение к функции сравнения цветов.

Диапазоны значений в CIELAB и интерпретация ΔE2000

В цветовом пространстве CIELAB компонент L* обозначает светлоту и обычно изменяется от 0 (черный) до 100 (белый). Компоненты a* и b* описывают цветовые оси: a* идет от зеленого к красному, а b* — от синего к желтому. На практике значения a* и b* чаще всего находятся в диапазоне от -128 до +127, хотя в зависимости от конверсии они могут немного выходить за эти пределы.

Пример двух цветов, имеющих незаметную разницу (JND), по мнению CIEDE2000
Цвет 1Цвет 2Значение ΔE2000
1
2
3
Примеры значений CIEDE2000, вычисленных между двумя различными цветами
Цвет 1Цвет 2Значение ΔE2000
5
10
15

Параметры k_l, k_c и k_h

Параметры k_l, k_c и k_h являются весовыми коэффициентами, применяемыми к компонентам яркости (ΔL*), хроматичности (ΔC*) и оттенка (ΔH*) в формуле CIEDE2000. Их значение по умолчанию — 1, что соответствует стандартным условиям наблюдения, рекомендованным Международная комиссия по освещению. На практике эти коэффициенты настраиваются для отражения конкретных условий: например, k_l = 2 иногда используется для придания большего веса различиям яркости (часто в печати), тогда как k_c или k_h могут быть уменьшены для повышения допустимости вариаций насыщенности или оттенка в зависимости от требований контроля качества. В зависимости от контекста эти коэффициенты обычно варьируются от 0,5 до 2.

ΔE2000 (CIEDE2000) измеряет воспринимаемую разницу между двумя цветами: 0 означает идентичные цвета, а более высокие значения (до примерно 185 в крайних случаях) показывают большую разницу. Например, значение ΔE2000 около 5 означает близкие цвета, а около 15 — явно разные.

Пример использования в Fortran

! Compute the Delta E (CIEDE2000) color difference between two L*a*b* colors in Fortran

! Color 1: l1 = 89.0   a1 = 33.3   b1 = -1.7
! Color 2: l2 = 89.2   a2 = 38.4   b2 = 2.2

delta_e = ciede_2000(l1, a1, b1, l2, a2, b2)
print '(F0.10)', delta_e

! .................................................. This shows a ΔE2000 of 2.9929564263
! As explained in the comments, compliance with Gaurav Sharma would display 2.9929700654

Результаты испытаний

Драйвер, написанный на языке C99, с помощью 250 точных статических тестов доказал, что эта функция Fortran совместима с функцией CIEDE2000, доступной на других языках программирования.

CIEDE2000 Verification Summary :
  First Verified Line : 24,122.6,117,21,-40.999999999847,-46,81.762663548041459
             Duration : 41.38 s
            Successes : 10000000
               Errors : 0
      Average Delta E : 63.2338
    Average Deviation : 4.6e-15
    Maximum Deviation : 1.1e-13

Файлы для загрузки

Не стесняйтесь использовать эти файлы, предоставленные Мишелем, даже в коммерческих целях.

Статистика сайта : загрузки файлов
ФайлРазмерКоличество кликов
ciede-2000.f905 KB61
ciede-2000-driver.f906 KB55
ciede-2000-random.f907 KB58
test-f90.yml3 KB41
reference-dataset.txt4 KB321
Нажмите на f90.zip, чтобы скачать все эти файлы в архиве.

Сообщество

Если вы хотите оставить своё мнение об этом исходном коде Fortran или о CIEDE2000 в целом, то в гостевой книге уже есть 1 сообщения на русском языке и 9 сообщений в целом, так что, пожалуйста, дайте нам знать, что вы думаете по этому поводу.