コード例 #1
0
ファイル: test_array.py プロジェクト: colour-science/colour
    def test_as_float(self):
        """
        Tests :func:`colour.utilities.array.as_float` definition.
        """

        self.assertEqual(as_float(1), 1.0)

        self.assertEqual(as_float(np.array([1])), 1.0)

        np.testing.assert_almost_equal(
            as_float(np.array([1, 2, 3])), np.array([1.0, 2.0, 3.0]))

        self.assertEqual(
            as_float(np.array([1, 2, 3])).dtype, DEFAULT_FLOAT_DTYPE)

        self.assertIsInstance(as_float(1), DEFAULT_FLOAT_DTYPE)
コード例 #2
0
ファイル: lightness.py プロジェクト: colour-science/colour
def intermediate_lightness_function_CIE1976(Y, Y_n=100):
    """
    Returns the intermediate value :math:`f(Y/Yn)` in the *Lightness*
    :math:`L^*` computation for given *luminance* :math:`Y` using given
    reference white *luminance* :math:`Y_n` as per *CIE 1976* recommendation.

    Parameters
    ----------
    Y : numeric or array_like
        *luminance* :math:`Y`.
    Y_n : numeric or array_like, optional
        White reference *luminance* :math:`Y_n`.

    Returns
    -------
    numeric or array_like
        Intermediate value :math:`f(Y/Yn)`.

    Notes
    -----

    +-------------+-----------------------+---------------+
    | **Domain**  | **Scale - Reference** | **Scale - 1** |
    +=============+=======================+===============+
    | ``Y``       | [0, 100]              | [0, 100]      |
    +-------------+-----------------------+---------------+

    +-------------+-----------------------+---------------+
    | **Range**   | **Scale - Reference** | **Scale - 1** |
    +=============+=======================+===============+
    | ``f_Y_Y_n`` | [0, 1]                | [0, 1]        |
    +-------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> intermediate_lightness_function_CIE1976(12.19722535)
    ... # doctest: +ELLIPSIS
    0.4959299...
    >>> intermediate_lightness_function_CIE1976(12.19722535, 95)
    ... # doctest: +ELLIPSIS
    0.5044821...
    """

    Y = as_float_array(Y)
    Y_n = as_float_array(Y_n)

    Y_Y_n = Y / Y_n

    f_Y_Y_n = as_float(
        np.where(
            Y_Y_n > (24 / 116) ** 3,
            spow(Y_Y_n, 1 / 3),
            (841 / 108) * Y_Y_n + 16 / 116,
        ))

    return f_Y_Y_n
コード例 #3
0
def maximise_spatial_frequency(L):
    """
    Maximises the spatial frequency :math:`u` for given luminance value.

    Parameters
    ----------
    L : numeric or array_like
        Luminance value at which to maximize the spatial frequency :math:`u`.

    Returns
    -------
    numeric or ndarray
        Maximised spatial frequency :math:`u`.
    """

    maximised_spatial_frequency = []
    for L_v in L:
        X_0 = 60
        d = colour.contrast.pupil_diameter_Barten1999(L_v, X_0)
        sigma = colour.contrast.sigma_Barten1999(0.5 / 60, 0.08 / 60, d)
        E = colour.contrast.retinal_illuminance_Barten1999(L_v, d, True)
        maximised_spatial_frequency.append(
            fmin(lambda x: (
                    -colour.contrast.contrast_sensitivity_function_Barten1999(
                        u=x,
                        sigma=sigma,
                        X_0=X_0,
                        E=E,
                        **settings_BT2246)
                ), 0, disp=False)[0])

    return as_float(np.array(maximised_spatial_frequency))
コード例 #4
0
ファイル: arib_std_b67.py プロジェクト: colour-science/colour
def oetf_reverse_ARIBSTDB67(E_p, r=0.5, constants=ARIBSTDB67_CONSTANTS):
    """
    Defines *ARIB STD-B67 (Hybrid Log-Gamma)* reverse opto-electrical transfer
    function (OETF / OECF).

    Parameters
    ----------
    E_p : numeric or array_like
        Non-linear signal :math:`E'`.
    r : numeric, optional
        Video level corresponding to reference white level.
    constants : Structure, optional
        *ARIB STD-B67 (Hybrid Log-Gamma)* constants.

    Returns
    -------
    numeric or ndarray
        Voltage :math:`E` normalised by the reference white level and
        proportional to the implicit light intensity that would be detected
        with a reference camera color channel R, G, B.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``E_p``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``E``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`AssociationofRadioIndustriesandBusinesses2015a`

    Examples
    --------
    >>> oetf_reverse_ARIBSTDB67(0.212132034355964)  # doctest: +ELLIPSIS
    0.1799999...
    """

    E_p = to_domain_1(E_p)

    a = constants.a
    b = constants.b
    c = constants.c

    with domain_range_scale('ignore'):
        E = np.where(
            E_p <= oetf_ARIBSTDB67(1),
            (E_p / r) ** 2,
            np.exp((E_p - c) / a) + b,
        )

    return as_float(from_range_1(E))
コード例 #5
0
ファイル: barten1999.py プロジェクト: colour-science/colour
def pupil_diameter_Barten1999(L, X_0=60, Y_0=None):
    """
    Returns the pupil diameter for given luminance and object or stimulus
    angular size using *Barten (1999)* method.

    Parameters
    ----------
    L : numeric or array_like
        Average luminance :math:`L` in :math:`cd/m^2`.
    X_0 : numeric or array_like, optional
        Angular size of the object :math:`X_0` in degrees in the x direction.
    Y_0 : numeric or array_like, optional
        Angular size of the object :math:`X_0` in degrees in the y direction.

    References
    ----------
    :cite:`Barten1999`, :cite:`Barten2003`, :cite:`Cowan2004`,
    :cite:`InternationalTelecommunicationUnion2015`,

    Examples
    --------
    >>> pupil_diameter_Barten1999(100, 60, 60)  # doctest: +ELLIPSIS
    2.0777571...
    """

    L = as_float_array(L)
    X_0 = as_float_array(X_0)
    Y_0 = X_0 if Y_0 is None else as_float_array(Y_0)

    return as_float(5 - 3 * np.tanh(0.4 * np.log(L * X_0 * Y_0 / 40 ** 2)))
コード例 #6
0
ファイル: barten1999.py プロジェクト: colour-science/colour
def optical_MTF_Barten1999(u, sigma=0.01):
    """
    Returns the optical modulation transfer function (MTF) :math:`M_{opt}` of
    the eye using *Barten (1999)* method.

    Parameters
    ----------
    u : numeric or array_like
        Spatial frequency :math:`u`, the cycles per degree.
    sigma : numeric or array_like, optional
        Standard deviation :math:`\\sigma` of the line-spread function
        resulting from the convolution of the different elements of the
        convolution process.

    Returns
    -------
    numeric or array_like
        Optical modulation transfer function (MTF) :math:`M_{opt}` of the eye.

    References
    ----------
    :cite:`Barten1999`, :cite:`Barten2003`, :cite:`Cowan2004`,
    :cite:`InternationalTelecommunicationUnion2015`,

    Examples
    --------
    >>> optical_MTF_Barten1999(4, 0.01)  # doctest: +ELLIPSIS
    0.9689107...
    """

    u = as_float_array(u)
    sigma = as_float_array(sigma)

    return as_float(np.exp(-2 * np.pi ** 2 * sigma ** 2 * u ** 2))
コード例 #7
0
ファイル: alexa_log_c.py プロジェクト: colour-science/colour
def log_encoding_ALEXALogC(x,
                           firmware='SUP 3.x',
                           method='Linear Scene Exposure Factor',
                           EI=800):
    """
    Defines the *ALEXA Log C* log encoding curve / opto-electronic transfer
    function.

    Parameters
    ----------
    x : numeric or array_like
        Linear data :math:`x`.
    firmware : unicode, optional
        **{'SUP 3.x', 'SUP 2.x'}**,
        Alexa firmware version.
    method : unicode, optional
        **{'Linear Scene Exposure Factor', 'Normalised Sensor Signal'}**,
        Conversion method.
    EI : int,  optional
        Ei.

    Returns
    -------
    numeric or ndarray
        *ALEXA Log C* encoded data :math:`t`.

    References
    ----------
    :cite:`ARRI2012a`

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``t``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    Examples
    --------
    >>> log_encoding_ALEXALogC(0.18)  # doctest: +ELLIPSIS
    0.3910068...
    """

    x = to_domain_1(x)

    cut, a, b, c, d, e, f, _e_cut_f = (
        ALEXA_LOG_C_CURVE_CONVERSION_DATA[firmware][method][EI])

    t = np.where(x > cut, c * np.log10(a * x + b) + d, e * x + f)

    return as_float(from_range_1(t))
コード例 #8
0
ファイル: alexa_log_c.py プロジェクト: colour-science/colour
def log_decoding_ALEXALogC(t,
                           firmware='SUP 3.x',
                           method='Linear Scene Exposure Factor',
                           EI=800):
    """
    Defines the *ALEXA Log C* log decoding curve / electro-optical transfer
    function.

    Parameters
    ----------
    t : numeric or array_like
        *ALEXA Log C* encoded data :math:`t`.
    firmware : unicode, optional
        **{'SUP 3.x', 'SUP 2.x'}**,
        Alexa firmware version.
    method : unicode,  optional
        **{'Linear Scene Exposure Factor', 'Normalised Sensor Signal'}**,
        Conversion method.
    EI : int,  optional
        Ei.

    Returns
    -------
    numeric or ndarray
        Linear data :math:`x`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``t``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`ARRI2012a`

    Examples
    --------
    >>> log_decoding_ALEXALogC(0.391006832034084)  # doctest: +ELLIPSIS
    0.18...
    """

    t = to_domain_1(t)

    cut, a, b, c, d, e, f, _e_cut_f = (
        ALEXA_LOG_C_CURVE_CONVERSION_DATA[firmware][method][EI])

    x = np.where(t > e * cut + f, (10 ** ((t - d) / c) - b) / a, (t - f) / e)

    return as_float(from_range_1(x))
コード例 #9
0
ファイル: luminance.py プロジェクト: colour-science/colour
def intermediate_luminance_function_CIE1976(f_Y_Y_n, Y_n=100):
    """
    Returns the *luminance* :math:`Y` in the *luminance* :math:`Y`
    computation for given intermediate value :math:`f(Y/Yn)` using given
    reference white *luminance* :math:`Y_n` as per *CIE 1976* recommendation.

    Parameters
    ----------
    f_Y_Y_n : numeric or array_like
        Intermediate value :math:`f(Y/Yn)`.
    Y_n : numeric or array_like
        White reference *luminance* :math:`Y_n`.

    Returns
    -------
    numeric or array_like
        *luminance* :math:`Y`.

    Notes
    -----

    +-------------+-----------------------+---------------+
    | **Domain**  | **Scale - Reference** | **Scale - 1** |
    +=============+=======================+===============+
    | ``f_Y_Y_n`` | [0, 1]                | [0, 1]        |
    +-------------+-----------------------+---------------+

    +-------------+-----------------------+---------------+
    | **Range**   | **Scale - Reference** | **Scale - 1** |
    +=============+=======================+===============+
    | ``Y``       | [0, 100]              | [0, 100]      |
    +-------------+-----------------------+---------------+

    References
    ----------
    :cite:`CIETC1-482004m`, :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> intermediate_luminance_function_CIE1976(0.495929964178047)
    ... # doctest: +ELLIPSIS
    12.1972253...
    >>> intermediate_luminance_function_CIE1976(0.504482161449319, 95)
    ... # doctest: +ELLIPSIS
    12.1972253...
    """

    f_Y_Y_n = as_float_array(f_Y_Y_n)
    Y_n = as_float_array(Y_n)

    Y = as_float(
        np.where(
            f_Y_Y_n > 24 / 116,
            Y_n * f_Y_Y_n ** 3,
            Y_n * (f_Y_Y_n - 16 / 116) * (108 / 841),
        ))

    return Y
コード例 #10
0
ファイル: arib_std_b67.py プロジェクト: colour-science/colour
def oetf_ARIBSTDB67(E, r=0.5, constants=ARIBSTDB67_CONSTANTS):
    """
    Defines *ARIB STD-B67 (Hybrid Log-Gamma)* opto-electrical transfer
    function (OETF / OECF).

    Parameters
    ----------
    E : numeric or array_like
        Voltage normalised by the reference white level and proportional to
        the implicit light intensity that would be detected with a reference
        camera color channel R, G, B.
    r : numeric, optional
        Video level corresponding to reference white level.
    constants : Structure, optional
        *ARIB STD-B67 (Hybrid Log-Gamma)* constants.

    Returns
    -------
    numeric or ndarray
        Resulting non-linear signal :math:`E'`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``E``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``E_p``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`AssociationofRadioIndustriesandBusinesses2015a`

    Examples
    --------
    >>> oetf_ARIBSTDB67(0.18)  # doctest: +ELLIPSIS
    0.2121320...
    """

    E = to_domain_1(E)

    a = constants.a
    b = constants.b
    c = constants.c

    E_p = np.where(E <= 1, r * np.sqrt(E), a * np.log(E - b) + c)

    return as_float(from_range_1(E_p))
