Source code for colour.models.rgb.transfer_functions.dicom_gsdf

"""
DICOM - Grayscale Standard Display Function
===========================================

Defines the *DICOM - Grayscale Standard Display Function* electro-optical
transfer function (EOTF) and its inverse:

-   :func:`colour.models.eotf_inverse_DICOMGSDF`
-   :func:`colour.models.eotf_DICOMGSDF`

The Grayscale Standard Display Function is defined for the Luminance Range from
:math:`0.05` to :math:`4000 cd/m^2`. The minimum Luminance corresponds to the
lowest practically useful Luminance of cathode-ray-tube (CRT) monitors and the
maximum exceeds the unattenuated Luminance of very bright light-boxes used for
interpreting X-Ray mammography. The Grayscale Standard Display Function
explicitly includes the effects of the diffused ambient Illuminance.

References
----------
-   :cite:`NationalElectricalManufacturersAssociation2004b` : National
    Electrical Manufacturers Association. (2004). Digital Imaging and
    Communications in Medicine (DICOM) Part 14: Grayscale Standard Display
    Function. http://medical.nema.org/dicom/2004/04_14PU.PDF
"""

from __future__ import annotations

import numpy as np

from colour.hints import ArrayLike, NDArrayFloat, NDArrayReal
from colour.utilities import (
    Structure,
    as_float,
    as_int,
    from_range_1,
    to_domain_1,
)

__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"

__all__ = [
    "CONSTANTS_DICOMGSDF",
    "eotf_inverse_DICOMGSDF",
    "eotf_DICOMGSDF",
]

CONSTANTS_DICOMGSDF: Structure = Structure(
    a=-1.3011877,
    b=-2.5840191e-2,
    c=8.0242636e-2,
    d=-1.0320229e-1,
    e=1.3646699e-1,
    f=2.8745620e-2,
    g=-2.5468404e-2,
    h=-3.1978977e-3,
    k=1.2992634e-4,
    m=1.3635334e-3,
    A=71.498068,
    B=94.593053,
    C=41.912053,
    D=9.8247004,
    E=0.28175407,
    F=-1.1878455,
    G=-0.18014349,
    H=0.14710899,
    I=-0.017046845,
)
"""*DICOM Grayscale Standard Display Function* constants."""


[docs] def eotf_inverse_DICOMGSDF( L: ArrayLike, out_int: bool = False, constants: Structure = CONSTANTS_DICOMGSDF, ) -> NDArrayReal: """ Define the *DICOM - Grayscale Standard Display Function* inverse electro-optical transfer function (EOTF). Parameters ---------- L *Luminance* :math:`L`. out_int Whether to return value as int code value or float equivalent of a code value at a given bit-depth. constants *DICOM - Grayscale Standard Display Function* constants. Returns ------- :class:`numpy.ndarray` Just-Noticeable Difference (JND) Index, :math:`j`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``L`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``J`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`NationalElectricalManufacturersAssociation2004b` Examples -------- >>> eotf_inverse_DICOMGSDF(130.0662) # doctest: +ELLIPSIS 0.5004862... >>> eotf_inverse_DICOMGSDF(130.0662, out_int=True) 512 """ L = to_domain_1(L) L_lg = np.log10(L) A = constants.A B = constants.B C = constants.C D = constants.D E = constants.E F = constants.F G = constants.G H = constants.H I = constants.I # noqa: E741 J = ( A + B * L_lg + C * L_lg**2 + D * L_lg**3 + E * L_lg**4 + F * L_lg**5 + G * L_lg**6 + H * L_lg**7 + I * L_lg**8 ) if out_int: return as_int(np.round(J)) else: return as_float(from_range_1(J / 1023))
[docs] def eotf_DICOMGSDF( J: ArrayLike, in_int: bool = False, constants: Structure = CONSTANTS_DICOMGSDF, ) -> NDArrayFloat: """ Define the *DICOM - Grayscale Standard Display Function* electro-optical transfer function (EOTF). Parameters ---------- J Just-Noticeable Difference (JND) Index, :math:`j`. in_int Whether to treat the input value as int code value or float equivalent of a code value at a given bit-depth. constants *DICOM - Grayscale Standard Display Function* constants. Returns ------- :class:`numpy.ndarray` Corresponding *luminance* :math:`L`. Notes ----- +------------+-----------------------+---------------+ | **Domain** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``J`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ +------------+-----------------------+---------------+ | **Range** | **Scale - Reference** | **Scale - 1** | +============+=======================+===============+ | ``L`` | [0, 1] | [0, 1] | +------------+-----------------------+---------------+ References ---------- :cite:`NationalElectricalManufacturersAssociation2004b` Examples -------- >>> eotf_DICOMGSDF(0.500486263438448) # doctest: +ELLIPSIS 130.0628647... >>> eotf_DICOMGSDF(512, in_int=True) # doctest: +ELLIPSIS 130.0652840... """ J = to_domain_1(J) if not in_int: J = J * 1023 a = constants.a b = constants.b c = constants.c d = constants.d e = constants.e f = constants.f g = constants.g h = constants.h k = constants.k m = constants.m J_ln = np.log(J) J_ln2 = J_ln**2 J_ln3 = J_ln**3 J_ln4 = J_ln**4 J_ln5 = J_ln**5 L = (a + c * J_ln + e * J_ln2 + g * J_ln3 + m * J_ln4) / ( 1 + b * J_ln + d * J_ln2 + f * J_ln3 + h * J_ln4 + k * J_ln5 ) L = 10**L return as_float(from_range_1(L))