Skip to content

Commit

Permalink
add HyCH color difference metric
Browse files Browse the repository at this point in the history
add HyCH tests
  • Loading branch information
mesvam authored and KelSolaar committed Nov 11, 2024
1 parent 657edf9 commit b34542a
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 0 deletions.
7 changes: 7 additions & 0 deletions colour/difference/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
delta_E_CMC,
delta_E_ITP,
delta_E_HyAB,
delta_E_HyCH,
)
from .din99 import delta_E_DIN99
from .huang2015 import power_function_Huang2015
Expand All @@ -77,6 +78,7 @@
"delta_E_CMC",
"delta_E_ITP",
"delta_E_HyAB",
"delta_E_HyCH",
]
__all__ += [
"delta_E_DIN99",
Expand Down Expand Up @@ -105,6 +107,7 @@
"CAM16-UCS": delta_E_CAM16UCS,
"DIN99": delta_E_DIN99,
"HyAB": delta_E_HyAB,
"HyCH": delta_E_HyCH,
}
)
DELTA_E_METHODS.__doc__ = """
Expand Down Expand Up @@ -210,6 +213,10 @@ def delta_E(
>>> b = np.array([53.12207516, -39.92365056, 249.54831278])
>>> delta_E(a, b, method="HyAB") # doctest: +ELLIPSIS
151.0215481...
>>> a = np.array([39.91531343, 51.16658481, 146.12933781])
>>> b = np.array([53.12207516, -39.92365056, 249.54831278])
>>> delta_E(a, b, method="HyCH") # doctest: +ELLIPSIS
48.66427941...
"""

method = validate_method(method, tuple(DELTA_E_METHODS))
Expand Down
67 changes: 67 additions & 0 deletions colour/difference/delta_e.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- :func:`colour.difference.delta_E_CMC`
- :func:`colour.difference.delta_E_ITP`
- :func:`colour.difference.delta_E_HyAB`
- :func:`colour.difference.delta_E_HyCH`
References
----------
Expand Down Expand Up @@ -79,6 +80,7 @@
"delta_E_CMC",
"delta_E_ITP",
"delta_E_HyAB",
"delta_E_HyCH",
]

JND_CIE1976 = 2.3
Expand Down Expand Up @@ -712,3 +714,68 @@ def delta_E_HyAB(Lab_1: ArrayLike, Lab_2: ArrayLike) -> NDArrayFloat:
HyAB = np.abs(dL) + np.hypot(da, db)

return as_float(HyAB)


def delta_E_HyCH(
Lab_1: ArrayLike, Lab_2: ArrayLike, textiles: bool = False
) -> NDArrayFloat:
"""
Return the difference between two *CIE L\\*a\\*b\\** colourspace arrays
This metric is intended for large color differences,
on the order of 10 CIELAB units or greater
Parameters
----------
Lab_1
*CIE L\\*a\\*b\\** colourspace array 1.
Lab_2
*CIE L\\*a\\*b\\** colourspace array 2.
Returns
-------
:class:`numpy.ndarray`
Colour difference HyCH.
Notes
-----
+------------+-----------------------+-------------------+
| **Domain** | **Scale - Reference** | **Scale - 1** |
+============+=======================+===================+
| ``Lab_1`` | ``L_1`` : [0, 100] | ``L_1`` : [0, 1] |
| | | |
| | ``a_1`` : [-100, 100] | ``a_1`` : [-1, 1] |
| | | |
| | ``b_1`` : [-100, 100] | ``b_1`` : [-1, 1] |
+------------+-----------------------+-------------------+
| ``Lab_2`` | ``L_2`` : [0, 100] | ``L_2`` : [0, 1] |
| | | |
| | ``a_2`` : [-100, 100] | ``a_2`` : [-1, 1] |
| | | |
| | ``b_2`` : [-100, 100] | ``b_2`` : [-1, 1] |
+------------+-----------------------+-------------------+
References
----------
:cite:`Abasi2020`
Examples
--------
>>> Lab_1 = np.array([39.91531343, 51.16658481, 146.12933781])
>>> Lab_2 = np.array([53.12207516, -39.92365056, 249.54831278])
>>> delta_E_HyCH(Lab_1, Lab_2) # doctest: +ELLIPSIS
48.664279419760369...
"""

S_L, S_C, S_H, delta_L_p, delta_C_p, delta_H_p, R_T = astuple(
intermediate_attributes_CIE2000(Lab_1, Lab_2)
)

k_L = 2 if textiles else 1
k_C = 1
k_H = 1

HyCH = np.abs(delta_L_p / (k_L * S_L)) + np.sqrt(
(delta_C_p / (k_C * S_C)) ** 2 + (delta_H_p / (k_H * S_H)) ** 2
)