コード例 #11
0
ファイル: barten1999.py プロジェクト: colour-science/colour
def sigma_Barten1999(sigma_0=0.5 / 60, C_ab=0.08 / 60, d=2.1):
    """
    Returns the standard deviation :math:`\\sigma` of the line-spread function
    resulting from the convolution of the different elements of the convolution
    process using *Barten (1999)* method.

    The :math:`\\sigma` quantity depends on the pupil diameter :math:`d` of the
    eye lens. For very small pupil diameters, :math:`\\sigma` increases
    inversely proportionally with pupil size because of diffraction, and for
    large pupil diameters, :math:`\\sigma` increases about linearly with pupil
    size because of chromatic aberration and others aberrations.

    Parameters
    ----------
    sigma_0 : numeric or array_like, optional
        Constant :math:`\\sigma_{0}` in degrees.
    C_ab : numeric or array_like, optional
        Spherical aberration of the eye :math:`C_{ab}` in
        :math:`degrees\\div mm`.
    d : numeric or array_like, optional
        Pupil diameter :math:`d` in millimeters.

    Returns
    -------
    ndarray
        Standard deviation :math:`\\sigma` of the line-spread function
        resulting from the convolution of the different elements of the
        convolution process.

    Warnings
    --------
    This definition expects :math:`\\sigma_{0}` and :math:`C_{ab}` to be given
    in degrees and :math:`degrees\\div mm` respectively. However, in the
    literature, the values for :math:`\\sigma_{0}` and
    :math:`C_{ab}` are usually given in :math:`arc min` and
    :math:`arc min\\div mm` respectively, thus they need to be divided by 60.

    References
    ----------
    :cite:`Barten1999`, :cite:`Barten2003`, :cite:`Cowan2004`,
    :cite:`InternationalTelecommunicationUnion2015`,

    Examples
    --------
    >>> sigma_Barten1999(0.5 / 60, 0.08 / 60, 2.1)  # doctest: +ELLIPSIS
    0.0087911...
    """

    sigma_0 = as_float_array(sigma_0)
    C_ab = as_float_array(C_ab)
    d = as_float_array(d)

    return as_float(np.sqrt(sigma_0 ** 2 + (C_ab * d) ** 2))
コード例 #12
0
ファイル: srgb.py プロジェクト: colour-science/colour
def oetf_reverse_sRGB(V):
    """
    Defines the *sRGB* colourspace reverse opto-electronic transfer function
    (OETF / OECF).

    Parameters
    ----------
    V : numeric or array_like
        Electrical signal :math:`V`.

    Returns
    -------
    numeric or ndarray
        Corresponding *luminance* :math:`L` of the image.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`InternationalElectrotechnicalCommission1999a`,
    :cite:`InternationalTelecommunicationUnion2015i`

    Examples
    --------
    >>> oetf_reverse_sRGB(0.461356129500442)  # doctest: +ELLIPSIS
    0.1...
    """

    V = to_domain_1(V)

    with domain_range_scale('ignore'):
        L = np.where(
            V <= oetf_sRGB(0.0031308),
            V / 12.92,
            spow((V + 0.055) / 1.055, 2.4),
        )

    return as_float(from_range_1(L))
コード例 #13
0
ファイル: smpte_240m.py プロジェクト: colour-science/colour
def eotf_SMPTE240M(V_r):
    """
    Defines *SMPTE 240M* electro-optical transfer function (EOTF / EOCF).

    Parameters
    ----------
    V_r : numeric or array_like
        Video signal level :math:`V_r` driving the reference reproducer
        normalised to the system reference white.

    Returns
    -------
    numeric or ndarray
         Light output :math:`L_r` from the reference reproducer normalised to
         the system reference white.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V_c``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_c``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SocietyofMotionPictureandTelevisionEngineers1999b`

    Examples
    --------
    >>> eotf_SMPTE240M(0.402285796753870)  # doctest: +ELLIPSIS
    0.1...
    """

    V_r = to_domain_1(V_r)

    with domain_range_scale('ignore'):
        L_r = np.where(
            V_r < oetf_SMPTE240M(0.0228),
            V_r / 4,
            spow((V_r + 0.1115) / 1.1115, 1 / 0.45),
        )

    return as_float(from_range_1(L_r))
コード例 #14
0
ファイル: ciecam02.py プロジェクト: colour-science/colour
def hue_quadrature(h):
    """
    Returns the hue quadrature from given hue :math:`h` angle in degrees.

    Parameters
    ----------
    h : numeric or array_like
        Hue :math:`h` angle in degrees.

    Returns
    -------
    numeric or ndarray
        Hue quadrature.

    Examples
    --------
    >>> hue_quadrature(219.0484326582719)  # doctest: +ELLIPSIS
    278.0607358...
    """

    h = as_float_array(h)

    h_i = HUE_DATA_FOR_HUE_QUADRATURE['h_i']
    e_i = HUE_DATA_FOR_HUE_QUADRATURE['e_i']
    H_i = HUE_DATA_FOR_HUE_QUADRATURE['H_i']

    # *np.searchsorted* returns an erroneous index if a *nan* is used as input.
    h[np.asarray(np.isnan(h))] = 0
    i = as_int_array(np.searchsorted(h_i, h, side='left') - 1)

    h_ii = h_i[i]
    e_ii = e_i[i]
    H_ii = H_i[i]
    h_ii1 = h_i[i + 1]
    e_ii1 = e_i[i + 1]

    H = H_ii + ((100 * (h - h_ii) / e_ii) / (
        (h - h_ii) / e_ii + (h_ii1 - h) / e_ii1))
    H = np.where(
        h < 20.14,
        385.9 + (14.1 * h / 0.856) / (h / 0.856 + (20.14 - h) / 0.8),
        H,
    )
    H = np.where(
        h >= 237.53,
        H_ii + ((85.9 * (h - h_ii) / e_ii) / (
            (h - h_ii) / e_ii + (360 - h) / 0.856)),
        H,
    )
    return as_float(H)
コード例 #15
0
ファイル: srgb.py プロジェクト: colour-science/colour
def oetf_sRGB(L):
    """
    Defines the *sRGB* colourspace opto-electronic transfer function
    (OETF / OECF).

    Parameters
    ----------
    L : numeric or array_like
        *Luminance* :math:`L` of the image.

    Returns
    -------
    numeric or ndarray
        Corresponding electrical signal :math:`V`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`InternationalElectrotechnicalCommission1999a`,
    :cite:`InternationalTelecommunicationUnion2015i`

    Examples
    --------
    >>> oetf_sRGB(0.18)  # doctest: +ELLIPSIS
    0.4613561...
    """

    L = to_domain_1(L)

    V = np.where(L <= 0.0031308, L * 12.92, 1.055 * spow(L, 1 / 2.4) - 0.055)

    return as_float(from_range_1(V))
コード例 #16
0
ファイル: smpte_240m.py プロジェクト: colour-science/colour
def oetf_SMPTE240M(L_c):
    """
    Defines *SMPTE 240M* opto-electrical transfer function (OETF / OECF).

    Parameters
    ----------
    L_c : numeric or array_like
        Light input :math:`L_c` to the reference camera normalised to the
        system reference white.

    Returns
    -------
    numeric or ndarray
        Video signal output :math:`V_c` of the reference camera normalised to
        the system reference white.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_c``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V_c``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SocietyofMotionPictureandTelevisionEngineers1999b`

    Examples
    --------
    >>> oetf_SMPTE240M(0.18)  # doctest: +ELLIPSIS
    0.4022857...
    """

    L_c = to_domain_1(L_c)

    V_c = np.where(L_c < 0.0228, 4 * L_c, 1.1115 * spow(L_c, 0.45) - 0.1115)

    return as_float(from_range_1(V_c))
コード例 #17
0
ファイル: dji_dlog.py プロジェクト: colour-science/colour
def log_decoding_DJIDLog(y):
    """
    Defines the *DJI D-Log* log decoding curve.

    Parameters
    ----------
    y : numeric or array_like
        Non-linear data :math:`t`.

    Returns
    -------
    numeric or ndarray
        Linear reflection data :math`x`.

    References
    ----------
    :cite:`DJI2017`

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    Examples
    --------
    >>> log_decoding_DJIDLog(0.3987645561893306)  # doctest: +ELLIPSIS
    0.1799998...
    """

    y = to_domain_1(y)

    x = np.where(y <= 0.14, (y - 0.0929) / 6.025,
                 (10 ** (3.89616 * y - 2.27752) - 0.0108) / 0.9892)

    return as_float(from_range_1(x))
コード例 #18
0
ファイル: dji_dlog.py プロジェクト: colour-science/colour
def log_encoding_DJIDLog(x):
    """
    Defines the *DJI D-Log* log encoding curve.

    Parameters
    ----------
    x : numeric or array_like
        Linear reflection data :math`x`.

    Returns
    -------
    numeric or ndarray
        *DJI D-Log* encoded data :math:`y`.

    References
    ----------
    :cite:`DJI2017`

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    Examples
    --------
    >>> log_encoding_DJIDLog(0.18)  # doctest: +ELLIPSIS
    0.3987645...
    """

    x = to_domain_1(x)

    y = np.where(x <= 0.0078, 6.025 * x + 0.0929,
                 (np.log10(x * 0.9892 + 0.0108)) * 0.256663 + 0.584555)

    return as_float(from_range_1(y))
コード例 #19
0
ファイル: cct.py プロジェクト: colour-science/colour
def xy_to_CCT_Hernandez1999(xy):
    """
    Returns the correlated colour temperature :math:`T_{cp}` from given
    *CIE XYZ* tristimulus values *xy* chromaticity coordinates using
    *Hernandez-Andres et al. (1999)* method.

    Parameters
    ----------
    xy : array_like
        *xy* chromaticity coordinates.

    Returns
    -------
    numeric
        Correlated colour temperature :math:`T_{cp}`.

    References
    ----------
    :cite:`Hernandez-Andres1999a`

    Examples
    --------
    >>> xy = np.array([0.31270, 0.32900])
    >>> xy_to_CCT_Hernandez1999(xy)  # doctest: +ELLIPSIS
    6500.7420431...
    """

    x, y = tsplit(xy)

    n = (x - 0.3366) / (y - 0.1735)
    CCT = (-949.86315 + 6253.80338 * np.exp(-n / 0.92159) +
           28.70599 * np.exp(-n / 0.20039) + 0.00004 * np.exp(-n / 0.07125))

    n = np.where(CCT > 50000, (x - 0.3356) / (y - 0.1691), n)

    CCT = np.where(
        CCT > 50000,
        36284.48953 + 0.00228 * np.exp(-n / 0.07861) +
        5.4535e-36 * np.exp(-n / 0.01543),
        CCT,
    )

    return as_float(CCT)
コード例 #20
0
    def __call__(self, x):
        """
        Evaluates the Extrapolator at given point(s).

        Parameters
        ----------
        x : numeric or array_like
            Point(s) to evaluate the Extrapolator at.

        Returns
        -------
        float or ndarray
            Extrapolated points value(s).
        """

        x = np.atleast_1d(x).astype(self._dtype)

        xe = as_float(self._evaluate(x))

        return xe
コード例 #21
0
ファイル: common.py プロジェクト: colour-science/colour
def spow(a, p):
    """
    Raises given array :math:`a` to the power :math:`p` as follows:
    :math:`sign(a) * |a|^p`.

    This avoids NaNs generation when array :math:`a` is negative and the power
    :math:`p` is fractional.

    Parameters
    ----------------
    a : numeric or array_like
        Array :math:`a`.
    p : numeric or array_like
        Power :math:`p`.

    Returns
    -------
    numeric or ndarray
        Array :math:`a` safely raised to the power :math:`p`.

    Examples
    --------
    >>> np.power(-2, 0.15)
    nan
    >>> spow(-2, 0.15)  # doctest: +ELLIPSIS
    -1.1095694...
    >>> spow(0, 0)
    0.0
    """

    if not _SPOW_ENABLED:
        return np.power(a, p)

    a = np.atleast_1d(a)
    p = as_float_array(p)

    a_p = np.sign(a) * np.abs(a) ** p

    a_p[np.isnan(a_p)] = 0

    return as_float(a_p)
コード例 #22
0
ファイル: abstract.py プロジェクト: colour-science/colour
    def domain_distance(self, a):
        """
        Returns the euclidean distance between given array and independent
        domain :math:`x` closest element.

        Parameters
        ----------
        a : numeric or array_like
            :math:`a` variable to compute the euclidean distance with
            independent domain :math:`x` variable.

        Returns
        -------
        numeric or array_like
            Euclidean distance between independent domain :math:`x` variable
            and given :math:`a` variable.
        """

        n = closest(self.domain, a)

        return as_float(np.abs(a - n))
コード例 #23
0
ファイル: sony_slog.py プロジェクト: colour-science/colour
def log_decoding_SLog(
    y: FloatingOrArrayLike,
    bit_depth: Integer = 10,
    in_normalised_code_value: Boolean = True,
    out_reflection: Boolean = True,
) -> FloatingOrNDArray:
    """
    Define the *Sony S-Log* log decoding curve / electro-optical transfer
    function.

    Parameters
    ----------
    y
        Non-linear *Sony S-Log* data :math:`y`.
    bit_depth
        Bit depth used for conversion.
    in_normalised_code_value
        Whether the non-linear *Sony S-Log* data :math:`y` is encoded as
        normalised code values.
    out_reflection
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Reflection or :math:`IRE / 100` input light level :math:`x` to a
        camera.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SonyCorporation2012a`

    Examples
    --------
    >>> log_decoding_SLog(0.384970815928670)  # doctest: +ELLIPSIS
    0.1...
    """

    y = to_domain_1(y)

    x = legal_to_full(y, bit_depth) if in_normalised_code_value else y

    with domain_range_scale("ignore"):
        x = np.where(
            y >= log_encoding_SLog(0.0, bit_depth, in_normalised_code_value),
            10**((x - 0.616596 - 0.03) / 0.432699) - 0.037584,
            (x - 0.030001222851889303) / 5.0,
        )

    if out_reflection:
        x = x * 0.9

    return as_float(from_range_1(x))
コード例 #24
0
ファイル: rimm_romm_rgb.py プロジェクト: ajun73/Work_Code
def oetf_RIMMRGB(X, bit_depth=8, out_int=False, E_clip=2.0):
    """
    Defines the *RIMM RGB* encoding opto-electronic transfer function
    (OETF / OECF).

    *RIMM RGB* encoding non-linearity is based on that specified by
    *Recommendation ITU-R BT.709-6*.

    Parameters
    ----------
    X : numeric or array_like
        Linear data :math:`X_{RIMM}`.
    bit_depth : int, optional
        Bit depth used for conversion.
    out_int : bool, optional
        Whether to return value as integer code value or float equivalent of a
        code value at a given bit depth.
    E_clip : numeric, optional
        Maximum exposure level.

    Returns
    -------
    numeric or ndarray
        Non-linear data :math:`X'_{RIMM}`.

    Notes
    -----

    +---------------+-----------------------+---------------+
    | **Domain \\*** | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X``         | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    +---------------+-----------------------+---------------+
    | **Range \\***  | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X_p``       | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    -   \\* This definition has an output integer switch, thus the domain-range
        scale information is only given for the floating point mode.

    References
    ----------
    :cite:`Spaulding2000b`

    Examples
    --------
    >>> oetf_RIMMRGB(0.18)  # doctest: +ELLIPSIS
    0.2916737...
    >>> oetf_RIMMRGB(0.18, out_int=True)
    74
    """

    X = to_domain_1(X)

    I_max = 2**bit_depth - 1

    V_clip = 1.099 * spow(E_clip, 0.45) - 0.099
    q = I_max / V_clip

    X_p = q * np.select([X < 0.0, X < 0.018, X >= 0.018, X > E_clip],
                        [0, 4.5 * X, 1.099 * spow(X, 0.45) - 0.099, I_max])

    if out_int:
        return as_int(np.round(X_p))
    else:
        return as_float(from_range_1(X_p / I_max))
コード例 #25
0
def log_encoding_VLog(L_in,
                      bit_depth=10,
                      out_legal=True,
                      in_reflection=True,
                      constants=VLOG_CONSTANTS):
    """
    Defines the *Panasonic V-Log* log encoding curve / opto-electronic transfer
    function.

    Parameters
    ----------
    L_in : numeric or array_like
        Linear reflection data :math`L_{in}`.
    bit_depth : int, optional
        Bit depth used for conversion.
    out_legal : bool, optional
        Whether the non-linear *Panasonic V-Log* data :math:`V_{out}` is
        encoded in legal range.
    in_reflection : bool, optional
        Whether the light level :math`L_{in}` to a camera is reflection.
    constants : Structure, optional
        *Panasonic V-Log* constants.

    Returns
    -------
    numeric or ndarray
        Non-linear data :math:`V_{out}`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_in``   | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V_out``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Panasonic2014a`

    Examples
    --------
    >>> log_encoding_VLog(0.18)  # doctest: +ELLIPSIS
    0.4233114...
    """

    L_in = to_domain_1(L_in)

    if not in_reflection:
        L_in = L_in * 0.9

    cut1 = constants.cut1
    b = constants.b
    c = constants.c
    d = constants.d

    V_out = np.where(
        L_in < cut1,
        5.6 * L_in + 0.125,
        c * np.log10(L_in + b) + d,
    )

    V_out = V_out if out_legal else legal_to_full(V_out, bit_depth)

    return as_float(from_range_1(V_out))
コード例 #26
0
ファイル: sony_slog.py プロジェクト: colour-science/colour
def log_decoding_SLog(y, bit_depth=10, in_legal=True, out_reflection=True):
    """
    Defines the *Sony S-Log* log decoding curve / electro-optical transfer
    function.

    Parameters
    ----------
    y : numeric or array_like
        Non-linear *Sony S-Log* data :math:`y`.
    bit_depth : int, optional
        Bit depth used for conversion.
    in_legal : bool, optional
        Whether the non-linear *Sony S-Log* data :math:`y` is encoded in legal
        range.
    out_reflection : bool, optional
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    numeric or ndarray
        Reflection or :math:`IRE / 100` input light level :math:`x` to a
        camera.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SonyCorporation2012a`

    Examples
    --------
    >>> log_decoding_SLog(0.384970815928670)  # doctest: +ELLIPSIS
    0.1...
    >>> log_decoding_SLog(0.376512722254600, in_legal=False)
    ... # doctest: +ELLIPSIS
    0.1...
    >>> log_decoding_SLog(0.370820482371268, out_reflection=False)
    ... # doctest: +ELLIPSIS
    0.1...
    """

    y = to_domain_1(y)

    x = legal_to_full(y, bit_depth) if in_legal else y

    with domain_range_scale('ignore'):
        x = np.where(
            y >= log_encoding_SLog(0.0, bit_depth, in_legal),
            10 ** ((x - 0.616596 - 0.03) / 0.432699) - 0.037584,
            (x - 0.030001222851889303) / 5.0,
        )

    if out_reflection:
        x = x * 0.9

    return as_float(from_range_1(x))
コード例 #27
0
ファイル: sony_slog.py プロジェクト: colour-science/colour
def log_decoding_SLog3(y, bit_depth=10, in_legal=True, out_reflection=True):
    """
    Defines the *Sony S-Log3* log decoding curve / electro-optical transfer
    function.

    Parameters
    ----------
    y : numeric or array_like
        Non-linear *Sony S-Log3* data :math:`y`.
    bit_depth : int, optional
        Bit depth used for conversion.
    in_legal : bool, optional
        Whether the non-linear *Sony S-Log3* data :math:`y` is encoded in legal
        range.
    out_reflection : bool, optional
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    numeric or ndarray
        Reflection or :math:`IRE / 100` input light level :math:`x` to a
        camera.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SonyCorporationd`

    Examples
    --------
    >>> log_decoding_SLog3(0.410557184750733)  # doctest: +ELLIPSIS
    0.1...
    >>> log_decoding_SLog3(0.406392694063927, in_legal=False)
    ... # doctest: +ELLIPSIS
    0.1...
    >>> log_decoding_SLog3(0.399507939606216, out_reflection=False)
    ... # doctest: +ELLIPSIS
    0.1...
    """

    y = to_domain_1(y)

    y = y if in_legal else full_to_legal(y, bit_depth)

    x = np.where(
        y >= 171.2102946929 / 1023,
        ((10 ** ((y * 1023 - 420) / 261.5)) * (0.18 + 0.01) - 0.01),
        (y * 1023 - 95) * 0.01125000 / (171.2102946929 - 95),
    )

    if not out_reflection:
        x = x / 0.9

    return as_float(from_range_1(x))
コード例 #28
0
ファイル: st_2084.py プロジェクト: colour-science/colour
def eotf_inverse_ST2084(
    C: FloatingOrArrayLike,
    L_p: Floating = 10000,
    constants: Structure = CONSTANTS_ST2084,
) -> FloatingOrNDArray:
    """
    Define *SMPTE ST 2084:2014* optimised perceptual inverse electro-optical
    transfer function (EOTF).

    Parameters
    ----------
    C
        Target optical output :math:`C` in :math:`cd/m^2` of the ideal
        reference display.
    L_p
        System peak luminance :math:`cd/m^2`, this parameter should stay at its
        default :math:`10000 cd/m^2` value for practical applications. It is
        exposed so that the definition can be used as a fitting function.
    constants
        *SMPTE ST 2084:2014* constants.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Color value abbreviated as :math:`N`, that is directly proportional to
        the encoded signal representation, and which is not directly
        proportional to the optical output of a display device.

    Warnings
    --------
    *SMPTE ST 2084:2014* is an absolute transfer function.

    Notes
    -----
    -   *SMPTE ST 2084:2014* is an absolute transfer function, thus the
        domain and range values for the *Reference* and *1* scales are only
        indicative that the data is not affected by scale transformations.
        The effective domain of *SMPTE ST 2084:2014* inverse electro-optical
        transfer function (EOTF) is [0.0001, 10000].

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``C``      | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``N``      | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Miller2014a`,
    :cite:`SocietyofMotionPictureandTelevisionEngineers2014a`

    Examples
    --------
    >>> eotf_inverse_ST2084(100)  # doctest: +ELLIPSIS
    0.5080784...
    """

    C = as_float_array(C)

    Y_p = spow(C / L_p, constants.m_1)

    N = spow(
        (constants.c_1 + constants.c_2 * Y_p) / (constants.c_3 * Y_p + 1),
        constants.m_2,
    )

    return as_float(N)
コード例 #29
0
ファイル: rimm_romm_rgb.py プロジェクト: ajun73/Work_Code
def eotf_ROMMRGB(X_p, bit_depth=8, in_int=False):
    """
    Defines the *ROMM RGB* encoding electro-optical transfer function
    (EOTF / EOCF).

    Parameters
    ----------
    X_p : numeric or array_like
        Non-linear data :math:`X'_{ROMM}`.
    bit_depth : int, optional
        Bit depth used for conversion.
    in_int : bool, optional
        Whether to treat the input value as integer code value or float
        equivalent of a code value at a given bit depth.

    Returns
    -------
    numeric or ndarray
        Linear data :math:`X_{ROMM}`.

    Notes
    -----

    +---------------+-----------------------+---------------+
    | **Domain \\*** | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X_p``       | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    +---------------+-----------------------+---------------+
    | **Range \\***  | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X``         | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    -   \\* This definition has an input integer switch, thus the domain-range
        scale information is only given for the floating point mode.

    References
    ----------
    :cite:`ANSI2003a`, :cite:`Spaulding2000b`

    Examples
    --------
    >>> eotf_ROMMRGB(0.385711424751138) # doctest: +ELLIPSIS
    0.1...
    >>> eotf_ROMMRGB(98, in_int=True) # doctest: +ELLIPSIS
    0.1...
    """

    X_p = to_domain_1(X_p)

    I_max = 2**bit_depth - 1

    if not in_int:
        X_p = X_p * I_max

    E_t = 16**(1.8 / (1 - 1.8))

    X = np.where(
        X_p < 16 * E_t * I_max,
        X_p / (16 * I_max),
        spow(X_p / I_max, 1.8),
    )

    return as_float(from_range_1(X))
コード例 #30
0
def log_decoding_NLog(
    out_r: FloatingOrArrayLike,
    bit_depth: Integer = 10,
    in_normalised_code_value: Boolean = True,
    out_reflection: Boolean = True,
    constants: Structure = NLOG_CONSTANTS,
) -> FloatingOrNDArray:
    """
    Define the *Nikon N-Log* log decoding curve / electro-optical transfer
    function.

    Parameters
    ----------
    out_r
        Non-linear data :math:`out`.
    bit_depth
        Bit depth used for conversion.
    in_normalised_code_value
        Whether the non-linear *Nikon N-Log* data :math:`out` is encoded as
        normalised code values.
    out_reflection
        Whether the light level :math`in` to a camera is reflection.
    constants
        *Nikon N-Log* constants.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Linear reflection data :math`in`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``out_r``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``in_r``   | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Nikon2018`

    Examples
    --------
    >>> log_decoding_NLog(0.36366777011713869)  # doctest: +ELLIPSIS
    0.1799999...
    """

    out_r = to_domain_1(out_r)

    out_r = (out_r if in_normalised_code_value else full_to_legal(
        out_r, bit_depth))

    cut2 = constants.cut2
    a = constants.a
    b = constants.b
    c = constants.c
    d = constants.d

    in_r = np.where(
        out_r < cut2,
        spow(out_r / a, 3) - b,
        np.exp((out_r - d) / c),
    )

    if not out_reflection:
        in_r = in_r / 0.9

    return as_float(from_range_1(in_r))