return as_float(HyCH)
97 changes: 97 additions & 0 deletions colour/difference/tests/test_delta_e.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
delta_E_CIE2000,
delta_E_CMC,
delta_E_HyAB,
delta_E_HyCH,
delta_E_ITP,
)
from colour.difference.delta_e import intermediate_attributes_CIE2000
Expand All @@ -40,6 +41,7 @@
"TestDelta_E_CMC",
"TestDelta_E_ITP",
"TestDelta_E_HyAB",
"TestDelta_E_HyCH",
]


Expand Down Expand Up @@ -918,3 +920,98 @@ def test_nan_delta_E_HyAB(self):
cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
cases = np.array(list(set(product(cases, repeat=3))))
delta_E_HyAB(cases, cases)


class TestDelta_E_HyCH:
"""
Define :func:`colour.difference.delta_e.delta_E_HyCH` definition unit
tests methods.
"""

def test_delta_E_HyCH(self):
"""Test :func:`colour.difference.delta_e.delta_E_HyCH` definition."""

np.testing.assert_allclose(
delta_E_HyCH(
np.array([39.91531343, 51.16658481, 146.12933781]),
np.array([53.12207516, -39.92365056, 249.54831278]),
),
48.664279419760369,
atol=TOLERANCE_ABSOLUTE_TESTS,
)

np.testing.assert_allclose(
delta_E_HyCH(
np.array([39.91531343, 51.16658481, 146.12933781]),
np.array([28.52234779, 19.46628874, 472.06042624]),
),
39.260928157999118,
atol=TOLERANCE_ABSOLUTE_TESTS,
)

np.testing.assert_allclose(
delta_E_HyCH(
np.array([48.99183622, -0.10561667, 400.65619925]),
np.array([50.65907324, -0.11671910, 402.82235718]),
),
1.7806293290163562,
atol=TOLERANCE_ABSOLUTE_TESTS,
)

def test_n_dimensional_delta_E_HyCH(self):
"""
Test :func:`colour.difference.delta_e.delta_E_HyCH` definition
n-dimensional arrays support.
"""

Lab_1 = (np.array([39.91531343, 51.16658481, 146.12933781]),)
Lab_2 = (np.array([53.12207516, -39.92365056, 249.54831278]),)
delta_E = delta_E_HyCH(Lab_1, Lab_2)

Lab_1 = np.tile(Lab_1, (6, 1))
Lab_2 = np.tile(Lab_2, (6, 1))
delta_E = np.tile(delta_E, 6)
np.testing.assert_allclose(
delta_E_HyCH(Lab_1, Lab_2),
delta_E,
atol=TOLERANCE_ABSOLUTE_TESTS,
)

Lab_1 = np.reshape(Lab_1, (2, 3, 3))
Lab_2 = np.reshape(Lab_2, (2, 3, 3))
delta_E = np.reshape(delta_E, (2, 3))
np.testing.assert_allclose(
delta_E_HyCH(Lab_1, Lab_2),
delta_E,
atol=TOLERANCE_ABSOLUTE_TESTS,
)

def test_domain_range_scale_delta_E_HyCH(self):
"""
Test :func:`colour.difference.delta_e.delta_E_HyCH` definition
domain and range scale support.
"""

Lab_1 = np.array([39.91531343, 51.16658481, 146.12933781])
Lab_2 = np.array([53.12207516, -39.92365056, 249.54831278])
delta_E = delta_E_HyCH(Lab_1, Lab_2)

d_r = (("reference", 1), ("1", 0.01), ("100", 1))
for scale, factor in d_r:
with domain_range_scale(scale):
np.testing.assert_allclose(
delta_E_HyCH(Lab_1 * factor, Lab_2 * factor),
delta_E,
atol=TOLERANCE_ABSOLUTE_TESTS,
)

@ignore_numpy_errors
def test_nan_delta_E_HyCH(self):
"""
Test :func:`colour.difference.delta_e.delta_E_HyCH` definition nan
support.
"""

cases = [-1.0, 0.0, 1.0, -np.inf, np.inf, np.nan]
cases = np.array(list(set(product(cases, repeat=3))))
delta_E_HyCH(cases, cases)
1 change: 1 addition & 0 deletions colour/hints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ def apply(self, RGB: ArrayLike, **kwargs: Any) -> NDArray: # noqa: D102
"CMC",
"DIN99",
"HyAB",
"HyCH",
"ITP",
"cie1976",
"cie1994",
Expand Down
12 changes: 12 additions & 0 deletions docs/colour.difference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,18 @@ HyAB

delta_E_HyAB

HyCH
-----

``colour.difference``

.. currentmodule:: colour.difference

.. autosummary::
:toctree: generated/

delta_E_HyCH

Standardized Residual Sum of Squares (STRESS) Index
---------------------------------------------------

Expand Down

0 comments on commit b34542a

Please sign in to comment.