コード例 #31
0
ファイル: luminance.py プロジェクト: colour-science/colour
def luminance_Abebe2017(
    L: FloatingOrArrayLike,
    Y_n: FloatingOrArrayLike = 100,
    method: Union[Literal["Michaelis-Menten", "Stevens"],
                  str] = "Michaelis-Menten",
) -> FloatingOrNDArray:
    """
    Compute *luminance* :math:`Y` of *Lightness* :math:`L` using
    *Abebe, Pouli, Larabi and Reinhard (2017)* method according to
    *Michaelis-Menten* kinetics or *Stevens's Power Law*.

    Parameters
    ----------
    L
        *Lightness* :math:`L`.
    Y_n
        Adapting luminance :math:`Y_n` in :math:`cd/m^2`.
    method
        *Luminance* :math:`Y` computation method.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        *Luminance* :math:`Y` in :math:`cd/m^2`.

    Notes
    -----
    -   *Abebe, Pouli, Larabi and Reinhard (2017)* method uses absolute
        luminance levels, thus the domain and range values for the *Reference*
        and *1* scales are only indicative that the data is not affected by
        scale transformations.

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L``      | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+
    | ``Y_n``    | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Abebe2017a`

    Examples
    --------
    >>> luminance_Abebe2017(0.486955571109229)  # doctest: +ELLIPSIS
    12.1972253...
    >>> luminance_Abebe2017(0.474544792145434, method='Stevens')
    ... # doctest: +ELLIPSIS
    12.1972253...
    """

    L = as_float_array(L)
    Y_n = as_float_array(Y_n)
    method = validate_method(method, ["Michaelis-Menten", "Stevens"])

    if method == "stevens":
        Y = np.where(
            Y_n <= 100,
            spow((L + 0.226) / 1.226, 1 / 0.266),
            spow((L + 0.127) / 1.127, 1 / 0.230),
        )
    else:
        Y = np.where(
            Y_n <= 100,
            spow(
                substrate_concentration_MichaelisMenten_Abebe2017(
                    L, 1.448, 0.635, 0.813),
                1 / 0.582,
            ),
            spow(
                substrate_concentration_MichaelisMenten_Abebe2017(
                    L, 1.680, 1.584, 0.096),
                1 / 0.293,
            ),
        )
    Y = Y * Y_n

    return as_float(Y)
コード例 #32
0
def log_encoding_FilmLightTLog(x, w=128.0, g=16.0, o=0.075):
    """
    Defines the *FilmLight T-Log* log encoding curve.

    Parameters
    ----------
    x : numeric or array_like
        Linear reflection data :math`x`.
    w : numeric, optional
        Value of :math:`x` for :math:`t = 1.0`.
    g : numeric, optional
        Gradient at :math:`x = 0.0`.
    o : numeric, optional
        Value of :math:`t` for :math:`x = 0.0`.

    Returns
    -------
    numeric or ndarray
        *FilmLight T-Log* encoded data :math:`t`.

    References
    ----------
    :cite:`Siragusano2018a`

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``t``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    -   The following is an excerpt from the FilmLight colour space file
        `./etc/colourspaces/FilmLight_TLog_EGamut.flspace` which can be
        obtained by installing the free Baselight for Nuke plugin::

            T-Log, a cineon driven log tone-curve developed by FilmLight.
            The colour space is designed to be used as *Working Colour Space*.

            Version 10.0
            This is similar to Cineon LogC function.

            The formula is...
            y = A + B*log(x + C)
            ...where x,y are the log and linear values.

            A,B,C are constants calculated from...
            w = x value for y = 1.0
            g = the gradient at x=0
            o = y value for x = 0.0

            We do not have an exact solution but the
            formula for b gives an approximation. The
            gradient is not g, but should be within a
            few percent for most sensible values of (w*g).

    Examples
    --------
    >>> log_encoding_FilmLightTLog(0.18)  # doctest: +ELLIPSIS
    0.3965678...
    """

    x = to_domain_1(x)

    b = 1.0 / (0.7107 + 1.2359 * np.log(w * g))
    gs = g / (1.0 - o)
    C = b / gs
    a = 1.0 - b * np.log(w + C)
    y0 = a + b * np.log(C)
    s = (1.0 - o) / (1.0 - y0)
    A = 1.0 + (a - 1.0) * s
    B = b * s
    G = gs * s

    t = np.where(
        x < 0.0,
        G * x + o,
        np.log(x + C) * B + A,
    )

    return as_float(from_range_1(t))
コード例 #33
0
ファイル: rimm_romm_rgb.py プロジェクト: ajun73/Work_Code
def oetf_ROMMRGB(X, bit_depth=8, out_int=False):
    """
    Defines the *ROMM RGB* encoding opto-electronic transfer function
    (OETF / OECF).

    Parameters
    ----------
    X : numeric or array_like
        Linear data :math:`X_{ROMM}`.
    bit_depth : int, optional
        Bit depth used for conversion.
    out_int : bool, optional
        Whether to return value as integer code value or float equivalent of a
        code value at a given bit depth.

    Returns
    -------
    numeric or ndarray
        Non-linear data :math:`X'_{ROMM}`.

    Notes
    -----

    +---------------+-----------------------+---------------+
    | **Domain \\*** | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X``         | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    +---------------+-----------------------+---------------+
    | **Range \\***  | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X_p``       | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    -   \\* This definition has an output integer switch, thus the domain-range
        scale information is only given for the floating point mode.

    References
    ----------
    :cite:`ANSI2003a`, :cite:`Spaulding2000b`

    Examples
    --------
    >>> oetf_ROMMRGB(0.18)  # doctest: +ELLIPSIS
    0.3857114...
    >>> oetf_ROMMRGB(0.18, out_int=True)
    98
    """

    X = to_domain_1(X)

    I_max = 2**bit_depth - 1

    E_t = 16**(1.8 / (1 - 1.8))

    X_p = np.where(X < E_t, X * 16 * I_max, spow(X, 1 / 1.8) * I_max)

    if out_int:
        return as_int(np.round(X_p))
    else:
        return as_float(from_range_1(X_p / I_max))
コード例 #34
0
ファイル: rimm_romm_rgb.py プロジェクト: ajun73/Work_Code
def log_decoding_ERIMMRGB(X_p,
                          bit_depth=8,
                          in_int=False,
                          E_min=0.001,
                          E_clip=316.2):
    """
    Defines the *ERIMM RGB* log decoding curve / electro-optical transfer
    function (EOTF / EOCF).

    Parameters
    ----------
    X_p : numeric or array_like
        Non-linear data :math:`X'_{ERIMM}`.
    bit_depth : int, optional
        Bit depth used for conversion.
    in_int : bool, optional
        Whether to treat the input value as integer code value or float
        equivalent of a code value at a given bit depth.
    E_min : numeric, optional
        Minimum exposure limit.
    E_clip : numeric, optional
        Maximum exposure limit.

    Returns
    -------
    numeric or ndarray
        Linear data :math:`X_{ERIMM}`.

    Notes
    -----

    +---------------+-----------------------+---------------+
    | **Domain \\*** | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X_p``       | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    +---------------+-----------------------+---------------+
    | **Range \\***  | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X``         | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    -   \\* This definition has an input integer switch, thus the domain-range
        scale information is only given for the floating point mode.

    References
    ----------
    :cite:`Spaulding2000b`

    Examples
    --------
    >>> log_decoding_ERIMMRGB(0.410052389492129) # doctest: +ELLIPSIS
    0.1...
    >>> log_decoding_ERIMMRGB(105, in_int=True) # doctest: +ELLIPSIS
    0.1...
    """

    X_p = to_domain_1(X_p)

    I_max = 2**bit_depth - 1

    if not in_int:
        X_p = X_p * I_max

    E_t = np.exp(1) * E_min

    X = np.where(
        X_p <= I_max * ((np.log(E_t) - np.log(E_min)) /
                        (np.log(E_clip) - np.log(E_min))),
        ((np.log(E_clip) - np.log(E_min)) / (np.log(E_t) - np.log(E_min))) *
        ((X_p * E_t) / I_max),
        np.exp((X_p / I_max) * (np.log(E_clip) - np.log(E_min)) +
               np.log(E_min)),
    )

    return as_float(from_range_1(X))
コード例 #35
0
ファイル: rimm_romm_rgb.py プロジェクト: ajun73/Work_Code
def log_encoding_ERIMMRGB(X,
                          bit_depth=8,
                          out_int=False,
                          E_min=0.001,
                          E_clip=316.2):
    """
    Defines the *ERIMM RGB* log encoding curve / opto-electronic transfer
    function (OETF / OECF).

    Parameters
    ----------
    X : numeric or array_like
        Linear data :math:`X_{ERIMM}`.
    bit_depth : int, optional
        Bit depth used for conversion.
    out_int : bool, optional
        Whether to return value as integer code value or float equivalent of a
        code value at a given bit depth.
    E_min : numeric, optional
        Minimum exposure limit.
    E_clip : numeric, optional
        Maximum exposure limit.

    Returns
    -------
    numeric or ndarray
        Non-linear data :math:`X'_{ERIMM}`.

    Notes
    -----

    +---------------+-----------------------+---------------+
    | **Domain \\*** | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X``         | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    +---------------+-----------------------+---------------+
    | **Range \\***  | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X_p``       | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    -   \\* This definition has an output integer switch, thus the domain-range
        scale information is only given for the floating point mode.

    References
    ----------
    :cite:`Spaulding2000b`

    Examples
    --------
    >>> log_encoding_ERIMMRGB(0.18)  # doctest: +ELLIPSIS
    0.4100523...
    >>> log_encoding_ERIMMRGB(0.18, out_int=True)
    105
    """

    X = to_domain_1(X)

    I_max = 2**bit_depth - 1

    E_t = np.exp(1) * E_min

    X_p = np.select([
        X < 0.0,
        X <= E_t,
        X > E_t,
        X > E_clip,
    ], [
        0,
        I_max * ((np.log(E_t) - np.log(E_min)) /
                 (np.log(E_clip) - np.log(E_min))) * (X / E_t),
        I_max * ((np.log(X) - np.log(E_min)) /
                 (np.log(E_clip) - np.log(E_min))),
        I_max,
    ])

    if out_int:
        return as_int(np.round(X_p))
    else:
        return as_float(from_range_1(X_p / I_max))
コード例 #36
0
ファイル: rimm_romm_rgb.py プロジェクト: ajun73/Work_Code
def eotf_RIMMRGB(X_p, bit_depth=8, in_int=False, E_clip=2.0):
    """
    Defines the *RIMM RGB* encoding electro-optical transfer function
    (EOTF / EOCF).

    Parameters
    ----------
    X_p : numeric or array_like
        Non-linear data :math:`X'_{RIMM}`.
    bit_depth : int, optional
        Bit depth used for conversion.
    in_int : bool, optional
        Whether to treat the input value as integer code value or float
        equivalent of a code value at a given bit depth.
    E_clip : numeric, optional
        Maximum exposure level.

    Returns
    -------
    numeric or ndarray
        Linear data :math:`X_{RIMM}`.

    Notes
    -----

    +---------------+-----------------------+---------------+
    | **Domain \\*** | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X_p``       | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    +---------------+-----------------------+---------------+
    | **Range \\***  | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``X``         | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    -   \\* This definition has an input integer switch, thus the domain-range
        scale information is only given for the floating point mode.

    References
    ----------
    :cite:`Spaulding2000b`

    Examples
    --------
    >>> eotf_RIMMRGB(0.291673732475746)  # doctest: +ELLIPSIS
    0.1...
    >>> eotf_RIMMRGB(74, in_int=True)  # doctest: +ELLIPSIS
    0.1...
    """

    X_p = to_domain_1(X_p)

    I_max = 2**bit_depth - 1

    if not in_int:
        X_p = X_p * I_max

    V_clip = 1.099 * spow(E_clip, 0.45) - 0.099

    m = V_clip * X_p / I_max

    with domain_range_scale('ignore'):
        X = np.where(
            X_p / I_max < oetf_RIMMRGB(0.018, bit_depth, E_clip=E_clip),
            m / 4.5,
            spow((m + 0.099) / 1.099, 1 / 0.45),
        )

    return as_float(from_range_1(X))
コード例 #37
0
ファイル: luminance.py プロジェクト: colour-science/colour
def luminance_Fairchild2011(
    L_hdr: FloatingOrArrayLike,
    epsilon: FloatingOrArrayLike = 0.474,
    method: Union[Literal["hdr-CIELAB", "hdr-IPT"], str] = "hdr-CIELAB",
) -> FloatingOrNDArray:
    """
    Compute *luminance* :math:`Y` of given *Lightness* :math:`L_{hdr}` using
    *Fairchild and Chen (2011)* method according to *Michaelis-Menten*
    kinetics.

    Parameters
    ----------
    L_hdr
        *Lightness* :math:`L_{hdr}`.
    epsilon
        :math:`\\epsilon` exponent.
    method
        *Lightness* :math:`L_{hdr}` computation method.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        *Luminance* :math:`Y`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_hdr``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Fairchild2011`

    Examples
    --------
    >>> luminance_Fairchild2011(51.852958445912506)  # doctest: +ELLIPSIS
    0.1219722...
    >>> luminance_Fairchild2011(51.643108411718522, method='hdr-IPT')
    ... # doctest: +ELLIPSIS
    0.1219722...
    """

    L_hdr = to_domain_100(L_hdr)
    method = validate_method(method, ["hdr-CIELAB", "hdr-IPT"])

    if method == "hdr-cielab":
        maximum_perception = 247
    else:
        maximum_perception = 246

    Y = np.exp(
        np.log(
            substrate_concentration_MichaelisMenten_Michaelis1913(
                L_hdr - 0.02, maximum_perception, spow(2, epsilon))) / epsilon)

    return as_float(from_range_1(Y))
コード例 #38
0
ファイル: lightness.py プロジェクト: colour-science/colour
def lightness_Fairchild2011(
    Y: FloatingOrArrayLike,
    epsilon: FloatingOrArrayLike = 0.474,
    method: Union[Literal["hdr-CIELAB", "hdr-IPT"], str] = "hdr-CIELAB",
) -> FloatingOrNDArray:
    """
    Compute *Lightness* :math:`L_{hdr}` of given *luminance* :math:`Y` using
    *Fairchild and Chen (2011)* method according to *Michaelis-Menten*
    kinetics.

    Parameters
    ----------
    Y
        *Luminance* :math:`Y`.
    epsilon
        :math:`\\epsilon` exponent.
    method
        *Lightness* :math:`L_{hdr}` computation method.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        *Lightness* :math:`L_{hdr}`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_hdr``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Fairchild2011`

    Examples
    --------
    >>> lightness_Fairchild2011(12.19722535 / 100)  # doctest: +ELLIPSIS
    51.8529584...
    >>> lightness_Fairchild2011(12.19722535 / 100, method='hdr-IPT')
    ... # doctest: +ELLIPSIS
    51.6431084...
    """

    Y = to_domain_1(Y)
    method = validate_method(method, ["hdr-CIELAB", "hdr-IPT"])

    if method == "hdr-cielab":
        maximum_perception = 247
    else:
        maximum_perception = 246

    L_hdr = (
        reaction_rate_MichaelisMenten_Michaelis1913(
            spow(Y, epsilon), maximum_perception, spow(2, epsilon)
        )
        + 0.02
    )

    return as_float(from_range_100(L_hdr))
コード例 #39
0
ファイル: st_2084.py プロジェクト: colour-science/colour
def eotf_ST2084(
    N: FloatingOrArrayLike,
    L_p: Floating = 10000,
    constants: Structure = CONSTANTS_ST2084,
) -> FloatingOrNDArray:
    """
    Define *SMPTE ST 2084:2014* optimised perceptual electro-optical transfer
    function (EOTF).

    This perceptual quantizer (PQ) has been modeled by Dolby Laboratories
    using *Barten (1999)* contrast sensitivity function.

    Parameters
    ----------
    N
        Color value abbreviated as :math:`N`, that is directly proportional to
        the encoded signal representation, and which is not directly
        proportional to the optical output of a display device.
    L_p
        System peak luminance :math:`cd/m^2`, this parameter should stay at its
        default :math:`10000 cd/m^2` value for practical applications. It is
        exposed so that the definition can be used as a fitting function.
    constants
        *SMPTE ST 2084:2014* constants.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
          Target optical output :math:`C` in :math:`cd/m^2` of the ideal
          reference display.

    Warnings
    --------
    *SMPTE ST 2084:2014* is an absolute transfer function.

    Notes
    -----
    -   *SMPTE ST 2084:2014* is an absolute transfer function, thus the
        domain and range values for the *Reference* and *1* scales are only
        indicative that the data is not affected by scale transformations.

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``N``      | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``C``      | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Miller2014a`,
    :cite:`SocietyofMotionPictureandTelevisionEngineers2014a`

    Examples
    --------
    >>> eotf_ST2084(0.508078421517399)  # doctest: +ELLIPSIS
    100.0000000...
    """

    N = as_float_array(N)

    m_1_d = 1 / constants.m_1
    m_2_d = 1 / constants.m_2

    V_p = spow(N, m_2_d)

    n = V_p - constants.c_1
    # Limiting negative values.
    n = np.where(n < 0, 0, n)

    L = spow((n / (constants.c_2 - constants.c_3 * V_p)), m_1_d)
    C = L_p * L

    return as_float(C)
コード例 #40
0
ファイル: filmlight_tlog.py プロジェクト: Munins-eye/colour
def log_decoding_FilmLightTLog(t, w=128.0, g=16.0, o=0.075):
    """
    Defines the *FilmLight T-Log* log decoding curve.

    Parameters
    ----------
    t : numeric or array_like
        Non-linear data :math:`t`.
    w : numeric, optional
        Value of :math:`x` for :math:`t = 1.0`.
    g : numeric, optional
        Gradient at :math:`x = 0.0`.
    o : numeric, optional
        Value of :math:`t` for :math:`x = 0.0`.

    Returns
    -------
    numeric or ndarray
        Linear reflection data :math`x`.

    References
    ----------
    :cite:`Siragusano2018a`

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``t``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    -   The following is an excerpt from the FilmLight colour space file
        `./etc/colourspaces/FilmLight_TLog_EGamut.flspace` which can be
        obtained by installing the free Baselight for Nuke plugin::

            T-Log, a cineon driven log tone-curve developed by FilmLight.
            The colour space is designed to be used as *Working Colour Space*.

            Version 10.0
            This is similar to Cineon LogC function.

            The formula is...
            y = A + B*log(x + C)
            ...where x,y are the log and linear values.

            A,B,C are constants calculated from...
            w = x value for y = 1.0
            g = the gradient at x=0
            o = y value for x = 0.0

            We do not have an exact solution but the
            formula for b gives an approximation. The
            gradient is not g, but should be within a
            few percent for most sensible values of (w*g).

    Examples
    --------
    >>> log_decoding_FilmLightTLog(0.396567801298332)  # doctest: +ELLIPSIS
    0.1800000...
    """

    t = to_domain_1(t)

    b = 1.0 / (0.7107 + 1.2359 * np.log(w * g))
    gs = g / (1.0 - o)
    C = b / gs
    a = 1.0 - b * np.log(w + C)
    y0 = a + b * np.log(C)
    s = (1.0 - o) / (1.0 - y0)
    A = 1.0 + (a - 1.0) * s
    B = b * s
    G = gs * s

    x = np.where(
        t < o,
        (t - o) / G,
        np.exp((t - A) / B) - C,
    )

    return as_float(from_range_1(x))
コード例 #41
0
ファイル: sony_slog.py プロジェクト: colour-science/colour
def log_encoding_SLog3(
    x: FloatingOrArrayLike,
    bit_depth: Integer = 10,
    out_normalised_code_value: Boolean = True,
    in_reflection: Boolean = True,
) -> FloatingOrNDArray:
    """
    Define the *Sony S-Log3* log encoding curve / opto-electronic transfer
    function.

    Parameters
    ----------
    x
        Reflection or :math:`IRE / 100` input light level :math:`x` to a
        camera.
    bit_depth
        Bit depth used for conversion.
    out_normalised_code_value
        Whether the non-linear *Sony S-Log3* data :math:`y` is encoded as
        normalised code values.
    in_reflection
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Non-linear *Sony S-Log3* data :math:`y`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SonyCorporationd`

    Examples
    --------
    >>> log_encoding_SLog3(0.18)  # doctest: +ELLIPSIS
    0.4105571...

    The values of *S-Log3 10bit code values (18%, 90%)* table in
    :cite:`SonyCorporationd` are obtained as follows:

    >>> x = np.array([0, 18, 90]) / 100
    >>> np.around(log_encoding_SLog3(x, 10, False) * 100).astype(np.int)
    array([ 4, 41, 61])
    >>> np.around(log_encoding_SLog3(x) * (2 ** 10 - 1)).astype(np.int)
    array([ 95, 420, 598])
    """

    x = to_domain_1(x)

    if not in_reflection:
        x = x * 0.9

    y = np.where(
        x >= 0.01125000,
        (420 + np.log10((x + 0.01) / (0.18 + 0.01)) * 261.5) / 1023,
        (x * (171.2102946929 - 95) / 0.01125000 + 95) / 1023,
    )

    y_cv = y if out_normalised_code_value else legal_to_full(y, bit_depth)

    return as_float(from_range_1(y_cv))
コード例 #42
0
def log_encoding_NLog(
    in_r: FloatingOrArrayLike,
    bit_depth: Integer = 10,
    out_normalised_code_value: Boolean = True,
    in_reflection: Boolean = True,
    constants: Structure = NLOG_CONSTANTS,
) -> FloatingOrNDArray:
    """
    Define the *Nikon N-Log* log encoding curve / opto-electronic transfer
    function.

    Parameters
    ----------
    in_r
        Linear reflection data :math`in`.
    bit_depth
        Bit depth used for conversion.
    out_normalised_code_value
        Whether the non-linear *Nikon N-Log* data :math:`out` is encoded as
        normalised code values.
    in_reflection
        Whether the light level :math`in` to a camera is reflection.
    constants
        *Nikon N-Log* constants.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Non-linear data :math:`out`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``in_r``   | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``out_r``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Nikon2018`

    Examples
    --------
    >>> log_encoding_NLog(0.18)  # doctest: +ELLIPSIS
    0.3636677...
    """

    in_r = to_domain_1(in_r)

    if not in_reflection:
        in_r = in_r * 0.9

    cut1 = constants.cut1
    a = constants.a
    b = constants.b
    c = constants.c
    d = constants.d

    out_r = np.where(
        in_r < cut1,
        a * spow(in_r + b, 1 / 3),
        c * np.log(in_r) + d,
    )

    out_r_cv = (out_r if out_normalised_code_value else legal_to_full(
        out_r, bit_depth))

    return as_float(from_range_1(out_r_cv))
コード例 #43
0
ファイル: lightness.py プロジェクト: colour-science/colour
def lightness_Abebe2017(
    Y: FloatingOrArrayLike,
    Y_n: FloatingOrArrayLike = 100,
    method: Union[
        Literal["Michaelis-Menten", "Stevens"], str
    ] = "Michaelis-Menten",
) -> FloatingOrNDArray:
    """
    Compute *Lightness* :math:`L` of given *luminance* :math:`Y` using
    *Abebe, Pouli, Larabi and Reinhard (2017)* method according to
    *Michaelis-Menten* kinetics or *Stevens's Power Law*.

    Parameters
    ----------
    Y
        *Luminance* :math:`Y` in :math:`cd/m^2`.
    Y_n
        Adapting luminance :math:`Y_n` in :math:`cd/m^2`.
    method
        *Lightness* :math:`L` computation method.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        *Lightness* :math:`L`.

    Notes
    -----
    -   *Abebe, Pouli, Larabi and Reinhard (2017)* method uses absolute
        luminance levels, thus the domain and range values for the *Reference*
        and *1* scales are only indicative that the data is not affected by
        scale transformations.

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``Y``      | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+
    | ``Y_n``    | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L``      | ``UN``                | ``UN``        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Abebe2017a`

    Examples
    --------
    >>> lightness_Abebe2017(12.19722535)  # doctest: +ELLIPSIS
    0.4869555...
    >>> lightness_Abebe2017(12.19722535, method='Stevens')
    ... # doctest: +ELLIPSIS
    0.4745447...
    """

    Y = as_float_array(Y)
    Y_n = as_float_array(Y_n)
    method = validate_method(method, ["Michaelis-Menten", "Stevens"])

    Y_Y_n = Y / Y_n
    if method == "stevens":
        L = np.where(
            Y_n <= 100,
            1.226 * spow(Y_Y_n, 0.266) - 0.226,
            1.127 * spow(Y_Y_n, 0.230) - 0.127,
        )
    else:
        L = np.where(
            Y_n <= 100,
            reaction_rate_MichaelisMenten_Abebe2017(
                spow(Y_Y_n, 0.582), 1.448, 0.635, 0.813
            ),
            reaction_rate_MichaelisMenten_Abebe2017(
                spow(Y_Y_n, 0.293), 1.680, 1.584, 0.096
            ),
        )

    return as_float(L)
コード例 #44
0
ファイル: canon_log.py プロジェクト: vidakDK/colour
def log_encoding_CanonLog(x, bit_depth=10, out_legal=True, in_reflection=True):
    """
    Defines the *Canon Log* log encoding curve / opto-electronic transfer
    function.

    Parameters
    ----------
    x : numeric or array_like
        Linear data :math:`x`.
    bit_depth : int, optional
        Bit depth used for conversion.
    out_legal : bool, optional
        Whether the *Canon Log* non-linear data is encoded in legal
        range.
    in_reflection : bool, optional
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    numeric or ndarray
        *Canon Log* non-linear data.

    References
    ----------
    :cite:`Thorpe2012a`

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``clog``   | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    Examples
    --------
    >>> log_encoding_CanonLog(0.18) * 100  # doctest: +ELLIPSIS
    34.3389651...
    """

    x = to_domain_1(x)

    if in_reflection:
        x = x / 0.9

    with domain_range_scale('ignore'):
        clog = np.where(
            x < log_decoding_CanonLog(0.0730597, bit_depth, False),
            -(0.529136 * (np.log10(-x * 10.1596 + 1)) - 0.0730597),
            0.529136 * np.log10(10.1596 * x + 1) + 0.0730597,
        )

    clog = full_to_legal(clog, bit_depth) if out_legal else clog

    return as_float(from_range_1(clog))
コード例 #45
0
ファイル: llab.py プロジェクト: colour-science/colour
def XYZ_to_LLAB(
    XYZ: ArrayLike,
    XYZ_0: ArrayLike,
    Y_b: FloatingOrArrayLike,
    L: FloatingOrArrayLike,
    surround: InductionFactors_LLAB = VIEWING_CONDITIONS_LLAB[
        "Reference Samples & Images, Average Surround, Subtending < 4"],
) -> CAM_Specification_LLAB:
    """
    Compute the *:math:`LLAB(l:c)`* colour appearance model correlates.

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values of test sample / stimulus.
    XYZ_0
        *CIE XYZ* tristimulus values of reference white.
    Y_b
        Luminance factor of the background in :math:`cd/m^2`.
    L
        Absolute luminance :math:`L` of reference white in :math:`cd/m^2`.
    surround
         Surround viewing conditions induction factors.

    Returns
    -------
    :class:`colour.CAM_Specification_LLAB`
        *:math:`LLAB(l:c)`* colour appearance model specification.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ``    | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_0``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------------------------+-----------------------+---------------+
    | **Range**                    | **Scale - Reference** | **Scale - 1** |
    +==============================+=======================+===============+
    | ``CAM_Specification_LLAB.h`` | [0, 360]              | [0, 1]        |
    +------------------------------+-----------------------+---------------+

    References
    ----------
    :cite:`Fairchild2013x`, :cite:`Luo1996b`, :cite:`Luo1996c`

    Examples
    --------
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> XYZ_0 = np.array([95.05, 100.00, 108.88])
    >>> Y_b = 20.0
    >>> L = 318.31
    >>> surround = VIEWING_CONDITIONS_LLAB['ref_average_4_minus']
    >>> XYZ_to_LLAB(XYZ, XYZ_0, Y_b, L, surround)  # doctest: +ELLIPSIS
    CAM_Specification_LLAB(J=37.3668650..., C=0.0089496..., h=270..., \
s=0.0002395..., M=0.0190185..., HC=None, a=..., b=-0.0190185...)
    """

    _X, Y, _Z = tsplit(to_domain_100(XYZ))
    RGB = XYZ_to_RGB_LLAB(to_domain_100(XYZ))
    RGB_0 = XYZ_to_RGB_LLAB(to_domain_100(XYZ_0))

    # Reference illuminant *CIE Standard Illuminant D Series* *D65*.
    XYZ_0r = np.array([95.05, 100.00, 108.88])
    RGB_0r = XYZ_to_RGB_LLAB(XYZ_0r)

    # Computing chromatic adaptation.
    XYZ_r = chromatic_adaptation(RGB, RGB_0, RGB_0r, Y, surround.D)

    # -------------------------------------------------------------------------
    # Computing the correlate of *Lightness* :math:`L_L`.
    # -------------------------------------------------------------------------
    # Computing opponent colour dimensions.
    L_L, a, b = tsplit(
        opponent_colour_dimensions(XYZ_r, Y_b, surround.F_S, surround.F_L))

    # Computing perceptual correlates.
    # -------------------------------------------------------------------------
    # Computing the correlate of *chroma* :math:`Ch_L`.
    # -------------------------------------------------------------------------
    Ch_L = chroma_correlate(a, b)

    # -------------------------------------------------------------------------
    # Computing the correlate of *colourfulness* :math:`C_L`.
    # -------------------------------------------------------------------------
    C_L = colourfulness_correlate(L, L_L, Ch_L, surround.F_C)

    # -------------------------------------------------------------------------
    # Computing the correlate of *saturation* :math:`s_L`.
    # -------------------------------------------------------------------------
    s_L = saturation_correlate(Ch_L, L_L)

    # -------------------------------------------------------------------------
    # Computing the *hue* angle :math:`h_L`.
    # -------------------------------------------------------------------------
    h_L = hue_angle(a, b)
    # TODO: Implement hue composition computation.

    # -------------------------------------------------------------------------
    # Computing final opponent signals.
    # -------------------------------------------------------------------------
    A_L, B_L = tsplit(final_opponent_signals(C_L, h_L))

    return CAM_Specification_LLAB(
        L_L,
        Ch_L,
        as_float(from_range_degrees(h_L)),
        s_L,
        C_L,
        None,
        A_L,
        B_L,
    )
コード例 #46
0
ファイル: sony_slog.py プロジェクト: colour-science/colour
def log_encoding_SLog(
    x: FloatingOrArrayLike,
    bit_depth: Integer = 10,
    out_normalised_code_value: Boolean = True,
    in_reflection: Boolean = True,
) -> FloatingOrNDArray:
    """
    Define the *Sony S-Log* log encoding curve / opto-electronic transfer
    function.

    Parameters
    ----------
    x
        Reflection or :math:`IRE / 100` input light level :math:`x` to a
        camera.
    bit_depth
        Bit depth used for conversion.
    out_normalised_code_value
        Whether the non-linear *Sony S-Log* data :math:`y` is encoded as
        normalised code values.
    in_reflection
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Non-linear *Sony S-Log* data :math:`y`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SonyCorporation2012a`

    Examples
    --------
    >>> log_encoding_SLog(0.18)  # doctest: +ELLIPSIS
    0.3849708...

    The values of *IRE and CV of S-Log2 @ISO800* table in
    :cite:`SonyCorporation2012a` are obtained as follows:

    >>> x = np.array([0, 18, 90]) / 100
    >>> np.around(log_encoding_SLog(x, 10, False) * 100).astype(np.int)
    array([ 3, 38, 65])
    >>> np.around(log_encoding_SLog(x) * (2 ** 10 - 1)).astype(np.int)
    array([ 90, 394, 636])
    """

    x = to_domain_1(x)

    if in_reflection:
        x = x / 0.9

    y = np.where(
        x >= 0,
        ((0.432699 * np.log10(x + 0.037584) + 0.616596) + 0.03),
        x * 5 + 0.030001222851889303,
    )

    y_cv = full_to_legal(y, bit_depth) if out_normalised_code_value else y

    return as_float(from_range_1(y_cv))
コード例 #47
0
ファイル: sony_slog.py プロジェクト: colour-science/colour
def log_encoding_SLog3(x, bit_depth=10, out_legal=True, in_reflection=True):
    """
    Defines the *Sony S-Log3* log encoding curve / opto-electronic transfer
    function.

    Parameters
    ----------
    x : numeric or array_like
        Reflection or :math:`IRE / 100` input light level :math:`x` to a
        camera.
    bit_depth : int, optional
        Bit depth used for conversion.
    out_legal : bool, optional
        Whether the non-linear *Sony S-Log3* data :math:`y` is encoded in legal
        range.
    in_reflection : bool, optional
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    numeric or ndarray
        Non-linear *Sony S-Log3* data :math:`y`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SonyCorporationd`

    Examples
    --------
    >>> log_encoding_SLog3(0.18)  # doctest: +ELLIPSIS
    0.4105571...
    >>> log_encoding_SLog3(0.18, out_legal=False)  # doctest: +ELLIPSIS
    0.4063926...
    >>> log_encoding_SLog3(0.18, in_reflection=False)  # doctest: +ELLIPSIS
    0.3995079...
    """

    x = to_domain_1(x)

    if not in_reflection:
        x = x * 0.9

    y = np.where(
        x >= 0.01125000,
        (420 + np.log10((x + 0.01) / (0.18 + 0.01)) * 261.5) / 1023,
        (x * (171.2102946929 - 95) / 0.01125000 + 95) / 1023,
    )

    y = y if out_legal else legal_to_full(y, bit_depth)

    return as_float(from_range_1(y))
コード例 #48
0
ファイル: aces.py プロジェクト: ajun73/Work_Code
def log_encoding_ACESproxy(lin_AP1,
                           bit_depth=10,
                           out_int=False,
                           constants=ACES_PROXY_CONSTANTS):
    """
    Defines the *ACESproxy* colourspace log encoding curve / opto-electronic
    transfer function.

    Parameters
    ----------
    lin_AP1 : numeric or array_like
        *lin_AP1* value.
    bit_depth : int, optional
        **{10, 12}**,
        *ACESproxy* bit depth.
    out_int : bool, optional
        Whether to return value as integer code value or float equivalent of a
        code value at a given bit depth.
    constants : Structure, optional
        *ACESproxy* constants.

    Returns
    -------
    numeric or ndarray
        *ACESproxy* non-linear value.

    Notes
    -----

    +---------------+-----------------------+---------------+
    | **Domain \\*** | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``lin_AP1``   | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    +---------------+-----------------------+---------------+
    | **Range \\***  | **Scale - Reference** | **Scale - 1** |
    +===============+=======================+===============+
    | ``ACESproxy`` | [0, 1]                | [0, 1]        |
    +---------------+-----------------------+---------------+

    -   \\* This definition has an output integer switch, thus the domain-range
        scale information is only given for the floating point mode.

    References
    ----------
    :cite:`TheAcademyofMotionPictureArtsandSciences2014q`,
    :cite:`TheAcademyofMotionPictureArtsandSciences2014r`,
    :cite:`TheAcademyofMotionPictureArtsandSciences2014s`,
    :cite:`TheAcademyofMotionPictureArtsandSciencese`

    Examples
    --------
    >>> log_encoding_ACESproxy(0.18)  # doctest: +ELLIPSIS
    0.4164222...
    >>> log_encoding_ACESproxy(0.18, out_int=True)
    426
    """

    lin_AP1 = to_domain_1(lin_AP1)

    constants = constants[bit_depth]

    CV_min = np.resize(constants.CV_min, lin_AP1.shape)
    CV_max = np.resize(constants.CV_max, lin_AP1.shape)

    def float_2_cv(x):
        """
        Converts given numeric to code value.
        """

        return np.maximum(CV_min, np.minimum(CV_max, np.round(x)))

    ACESproxy = np.where(
        lin_AP1 > 2**-9.72,
        float_2_cv((np.log2(lin_AP1) + constants.mid_log_offset) *
                   constants.steps_per_stop + constants.mid_CV_offset),
        np.resize(CV_min, lin_AP1.shape),
    )

    if out_int:
        return as_int(np.round(ACESproxy))
    else:
        return as_float(from_range_1(ACESproxy / (2**bit_depth - 1)))
コード例 #49
0
ファイル: sony_slog.py プロジェクト: colour-science/colour
def log_encoding_SLog(x, bit_depth=10, out_legal=True, in_reflection=True):
    """
    Defines the *Sony S-Log* log encoding curve / opto-electronic transfer
    function.

    Parameters
    ----------
    x : numeric or array_like
        Reflection or :math:`IRE / 100` input light level :math:`x` to a
        camera.
    bit_depth : int, optional
        Bit depth used for conversion.
    out_legal : bool, optional
        Whether the non-linear *Sony S-Log* data :math:`y` is encoded in legal
        range.
    in_reflection : bool, optional
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    numeric or ndarray
        Non-linear *Sony S-Log* data :math:`y`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SonyCorporation2012a`

    Examples
    --------
    >>> log_encoding_SLog(0.18)  # doctest: +ELLIPSIS
    0.3849708...
    >>> log_encoding_SLog(0.18, out_legal=False)  # doctest: +ELLIPSIS
    0.3765127...
    >>> log_encoding_SLog(0.18, in_reflection=False)  # doctest: +ELLIPSIS
    0.3708204...
    """

    x = to_domain_1(x)

    if in_reflection:
        x = x / 0.9

    y = np.where(
        x >= 0,
        ((0.432699 * np.log10(x + 0.037584) + 0.616596) + 0.03),
        x * 5 + 0.030001222851889303,
    )

    y = full_to_legal(y, bit_depth) if out_legal else y

    return as_float(from_range_1(y))
コード例 #50
0
def log_decoding_ALEXALogC(
    t: FloatingOrArrayLike,
    firmware: Union[Literal["SUP 2.x", "SUP 3.x"], str] = "SUP 3.x",
    method: Union[Literal["Linear Scene Exposure Factor",
                          "Normalised Sensor Signal"],
                  str, ] = "Linear Scene Exposure Factor",
    EI: Literal[160, 200, 250, 320, 400, 500, 640, 800, 1000, 1280,
                1600] = 800,
) -> FloatingOrNDArray:
    """
    Define the *ARRI ALEXA Log C* log decoding curve / electro-optical
    transfer function.

    Parameters
    ----------
    t
        *ARRI ALEXA Log C* encoded data :math:`t`.
    firmware
        Alexa firmware version.
    method
        Conversion method.
    EI
        Exposure Index :math:`EI`.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Linear data :math:`x`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``t``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`ARRI2012a`

    Examples
    --------
    >>> log_decoding_ALEXALogC(0.391006832034084)  # doctest: +ELLIPSIS
    0.18...
    """

    t = to_domain_1(t)
    method = validate_method(
        method, ["Linear Scene Exposure Factor", "Normalised Sensor Signal"])

    cut, a, b, c, d, e, f, _e_cut_f = DATA_ALEXA_LOG_C_CURVE_CONVERSION[
        firmware][method][EI]

    x = np.where(t > e * cut + f, (10**((t - d) / c) - b) / a, (t - f) / e)

    return as_float(from_range_1(x))
コード例 #51
0
def log_decoding_VLog(V_out,
                      bit_depth=10,
                      in_legal=True,
                      out_reflection=True,
                      constants=VLOG_CONSTANTS):
    """
    Defines the *Panasonic V-Log* log decoding curve / electro-optical transfer
    function.

    Parameters
    ----------
    V_out : numeric or array_like
        Non-linear data :math:`V_{out}`.
    bit_depth : int, optional
        Bit depth used for conversion.
    in_legal : bool, optional
        Whether the non-linear *Panasonic V-Log* data :math:`V_{out}` is
        encoded in legal range.
    out_reflection : bool, optional
        Whether the light level :math`L_{in}` to a camera is reflection.
    constants : Structure, optional
        *Panasonic V-Log* constants.

    Returns
    -------
    numeric or ndarray
        Linear reflection data :math`L_{in}`.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V_out``  | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_in``   | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Panasonic2014a`

    Examples
    --------
    >>> log_decoding_VLog(0.423311448760136)  # doctest: +ELLIPSIS
    0.1799999...
    """

    V_out = to_domain_1(V_out)

    V_out = V_out if in_legal else full_to_legal(V_out, bit_depth)

    cut2 = constants.cut2
    b = constants.b
    c = constants.c
    d = constants.d

    L_in = np.where(
        V_out < cut2,
        (V_out - 0.125) / 5.6,
        10 ** ((V_out - d) / c) - b,
    )

    if not out_reflection:
        L_in = L_in / 0.9

    return as_float(from_range_1(L_in))
コード例 #52
0
ファイル: common.py プロジェクト: colour-science/colour
def legal_to_full(
    CV: Union[FloatingOrArrayLike, IntegerOrArrayLike],
    bit_depth: Integer = 10,
    in_int: Boolean = False,
    out_int: Boolean = False,
) -> Union[FloatingOrNDArray, IntegerOrNDArray]:
    """
    Convert given code value :math:`CV` or float equivalent of a code value at
    a given bit depth from legal range (studio swing) to full range
    (full swing).

    Parameters
    ----------
    CV
        Legal range code value :math:`CV` or float equivalent of a code value
        at a given bit depth.
    bit_depth
        Bit depth used for conversion.
    in_int
        Whether to treat the input value as integer code value or float
        equivalent of a code value at a given bit depth.
    out_int
        Whether to return value as integer code value or float equivalent of a
        code value at a given bit depth.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.integer` or :class:`numpy.ndarray`
        Full range code value :math:`CV` or float equivalent of a code value
        at a given bit depth.

    Examples
    --------
    >>> legal_to_full(64 / 1023)
    0.0
    >>> legal_to_full(940 / 1023)
    1.0
    >>> legal_to_full(64 / 1023, out_int=True)
    0
    >>> legal_to_full(940 / 1023, out_int=True)
    1023
    >>> legal_to_full(64, in_int=True)
    0.0
    >>> legal_to_full(940, in_int=True)
    1.0
    >>> legal_to_full(64, in_int=True, out_int=True)
    0
    >>> legal_to_full(940, in_int=True, out_int=True)
    1023
    """

    CV = as_float_array(CV)

    MV = 2**bit_depth - 1

    CV_full = as_int_array(np.round(CV)) if in_int else CV * MV

    B, W = CV_range(bit_depth, True, True)

    CV_full = (CV_full - B) / (W - B)

    if out_int:
        return as_int(np.round(CV_full * MV))
    else:
        return as_float(CV_full)
コード例 #53
0
ファイル: itur_bt_2100.py プロジェクト: colour-science/colour
def ootf_reverse_BT2100_HLG(F_D, L_B=0, L_W=1000, gamma=None):
    """
    Defines *Recommendation ITU-R BT.2100* *Reference HLG* reverse opto-optical
    transfer function (OOTF / OOCF).

    Parameters
    ----------
    F_D : numeric or array_like
        :math:`F_D` is the luminance of a displayed linear component
        :math:`{R_D, G_D, or B_D}`, in :math:`cd/m^2`.
    L_B : numeric, optional
        :math:`L_B` is the display luminance for black in :math:`cd/m^2`.
    L_W : numeric, optional
        :math:`L_W` is nominal peak luminance of the display in :math:`cd/m^2`
        for achromatic pixels.
    gamma : numeric, optional
        System gamma value, 1.2 at the nominal display peak luminance of
        :math:`1000 cd/m^2`.

    Returns
    -------
    numeric or ndarray
        :math:`E` is the signal for each colour component
        :math:`{R_S, G_S, B_S}` proportional to scene linear light and scaled
        by camera exposure.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``F_D``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``E``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Borer2017a`, :cite:`InternationalTelecommunicationUnion2016a`

    Examples
    --------
    >>> ootf_reverse_BT2100_HLG(63.095734448019336)  # doctest: +ELLIPSIS
    0.1000000...
    """

    F_D = np.atleast_1d(to_domain_1(F_D))

    if F_D.shape[-1] != 3:
        usage_warning(
            '"Recommendation ITU-R BT.2100" "Reference HLG OOTF" uses '
            'RGB Luminance in computations and expects a vector input, thus '
            'the given input array will be stacked to compose a vector for '
            'internal computations but a single component will be output.')
        R_D = G_D = B_D = F_D
    else:
        R_D, G_D, B_D = tsplit(F_D)

    Y_D = np.sum(BT2100_HLG_WEIGHTS * tstack([R_D, G_D, B_D]), axis=-1)

    alpha = L_W - L_B
    beta = L_B

    if gamma is None:
        gamma = gamma_function_BT2100_HLG(L_W)

    R_S = np.where(
        Y_D == beta,
        0.0,
        (np.abs((Y_D - beta) / alpha) **
         ((1 - gamma) / gamma)) * (R_D - beta) / alpha,
    )
    G_S = np.where(
        Y_D == beta,
        0.0,
        (np.abs((Y_D - beta) / alpha) **
         ((1 - gamma) / gamma)) * (G_D - beta) / alpha,
    )
    B_S = np.where(
        Y_D == beta,
        0.0,
        (np.abs((Y_D - beta) / alpha) **
         ((1 - gamma) / gamma)) * (B_D - beta) / alpha,
    )

    if F_D.shape[-1] != 3:
        return as_float(from_range_1(R_S))
    else:
        RGB_S = tstack([R_S, G_S, B_S])

        return from_range_1(RGB_S)
コード例 #54
0
ファイル: cam16.py プロジェクト: colour-science/colour
def XYZ_to_CAM16(
    XYZ: ArrayLike,
    XYZ_w: ArrayLike,
    L_A: FloatingOrArrayLike,
    Y_b: FloatingOrArrayLike,
    surround: Union[
        InductionFactors_CIECAM02,
        InductionFactors_CAM16] = VIEWING_CONDITIONS_CAM16["Average"],
    discount_illuminant: Boolean = False,
) -> CAM_Specification_CAM16:
    """
    Compute the *CAM16* colour appearance model correlates from given
    *CIE XYZ* tristimulus values.

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values of test sample / stimulus.
    XYZ_w
        *CIE XYZ* tristimulus values of reference white.
    L_A
        Adapting field *luminance* :math:`L_A` in :math:`cd/m^2`, (often taken
        to be 20% of the luminance of a white object in the scene).
    Y_b
        Luminous factor of background :math:`Y_b` such as
        :math:`Y_b = 100 x L_b / L_w` where :math:`L_w` is the luminance of the
        light source and :math:`L_b` is the luminance of the background. For
        viewing images, :math:`Y_b` can be the average :math:`Y` value for the
        pixels in the entire image, or frequently, a :math:`Y` value of 20,
        approximate an :math:`L^*` of 50 is used.
    surround
        Surround viewing conditions induction factors.
    discount_illuminant
        Truth value indicating if the illuminant should be discounted.

    Returns
    -------
    :class:`colour.CAM_Specification_CAM16`
        *CAM16* colour appearance model specification.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ``    | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_w``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

    +-------------------------------+-----------------------+---------------+
    | **Range**                     | **Scale - Reference** | **Scale - 1** |
    +===============================+=======================+===============+
    | ``CAM_Specification_CAM16.J`` | [0, 100]              | [0, 1]        |
    +-------------------------------+-----------------------+---------------+
    | ``CAM_Specification_CAM16.C`` | [0, 100]              | [0, 1]        |
    +-------------------------------+-----------------------+---------------+
    | ``CAM_Specification_CAM16.h`` | [0, 360]              | [0, 1]        |
    +-------------------------------+-----------------------+---------------+
    | ``CAM_Specification_CAM16.s`` | [0, 100]              | [0, 1]        |
    +-------------------------------+-----------------------+---------------+
    | ``CAM_Specification_CAM16.Q`` | [0, 100]              | [0, 1]        |
    +-------------------------------+-----------------------+---------------+
    | ``CAM_Specification_CAM16.M`` | [0, 100]              | [0, 1]        |
    +-------------------------------+-----------------------+---------------+
    | ``CAM_Specification_CAM16.H`` | [0, 400]              | [0, 1]        |
    +-------------------------------+-----------------------+---------------+

    References
    ----------
    :cite:`Li2017`

    Examples
    --------
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> XYZ_w = np.array([95.05, 100.00, 108.88])
    >>> L_A = 318.31
    >>> Y_b = 20.0
    >>> surround = VIEWING_CONDITIONS_CAM16['Average']
    >>> XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround)  # doctest: +ELLIPSIS
    CAM_Specification_CAM16(J=41.7312079..., C=0.1033557..., \
h=217.0679597..., s=2.3450150..., Q=195.3717089..., M=0.1074367..., \
H=275.5949861..., HC=None)
    """

    XYZ = to_domain_100(XYZ)
    XYZ_w = to_domain_100(XYZ_w)
    _X_w, Y_w, _Z_w = tsplit(XYZ_w)
    L_A = as_float_array(L_A)
    Y_b = as_float_array(Y_b)

    # Step 0
    # Converting *CIE XYZ* tristimulus values to sharpened *RGB* values.
    RGB_w = vector_dot(MATRIX_16, XYZ_w)

    # Computing degree of adaptation :math:`D`.
    D = (np.clip(degree_of_adaptation(surround.F, L_A), 0, 1)
         if not discount_illuminant else ones(L_A.shape))

    n, F_L, N_bb, N_cb, z = viewing_condition_dependent_parameters(
        Y_b, Y_w, L_A)

    D_RGB = (D[..., np.newaxis] * Y_w[..., np.newaxis] / RGB_w + 1 -
             D[..., np.newaxis])
    RGB_wc = D_RGB * RGB_w

    # Applying forward post-adaptation non-linear response compression.
    RGB_aw = post_adaptation_non_linear_response_compression_forward(
        RGB_wc, F_L)

    # Computing achromatic responses for the whitepoint.
    A_w = achromatic_response_forward(RGB_aw, N_bb)

    # Step 1
    # Converting *CIE XYZ* tristimulus values to sharpened *RGB* values.
    RGB = vector_dot(MATRIX_16, XYZ)

    # Step 2
    RGB_c = D_RGB * RGB

    # Step 3
    # Applying forward post-adaptation non-linear response compression.
    RGB_a = post_adaptation_non_linear_response_compression_forward(RGB_c, F_L)

    # Step 4
    # Converting to preliminary cartesian coordinates.
    a, b = tsplit(opponent_colour_dimensions_forward(RGB_a))

    # Computing the *hue* angle :math:`h`.
    h = hue_angle(a, b)

    # Step 5
    # Computing eccentricity factor *e_t*.
    e_t = eccentricity_factor(h)

    # Computing hue :math:`h` quadrature :math:`H`.
    H = hue_quadrature(h)
    # TODO: Compute hue composition.

    # Step 6
    # Computing achromatic responses for the stimulus.
    A = achromatic_response_forward(RGB_a, N_bb)

    # Step 7
    # Computing the correlate of *Lightness* :math:`J`.
    J = lightness_correlate(A, A_w, surround.c, z)

    # Step 8
    # Computing the correlate of *brightness* :math:`Q`.
    Q = brightness_correlate(surround.c, J, A_w, F_L)

    # Step 9
    # Computing the correlate of *chroma* :math:`C`.
    C = chroma_correlate(J, n, surround.N_c, N_cb, e_t, a, b, RGB_a)

    # Computing the correlate of *colourfulness* :math:`M`.
    M = colourfulness_correlate(C, F_L)

    # Computing the correlate of *saturation* :math:`s`.
    s = saturation_correlate(M, Q)

    return CAM_Specification_CAM16(
        as_float(from_range_100(J)),
        as_float(from_range_100(C)),
        as_float(from_range_degrees(h)),
        as_float(from_range_100(s)),
        as_float(from_range_100(Q)),
        as_float(from_range_100(M)),
        as_float(from_range_degrees(H, 400)),
        None,
    )
コード例 #55
0
def log_encoding_ALEXALogC(
    x: FloatingOrArrayLike,
    firmware: Union[Literal["SUP 2.x", "SUP 3.x"], str] = "SUP 3.x",
    method: Union[Literal["Linear Scene Exposure Factor",
                          "Normalised Sensor Signal"],
                  str, ] = "Linear Scene Exposure Factor",
    EI: Literal[160, 200, 250, 320, 400, 500, 640, 800, 1000, 1280,
                1600] = 800,
) -> FloatingOrNDArray:
    """
    Define the *ARRI ALEXA Log C* log encoding curve / opto-electronic
    transfer function.

    Parameters
    ----------
    x
        Linear data :math:`x`.
    firmware
        Alexa firmware version.
    method
        Conversion method.
    EI
        Exposure Index :math:`EI`.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        *ARRI ALEXA Log C* encoded data :math:`t`.

    References
    ----------
    :cite:`ARRI2012a`

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``t``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    Examples
    --------
    >>> log_encoding_ALEXALogC(0.18)  # doctest: +ELLIPSIS
    0.3910068...
    """

    x = to_domain_1(x)
    firmware = validate_method(firmware, ["SUP 3.x", "SUP 2.x"])
    method = validate_method(
        method, ["Linear Scene Exposure Factor", "Normalised Sensor Signal"])

    cut, a, b, c, d, e, f, _e_cut_f = DATA_ALEXA_LOG_C_CURVE_CONVERSION[
        firmware][method][EI]

    t = np.where(x > cut, c * np.log10(a * x + b) + d, e * x + f)

    return as_float(from_range_1(t))
コード例 #56
0
ファイル: itur_bt_2100.py プロジェクト: Munins-eye/colour
def ootf_reverse_BT2100_HLG(F_D, L_B=0, L_W=1000, gamma=None):
    """
    Defines *Recommendation ITU-R BT.2100* *Reference HLG* reverse opto-optical
    transfer function (OOTF / OOCF).

    Parameters
    ----------
    F_D : numeric or array_like
        :math:`F_D` is the luminance of a displayed linear component
        :math:`{R_D, G_D, or B_D}`, in :math:`cd/m^2`.
    L_B : numeric, optional
        :math:`L_B` is the display luminance for black in :math:`cd/m^2`.
    L_W : numeric, optional
        :math:`L_W` is nominal peak luminance of the display in :math:`cd/m^2`
        for achromatic pixels.
    gamma : numeric, optional
        System gamma value, 1.2 at the nominal display peak luminance of
        :math:`1000 cd/m^2`.

    Returns
    -------
    numeric or ndarray
        :math:`E` is the signal for each colour component
        :math:`{R_S, G_S, B_S}` proportional to scene linear light and scaled
        by camera exposure.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``F_D``    | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``E``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`Borer2017a`, :cite:`InternationalTelecommunicationUnion2016a`

    Examples
    --------
    >>> ootf_reverse_BT2100_HLG(63.095734448019336)  # doctest: +ELLIPSIS
    0.1000000...
    """

    F_D = np.atleast_1d(to_domain_1(F_D))

    if F_D.shape[-1] != 3:
        usage_warning(
            '"Recommendation ITU-R BT.2100" "Reference HLG OOTF" uses '
            'RGB Luminance in computations and expects a vector input, thus '
            'the given input array will be stacked to compose a vector for '
            'internal computations but a single component will be output.')
        R_D = G_D = B_D = F_D
    else:
        R_D, G_D, B_D = tsplit(F_D)

    Y_D = np.sum(BT2100_HLG_WEIGHTS * tstack([R_D, G_D, B_D]), axis=-1)

    alpha = L_W - L_B
    beta = L_B

    if gamma is None:
        gamma = gamma_function_BT2100_HLG(L_W)

    R_S = np.where(
        Y_D == beta,
        0.0,
        (np.abs((Y_D - beta) / alpha)**((1 - gamma) / gamma)) * (R_D - beta) /
        alpha,
    )
    G_S = np.where(
        Y_D == beta,
        0.0,
        (np.abs((Y_D - beta) / alpha)**((1 - gamma) / gamma)) * (G_D - beta) /
        alpha,
    )
    B_S = np.where(
        Y_D == beta,
        0.0,
        (np.abs((Y_D - beta) / alpha)**((1 - gamma) / gamma)) * (B_D - beta) /
        alpha,
    )

    if F_D.shape[-1] != 3:
        return as_float(from_range_1(R_S))
    else:
        RGB_S = tstack([R_S, G_S, B_S])

        return from_range_1(RGB_S)
コード例 #57
0
ファイル: dicom_gsdf.py プロジェクト: Munins-eye/colour
def eotf_DICOMGSDF(J, in_int=False):
    """
    Defines the *DICOM - Grayscale Standard Display Function* electro-optical
    transfer function (EOTF / EOCF).

    Parameters
    ----------
    J : numeric or array_like
        Just-Noticeable Difference (JND) Index, :math:`j`.
    in_int : bool, optional
        Whether to treat the input value as integer code value or float
        equivalent of a code value at a given bit depth.

    Returns
    -------
    numeric or 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 = DICOMGSDF_CONSTANTS.a
    b = DICOMGSDF_CONSTANTS.b
    c = DICOMGSDF_CONSTANTS.c
    d = DICOMGSDF_CONSTANTS.d
    e = DICOMGSDF_CONSTANTS.e
    f = DICOMGSDF_CONSTANTS.f
    g = DICOMGSDF_CONSTANTS.g
    h = DICOMGSDF_CONSTANTS.h
    k = DICOMGSDF_CONSTANTS.k
    m = DICOMGSDF_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))
コード例 #58
0
ファイル: dicom_gsdf.py プロジェクト: Munins-eye/colour
def oetf_DICOMGSDF(L, out_int=False):
    """
    Defines the *DICOM - Grayscale Standard Display Function* opto-electronic
    transfer function (OETF / OECF).

    Parameters
    ----------
    L : numeric or array_like
        *Luminance* :math:`L`.
    out_int : bool, optional
        Whether to return value as integer code value or float equivalent of a
        code value at a given bit depth.

    Returns
    -------
    numeric or 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
    --------
    >>> oetf_DICOMGSDF(130.0662)  # doctest: +ELLIPSIS
    0.5004862...
    >>> oetf_DICOMGSDF(130.0662, out_int=True)
    512
    """

    L = to_domain_1(L)

    L_lg = np.log10(L)

    A = DICOMGSDF_CONSTANTS.A
    B = DICOMGSDF_CONSTANTS.B
    C = DICOMGSDF_CONSTANTS.C
    D = DICOMGSDF_CONSTANTS.D
    E = DICOMGSDF_CONSTANTS.E
    F = DICOMGSDF_CONSTANTS.F
    G = DICOMGSDF_CONSTANTS.G
    H = DICOMGSDF_CONSTANTS.H
    I = DICOMGSDF_CONSTANTS.I  # noqa

    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))
コード例 #59
0
ファイル: sony_slog.py プロジェクト: colour-science/colour
def log_decoding_SLog3(
    y: FloatingOrArrayLike,
    bit_depth: Integer = 10,
    in_normalised_code_value: Boolean = True,
    out_reflection: Boolean = True,
) -> FloatingOrNDArray:
    """
    Define the *Sony S-Log3* log decoding curve / electro-optical transfer
    function.

    Parameters
    ----------
    y
        Non-linear *Sony S-Log3* data :math:`y`.
    bit_depth
        Bit depth used for conversion.
    in_normalised_code_value
        Whether the non-linear *Sony S-Log3* data :math:`y` is encoded as
        normalised code values.
    out_reflection
        Whether the light level :math:`x` to a camera is reflection.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Reflection or :math:`IRE / 100` input light level :math:`x` to a
        camera.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``y``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``x``      | [0, 1]                | [0, 1]        |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`SonyCorporationd`

    Examples
    --------
    >>> log_decoding_SLog3(0.410557184750733)  # doctest: +ELLIPSIS
    0.1...
    """

    y = to_domain_1(y)

    y = y if in_normalised_code_value else full_to_legal(y, bit_depth)

    x = np.where(
        y >= 171.2102946929 / 1023,
        ((10**((y * 1023 - 420) / 261.5)) * (0.18 + 0.01) - 0.01),
        (y * 1023 - 95) * 0.01125000 / (171.2102946929 - 95),
    )

    if not out_reflection:
        x = x / 0.9

    return as_float(from_range_1(x))
コード例 #60
0
ファイル: common.py プロジェクト: colour-science/colour
def full_to_legal(
    CV: Union[FloatingOrArrayLike, IntegerOrArrayLike],
    bit_depth: Integer = 10,
    in_int: Boolean = False,
    out_int: Boolean = False,
) -> Union[FloatingOrNDArray, IntegerOrNDArray]:
    """
    Convert given code value :math:`CV` or float equivalent of a code value at
    a given bit depth from full range (full swing) to legal range
    (studio swing).

    Parameters
    ----------
    CV
        Full range code value :math:`CV` or float equivalent of a code value at
        a given bit depth.
    bit_depth
        Bit depth used for conversion.
    in_int
        Whether to treat the input value as integer code value or float
        equivalent of a code value at a given bit depth.
    out_int
        Whether to return value as integer code value or float equivalent of a
        code value at a given bit depth.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.integer` or :class:`numpy.ndarray`
        Legal range code value :math:`CV` or float equivalent of a code value
        at a given bit depth.

    Examples
    --------
    >>> full_to_legal(0.0)  # doctest: +ELLIPSIS
    0.0625610...
    >>> full_to_legal(1.0)  # doctest: +ELLIPSIS
    0.9188660...
    >>> full_to_legal(0.0, out_int=True)
    64
    >>> full_to_legal(1.0, out_int=True)
    940
    >>> full_to_legal(0, in_int=True)  # doctest: +ELLIPSIS
    0.0625610...
    >>> full_to_legal(1023, in_int=True)  # doctest: +ELLIPSIS
    0.9188660...
    >>> full_to_legal(0, in_int=True, out_int=True)
    64
    >>> full_to_legal(1023, in_int=True, out_int=True)
    940
    """

    CV = as_float_array(CV)

    MV = 2**bit_depth - 1

    CV_legal = as_int_array(np.round(CV / MV)) if in_int else CV

    B, W = CV_range(bit_depth, True, True)

    CV_legal = (W - B) * CV_legal + B

    if out_int:
        return as_int(np.round(CV_legal))
    else:
        return as_float(CV_legal / MV)