コード例 #1
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def normalised_achromatic_lightness_correlate(B_r, B_rw):
    """
    Returns the *normalised achromatic Lightness* correlate :math:`L_n^\\star`.

    Parameters
    ----------
    B_r : numeric or array_like
        *Brightness* correlate :math:`B_r`.
    B_rw : numeric or array_like
        Ideal white *brightness* correlate :math:`B_{rw}`.

    Returns
    -------
    numeric or ndarray
        *Normalised achromatic Lightness* correlate :math:`L_n^\\star`.

    Examples
    --------
    >>> B_r = 62.626673467230766
    >>> B_rw = 125.24353925846037
    >>> normalised_achromatic_lightness_correlate(B_r, B_rw)
    ... # doctest: +ELLIPSIS
    50.0039154...
    """

    B_r = as_float_array(B_r)
    B_rw = as_float_array(B_rw)

    return 100 * (B_r / B_rw)
コード例 #2
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def scaling_coefficient(x, y):
    """
    Returns the scaling coefficient :math:`e(R)` or :math:`e(G)`.

    Parameters
    ----------
    x: numeric or array_like
        Cone response.
    y: numeric or array_like
        Intermediate value.

    Returns
    -------
    numeric or ndarray
        Scaling coefficient :math:`e(R)` or :math:`e(G)`.

    Examples
    --------
    >>> x = 20.000520600000002
    >>> y = 1.000042192
    >>> scaling_coefficient(x, y)
    array(1.0)
    """

    x = as_float_array(x)
    y = as_float_array(y)

    return np.where(x >= (20 * y), 1.758, 1)
コード例 #3
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def brightness_correlate(bRGB_o, bL_or, Q):
    """
    Returns the *brightness* correlate :math:`B_r`.

    Parameters
    ----------
    bRGB_o: ndarray
         Chromatic adaptation exponential factors :math:`\\beta_1(R_o)`,
         :math:`\\beta_1(G_o)` and :math:`\\beta_2(B_o)`.
    bL_or: numeric or array_like
         Normalising chromatic adaptation exponential factor
         :math:`\\beta_1(B_or)`.
    Q : numeric or array_like
        Achromatic response :math:`Q`.
    Returns
    -------
    numeric or ndarray
        *Brightness* correlate :math:`B_r`.

    Examples
    --------
    >>> bRGB_o = np.array([4.61062223, 4.61058926, 4.65206986])
    >>> bL_or = 3.681021495604089
    >>> Q = -0.000117024294955
    >>> brightness_correlate(bRGB_o, bL_or, Q)  # doctest: +ELLIPSIS
    62.6266734...
    """

    bR_o, bG_o, _bB_o = tsplit(bRGB_o)
    bL_or = as_float_array(bL_or)
    Q = as_float_array(Q)

    B_r = (50 / bL_or) * ((2 / 3) * bR_o + (1 / 3) * bG_o) + Q

    return B_r
コード例 #4
0
ファイル: atd95.py プロジェクト: colour-science/colour
def luminance_to_retinal_illuminance(XYZ, Y_c):
    """
    Converts from luminance in :math:`cd/m^2` to retinal illuminance in
    trolands.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values.
    Y_c : numeric or array_like
        Absolute adapting field luminance in :math:`cd/m^2`.

    Returns
    -------
    ndarray
        Converted *CIE XYZ* tristimulus values in trolands.

    Examples
    --------
    >>> XYZ = np.array([19.01, 20.00, 21.78])
    >>> Y_0 = 318.31
    >>> luminance_to_retinal_illuminance(XYZ, Y_0)  # doctest: +ELLIPSIS
    array([ 479.4445924...,  499.3174313...,  534.5631673...])
    """

    XYZ = as_float_array(XYZ)
    Y_c = as_float_array(Y_c)

    return 18 * spow(Y_c[..., np.newaxis] * XYZ / 100, 0.8)
コード例 #5
0
ファイル: cct.py プロジェクト: colour-science/colour
def CCT_to_uv_Robertson1968(CCT_D_uv):
    """
    Returns the *CIE UCS* colourspace *uv* chromaticity coordinates from given
    correlated colour temperature :math:`T_{cp}` and :math:`\\Delta_{uv}` using
    *Roberston (1968)* method.

    Parameters
    ----------
    CCT_D_uv : ndarray
        Correlated colour temperature :math:`T_{cp}`, :math:`\\Delta_{uv}`.

    Returns
    -------
    ndarray
        *CIE UCS* colourspace *uv* chromaticity coordinates.

    References
    ----------
    :cite:`AdobeSystems2013a`, :cite:`Wyszecki2000y`

    Examples
    --------
    >>> CCT_D_uv = np.array([6500.0081378199056, 0.008333331244225])
    >>> CCT_to_uv_Robertson1968(CCT_D_uv)  # doctest: +ELLIPSIS
    array([ 0.1937413...,  0.3152210...])
    """

    CCT_D_uv = as_float_array(CCT_D_uv)

    uv = [_CCT_to_uv_Robertson1968(a) for a in np.reshape(CCT_D_uv, (-1, 2))]

    return as_float_array(uv).reshape(CCT_D_uv.shape)
コード例 #6
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def chroma_components(L_star_P, S_RG, S_YB):
    """
    Returns the *chroma* components :math:`C_{RG}` and :math:`C_{YB}`.

    Parameters
    ----------
    L_star_P : numeric or array_like
        *Achromatic Lightness* correlate :math:`L_p^\\star`.
    S_RG : numeric or array_like
        *Saturation* component :math:`S_{RG}`.
    S_YB : numeric or array_like
        *Saturation* component :math:`S_{YB}`.

    Returns
    -------
    ndarray
        *Chroma* components :math:`C_{RG}` and :math:`C_{YB}`.

    Examples
    --------
    >>> L_star_P = 49.99988297570504
    >>> S_RG = -0.002885271638197
    >>> S_YB = -0.013039632941332
    >>> chroma_components(L_star_P, S_RG, S_YB)  # doctest: +ELLIPSIS
    array([-0.00288527, -0.01303961])
    """

    L_star_P = as_float_array(L_star_P)
    S_RG = as_float_array(S_RG)
    S_YB = as_float_array(S_YB)

    C_RG = spow(L_star_P / 50, 0.7) * S_RG
    C_YB = spow(L_star_P / 50, 0.7) * S_YB

    return tstack([C_RG, C_YB])
コード例 #7
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def colourfulness_components(C_RG, C_YB, B_rw):
    """
    Returns the *colourfulness* components :math:`M_{RG}` and :math:`M_{YB}`.

    Parameters
    ----------
    C_RG : numeric or array_like
        *Chroma* component :math:`C_{RG}`.
    C_YB : numeric or array_like
        *Chroma* component :math:`C_{YB}`.
    B_rw : numeric or array_like
        Ideal white *brightness* correlate :math:`B_{rw}`.

    Returns
    -------
    numeric or ndarray
        *Colourfulness* components :math:`M_{RG}` and :math:`M_{YB}`.

    Examples
    --------
    >>> C_RG = -0.002885271638197
    >>> C_YB = -0.013039632941332
    >>> B_rw = 125.24353925846037
    >>> colourfulness_components(C_RG, C_YB, B_rw)  # doctest: +ELLIPSIS
    (-0.0036136..., -0.0163312...)
    """

    C_RG = as_float_array(C_RG)
    C_YB = as_float_array(C_YB)
    B_rw = as_float_array(B_rw)

    M_RG = C_RG * B_rw / 100
    M_YB = C_YB * B_rw / 100

    return M_RG, M_YB
コード例 #8
0
ファイル: ciecam02.py プロジェクト: colour-science/colour
def saturation_correlate(M, Q):
    """
    Returns the *saturation* correlate :math:`s`.

    Parameters
    ----------
    M : numeric or array_like
        *Colourfulness* correlate :math:`M`.
    Q : numeric or array_like
        *Brightness* correlate :math:`C`.

    Returns
    -------
    numeric or ndarray
        *Saturation* correlate :math:`s`.

    Examples
    --------
    >>> M = 0.108842175669
    >>> Q = 195.371325966
    >>> saturation_correlate(M, Q)  # doctest: +ELLIPSIS
    2.3603053...
    """

    M = as_float_array(M)
    Q = as_float_array(Q)

    s = 100 * spow(M / Q, 0.5)

    return s
コード例 #9
0
ファイル: ciecam02.py プロジェクト: colour-science/colour
def viewing_condition_dependent_parameters(Y_b, Y_w, L_A):
    """
    Returns the viewing condition dependent parameters.

    Parameters
    ----------
    Y_b : numeric or array_like
        Adapting field *Y* tristimulus value :math:`Y_b`.
    Y_w : numeric or array_like
        Whitepoint *Y* tristimulus value :math:`Y_w`.
    L_A : numeric or array_like
        Adapting field *luminance* :math:`L_A` in :math:`cd/m^2`.

    Returns
    -------
    ndarray
        Viewing condition dependent parameters.

    Examples
    --------
    >>> viewing_condition_dependent_parameters(20.0, 100.0, 318.31)
    ... # doctest: +ELLIPSIS
    array([ 0.2...,  1.1675444...,  1.000304  ,  1.000304  ,  1.9272136...])
    """

    Y_b = as_float_array(Y_b)
    Y_w = as_float_array(Y_w)

    n = Y_b / Y_w

    F_L = luminance_level_adaptation_factor(L_A)
    N_bb, N_cb = tsplit(chromatic_induction_factors(n))
    z = base_exponential_non_linearity(n)

    return tstack([n, F_L, N_bb, N_cb, z])
コード例 #10
0
ファイル: llab.py プロジェクト: colour-science/colour
def saturation_correlate(Ch_L, L_L):
    """
    Returns the correlate of *saturation* :math:`S_L`.

    Parameters
    ----------
    Ch_L : numeric or array_like
        Correlate of *chroma* :math:`Ch_L`.
    L_L : numeric or array_like
        Correlate of *Lightness* :math:`L_L`.

    Returns
    -------
    numeric or ndarray
        Correlate of *saturation* :math:`S_L`.

    Examples
    --------
    >>> Ch_L = 0.008650662051714
    >>> L_L = 37.368047493928195
    >>> saturation_correlate(Ch_L, L_L)  # doctest: +ELLIPSIS
    0.0002314...
    """

    Ch_L = as_float_array(Ch_L)
    L_L = as_float_array(L_L)

    S_L = Ch_L / L_L

    return S_L
コード例 #11
0
ファイル: ciecam02.py プロジェクト: colour-science/colour
def colourfulness_correlate(C, F_L):
    """
    Returns the *colourfulness* correlate :math:`M`.

    Parameters
    ----------
    C : numeric or array_like
        *Chroma* correlate :math:`C`.
    F_L : numeric or array_like
        *Luminance* level adaptation factor :math:`F_L`.

    Returns
    -------
    numeric or ndarray
        *Colourfulness* correlate :math:`M`.

    Examples
    --------
    >>> C = 0.104707757171
    >>> F_L = 1.16754446415
    >>> colourfulness_correlate(C, F_L)  # doctest: +ELLIPSIS
    0.1088421...
    """

    C = as_float_array(C)
    F_L = as_float_array(F_L)

    M = C * spow(F_L, 0.25)

    return M
コード例 #12
0
ファイル: llab.py プロジェクト: colour-science/colour
def chroma_correlate(a, b):
    """
    Returns the correlate of *chroma* :math:`Ch_L`.

    Parameters
    ----------
    a : numeric or array_like
        Opponent colour dimension :math:`a`.
    b : numeric or array_like
        Opponent colour dimension :math:`b`.

    Returns
    -------
    numeric or ndarray
        Correlate of *chroma* :math:`Ch_L`.

    Examples
    --------
    >>> a = -4.49864756e-03
    >>> b = -5.26046353e-03
    >>> chroma_correlate(a, b)  # doctest: +ELLIPSIS
    0.0086506...
    """

    a = as_float_array(a)
    b = as_float_array(b)

    c = spow(a ** 2 + b ** 2, 0.5)
    Ch_L = 25 * np.log(1 + 0.05 * c)

    return Ch_L
コード例 #13
0
ファイル: llab.py プロジェクト: colour-science/colour
def hue_angle(a, b):
    """
    Returns the *hue* angle :math:`h_L` in degrees.

    Parameters
    ----------
    a : numeric or array_like
        Opponent colour dimension :math:`a`.
    b : numeric or array_like
        Opponent colour dimension :math:`b`.

    Returns
    -------
    numeric or ndarray
        *Hue* angle :math:`h_L` in degrees.

    Examples
    --------
    >>> hue_angle(-4.49864756e-03, -5.26046353e-03)  # doctest: +ELLIPSIS
    229.4635727...
    """

    a = as_float_array(a)
    b = as_float_array(b)

    h_L = np.degrees(np.arctan2(b, a)) % 360

    return h_L
コード例 #14
0
ファイル: llab.py プロジェクト: colour-science/colour
def f(x, F_S):
    """
    Defines the nonlinear response function of the *:math:`LLAB(l:c)`* colour
    appearance model used to model the nonlinear behaviour of various visual
    responses.

    Parameters
    ----------
    x : numeric or array_like or array_like
        Visual response variable :math:`x`.
    F_S : numeric or array_like
        Surround induction factor :math:`F_S`.

    Returns
    -------
    numeric or array_like
        Modeled visual response variable :math:`x`.

    Examples
    --------
    >>> x = np.array([0.23350512, 0.23351103, 0.23355179])
    >>> f(0.200009186234000, 3)  # doctest: +ELLIPSIS
    array(0.5848125...)
    """

    x = as_float_array(x)
    F_S = as_float_array(F_S)

    x_m = np.where(
        x > 0.008856,
        spow(x, 1 / F_S),
        ((spow(0.008856, 1 / F_S) - (16 / 116)) / 0.008856) * x + (16 / 116),
    )

    return x_m
コード例 #15
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def hue_angle(p, t):
    """
    Returns the *hue* angle :math:`h` in degrees.

    Parameters
    ----------
    p : numeric or array_like
        Protanopic response :math:`p`.
    t : numeric or array_like
        Tritanopic response :math:`t`.

    Returns
    -------
    numeric or ndarray
        *Hue* angle :math:`h` in degrees.

    Examples
    --------
    >>> p = -8.002142682085493e-05
    >>> t = -0.000017703650669
    >>> hue_angle(p, t)  # doctest: +ELLIPSIS
    257.5250300...
    """

    p = as_float_array(p)
    t = as_float_array(t)

    h_L = np.degrees(np.arctan2(p, t)) % 360

    return h_L
コード例 #16
0
ファイル: ciecam02.py プロジェクト: colour-science/colour
def degree_of_adaptation(F, L_A):
    """
    Returns the degree of adaptation :math:`D` from given surround maximum
    degree of adaptation :math:`F` and Adapting field *luminance* :math:`L_A`
    in :math:`cd/m^2`.

    Parameters
    ----------
    F : numeric or array_like
        Surround maximum degree of adaptation :math:`F`.
    L_A : numeric or array_like
        Adapting field *luminance* :math:`L_A` in :math:`cd/m^2`.

    Returns
    -------
    numeric or ndarray
        Degree of adaptation :math:`D`.

    Examples
    --------
    >>> degree_of_adaptation(1.0, 318.31)  # doctest: +ELLIPSIS
    0.9944687...
    """

    F = as_float_array(F)
    L_A = as_float_array(L_A)

    D = F * (1 - (1 / 3.6) * np.exp((-L_A - 42) / 92))

    return D
コード例 #17
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def saturation_correlate(S_RG, S_YB):
    """
    Returns the correlate of *saturation* :math:`S`.

    Parameters
    ----------
    S_RG : numeric or array_like
        *Saturation* component :math:`S_{RG}`.
    S_YB : numeric or array_like
        *Saturation* component :math:`S_{YB}`.

    Returns
    -------
    numeric or ndarray
        Correlate of *saturation* :math:`S`.

    Examples
    --------
    >>> S_RG = -0.002885271638197
    >>> S_YB = -0.013039632941332
    >>> saturation_correlate(S_RG, S_YB)  # doctest: +ELLIPSIS
    0.0133550...
    """

    S_RG = as_float_array(S_RG)
    S_YB = as_float_array(S_YB)

    S = np.hypot(S_RG, S_YB)

    return S
コード例 #18
0
ファイル: ciecam02.py プロジェクト: colour-science/colour
def post_adaptation_non_linear_response_compression_reverse(RGB, F_L):
    """
    Returns given *CMCCAT2000* transform sharpened *RGB* array without post
    adaptation non linear response compression.

    Parameters
    ----------
    RGB : array_like
        *CMCCAT2000* transform sharpened *RGB* array.
    F_L : array_like
        *Luminance* level adaptation factor :math:`F_L`.

    Returns
    -------
    ndarray
        Uncompressed *CMCCAT2000* transform sharpened *RGB* array.

    Examples
    --------
    >>> RGB = np.array([7.94632020, 7.94711528, 7.94899595])
    >>> F_L = 1.16754446415
    >>> post_adaptation_non_linear_response_compression_reverse(RGB, F_L)
    ... # doctest: +ELLIPSIS
    array([ 19.9969397...,  20.0018612...,  20.0135052...])
    """

    RGB = as_float_array(RGB)
    F_L = as_float_array(F_L)

    RGB_p = ((np.sign(RGB - 0.1) * (100 / F_L[..., np.newaxis]) * spow(
        (27.13 * np.absolute(RGB - 0.1)) / (400 - np.absolute(RGB - 0.1)),
        1 / 0.42)))

    return RGB_p
コード例 #19
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def chroma_correlate(L_star_P, S):
    """
    Returns the correlate of *chroma* :math:`C`.

    Parameters
    ----------
    L_star_P : numeric or array_like
        *Achromatic Lightness* correlate :math:`L_p^\\star`.
    S : numeric or array_like
        Correlate of *saturation* :math:`S`.

    Returns
    -------
    numeric or ndarray
        Correlate of *chroma* :math:`C`.

    Examples
    --------
    >>> L_star_P = 49.99988297570504
    >>> S = 0.013355029751778
    >>> chroma_correlate(L_star_P, S)  # doctest: +ELLIPSIS
    0.0133550...
    """

    L_star_P = as_float_array(L_star_P)
    S = as_float_array(S)

    C = spow(L_star_P / 50, 0.7) * S

    return C
コード例 #20
0
ファイル: ciecam02.py プロジェクト: colour-science/colour
def hue_angle(a, b):
    """
    Returns the *hue* angle :math:`h` in degrees.

    Parameters
    ----------
    a : numeric or array_like
        Opponent colour dimension :math:`a`.
    b : numeric or array_like
        Opponent colour dimension :math:`b`.

    Returns
    -------
    numeric or ndarray
        *Hue* angle :math:`h` in degrees.

    Examples
    --------
    >>> a = -0.000624112068243
    >>> b = -0.000506270106773
    >>> hue_angle(a, b)  # doctest: +ELLIPSIS
    219.0484326...
    """

    a = as_float_array(a)
    b = as_float_array(b)

    h = np.degrees(np.arctan2(b, a)) % 360

    return h
コード例 #21
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def colourfulness_correlate(C, B_rw):
    """
    Returns the correlate of *colourfulness* :math:`M`.

    Parameters
    ----------
    C : numeric or array_like
        Correlate of *chroma* :math:`C`.
    B_rw : numeric or array_like
        Ideal white *brightness* correlate :math:`B_{rw}`.

    Returns
    -------
    numeric or ndarray
        Correlate of *colourfulness* :math:`M`.

    Examples
    --------
    >>> C = 0.013355007871689
    >>> B_rw = 125.24353925846037
    >>> colourfulness_correlate(C, B_rw)  # doctest: +ELLIPSIS
    0.0167262...
    """

    C = as_float_array(C)
    B_rw = as_float_array(B_rw)

    M = C * B_rw / 100

    return M
コード例 #22
0
ファイル: nayatani95.py プロジェクト: colour-science/colour
def illuminance_to_luminance(E, Y_f):
    """
    Converts given *illuminance* :math:`E` value in lux to *luminance* in
    :math:`cd/m^2`.

    Parameters
    ----------
    E : numeric or array_like
        *Illuminance* :math:`E` in lux.
    Y_f : numeric or array_like
        *Luminance* factor :math:`Y_f` in :math:`cd/m^2`.

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

    Examples
    --------
    >>> illuminance_to_luminance(5000.0, 20.0)  # doctest: +ELLIPSIS
    318.3098861...
    """

    E = as_float_array(E)
    Y_f = as_float_array(Y_f)

    return Y_f * E / (100 * np.pi)
コード例 #23
0
ファイル: cct.py プロジェクト: colour-science/colour
def uv_to_CCT_Robertson1968(uv):
    """
    Returns the correlated colour temperature :math:`T_{cp}` and
    :math:`\\Delta_{uv}` from given *CIE UCS* colourspace *uv* chromaticity
    coordinates using *Roberston (1968)* method.

    Parameters
    ----------
    uv : array_like
        *CIE UCS* colourspace *uv* chromaticity coordinates.

    Returns
    -------
    ndarray
        Correlated colour temperature :math:`T_{cp}`, :math:`\\Delta_{uv}`.

    References
    ----------
    :cite:`AdobeSystems2013`, :cite:`Wyszecki2000y`

    Examples
    --------
    >>> uv = np.array([0.193741375998230, 0.315221043940594])
    >>> uv_to_CCT_Robertson1968(uv)  # doctest: +ELLIPSIS
    array([  6.5000162...e+03,   8.3333289...e-03])
    """

    uv = as_float_array(uv)

    CCT_D_uv = [_uv_to_CCT_Robertson1968(a) for a in np.reshape(uv, (-1, 2))]

    return as_float_array(CCT_D_uv).reshape(uv.shape)
コード例 #24
0
ファイル: metrics.py プロジェクト: colour-science/colour
def metric_mse(a, b):
    """
    Computes the mean squared error (MSE) or mean squared deviation (MSD)
    between given *array_like* :math:`a` and :math:`b` variables.

    Parameters
    ----------
    a : array_like
        :math:`a` variable.
    b : array_like
        :math:`b` variable.

    Returns
    -------
    float
        Mean squared error (MSE).

    References
    ----------
    :cite:`Wikipedia2003c`

    Examples
    --------
    >>> a = np.array([0.48222001, 0.31654775, 0.22070353])
    >>> b = a * 0.9
    >>> metric_mse(a, b)  # doctest: +ELLIPSIS
    0.0012714...
    """

    return np.mean((as_float_array(a) - as_float_array(b)) ** 2)
コード例 #25
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))
コード例 #26
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)))
コード例 #27
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
コード例 #28
0
ファイル: rayleigh.py プロジェクト: colour-science/colour
def air_refraction_index_Bodhaine1999(
        wavelength, CO2_concentration=STANDARD_CO2_CONCENTRATION):
    """
    Returns the air refraction index :math:`n_s` from given wavelength
    :math:`\\lambda` in micrometers (:math:`\\mu m`) using
    *Bodhaine, Wood, Dutton and Slusser (1999)* method.

    Parameters
    ----------
    wavelength : numeric or array_like
        Wavelength :math:`\\lambda` in micrometers (:math:`\\mu m`).
    CO2_concentration : numeric or array_like
        :math:`CO_2` concentration in parts per million (ppm).

    Returns
    -------
    numeric or ndarray
        Air refraction index :math:`n_s`.

    Examples
    --------
    >>> air_refraction_index_Bodhaine1999(0.555)  # doctest: +ELLIPSIS
    1.0002777...
    """

    wl = as_float_array(wavelength)
    CO2_c = as_float_array(CO2_concentration)

    n = ((1 + 0.54 * ((CO2_c * 1e-6) - 300e-6)) *
         (air_refraction_index_Peck1972(wl) - 1) + 1)

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

        np.testing.assert_equal(as_float_array([1, 2, 3]), np.array([1, 2, 3]))

        self.assertEqual(as_float_array([1, 2, 3]).dtype, DEFAULT_FLOAT_DTYPE)
コード例 #30
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
コード例 #31
0
ファイル: cie1994.py プロジェクト: yixw/colour
def chromatic_adaptation_CIE1994(XYZ_1, xy_o1, xy_o2, Y_o, E_o1, E_o2, n=1):
    """
    Adapts given stimulus *CIE XYZ_1* tristimulus values from test viewing
    conditions to reference viewing conditions using *CIE 1994* chromatic
    adaptation model.

    Parameters
    ----------
    XYZ_1 : array_like
        *CIE XYZ* tristimulus values of test sample / stimulus.
    xy_o1 : array_like
        Chromaticity coordinates :math:`x_{o1}` and :math:`y_{o1}` of test
        illuminant and background.
    xy_o2 : array_like
        Chromaticity coordinates :math:`x_{o2}` and :math:`y_{o2}` of reference
        illuminant and background.
    Y_o : numeric
        Luminance factor :math:`Y_o` of achromatic background as percentage
        normalised to domain [18, 100] in **'Reference'** domain-range scale.
    E_o1 : numeric
        Test illuminance :math:`E_{o1}` in :math:`cd/m^2`.
    E_o2 : numeric
        Reference illuminance :math:`E_{o2}` in :math:`cd/m^2`.
    n : numeric, optional
        Noise component in fundamental primary system.

    Returns
    -------
    ndarray
        Adapted *CIE XYZ_2* tristimulus values of test stimulus.

    Notes
    -----

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

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

    References
    ----------
    :cite:`CIETC1-321994b`

    Examples
    --------
    >>> XYZ_1 = np.array([28.00, 21.26, 5.27])
    >>> xy_o1 = np.array([0.4476, 0.4074])
    >>> xy_o2 = np.array([0.3127, 0.3290])
    >>> Y_o = 20
    >>> E_o1 = 1000
    >>> E_o2 = 1000
    >>> chromatic_adaptation_CIE1994(XYZ_1, xy_o1, xy_o2, Y_o, E_o1, E_o2)
    ... # doctest: +ELLIPSIS
    array([ 24.0337952...,  21.1562121...,  17.6430119...])
    """

    XYZ_1 = to_domain_100(XYZ_1)
    Y_o = to_domain_100(Y_o)
    E_o1 = as_float_array(E_o1)
    E_o2 = as_float_array(E_o2)

    if np.any(Y_o < 18) or np.any(Y_o > 100):
        usage_warning(('"Y_o" luminance factor must be in [18, 100] domain, '
                       'unpredictable results may occur!'))

    RGB_1 = XYZ_to_RGB_CIE1994(XYZ_1)

    xez_1 = intermediate_values(xy_o1)
    xez_2 = intermediate_values(xy_o2)

    RGB_o1 = effective_adapting_responses(xez_1, Y_o, E_o1)
    RGB_o2 = effective_adapting_responses(xez_2, Y_o, E_o2)

    bRGB_o1 = exponential_factors(RGB_o1)
    bRGB_o2 = exponential_factors(RGB_o2)

    K = K_coefficient(xez_1, xez_2, bRGB_o1, bRGB_o2, Y_o, n)

    RGB_2 = corresponding_colour(RGB_1, xez_1, xez_2, bRGB_o1, bRGB_o2, Y_o, K,
                                 n)
    XYZ_2 = RGB_to_XYZ_CIE1994(RGB_2)

    return from_range_100(XYZ_2)
コード例 #32
0
ファイル: cam16.py プロジェクト: zachlewis/colour
def CAM16_to_XYZ(CAM16_specification,
                 XYZ_w,
                 L_A,
                 Y_b,
                 surround=CAM16_VIEWING_CONDITIONS['Average'],
                 discount_illuminant=False):
    """
    Converts from *CAM16* specification to *CIE XYZ* tristimulus values.

    This is the *inverse* implementation.

    Parameters
    ----------
    CAM16_specification : CAM16_Specification
        *CAM16* colour appearance model specification. Correlate of
        *Lightness* :math:`J`, correlate of *chroma* :math:`C` or correlate of
        *colourfulness* :math:`M` and *hue* angle :math:`h` in degrees must be
        specified, e.g. :math:`JCh` or :math:`JMh`.
    XYZ_w : array_like
        *CIE XYZ* tristimulus values of reference white.
    L_A : numeric or array_like
        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 : numeric or array_like
        Relative luminance of background :math:`Y_b` in :math:`cd/m^2`.
    surround : CAM16_InductionFactors, optional
        Surround viewing conditions.
    discount_illuminant : bool, optional
        Discount the illuminant.

    Returns
    -------
    XYZ : ndarray
        *CIE XYZ* tristimulus values.

    Raises
    ------
    ValueError
        If neither *C* or *M* correlates have been defined in the
        ``CAM16_specification`` argument.

    Notes
    -----

    +---------------------------+-----------------------+---------------+
    | **Domain**                | **Scale - Reference** | **Scale - 1** |
    +===========================+=======================+===============+
    | ``CAM16_specification.J`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.C`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.h`` | [0, 360]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.s`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.Q`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.M`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.H`` | [0, 360]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``XYZ_w``                 | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+

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

    -   ``CAM16_specification`` can also be passed as a compatible argument
        to :func:`colour.utilities.as_namedtuple` definition.

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

    Examples
    --------
    >>> specification = CAM16_Specification(J=41.731207905126638,
    ...                                     C=0.103355738709070,
    ...                                     h=217.067959767393010)
    >>> XYZ_w = np.array([95.05, 100.00, 108.88])
    >>> L_A = 318.31
    >>> Y_b = 20.0
    >>> CAM16_to_XYZ(specification, XYZ_w, L_A, Y_b)  # doctest: +ELLIPSIS
    array([ 19.01...,  20...  ,  21.78...])
    """

    J, C, h, _s, _Q, M, _H, _HC = as_namedtuple(CAM16_specification,
                                                CAM16_Specification)
    J = to_domain_100(J)
    C = to_domain_100(C) if C is not None else C
    h = to_domain_degrees(h)
    M = to_domain_100(M) if M is not None else M
    L_A = as_float_array(L_A)
    XYZ_w = to_domain_100(XYZ_w)
    _X_w, Y_w, _Z_w = tsplit(XYZ_w)

    # Step 0
    # Converting *CIE XYZ* tristimulus values to sharpened *RGB* values.
    RGB_w = dot_vector(M_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 np.ones(L_A.shape))

    n, F_L, N_bb, N_cb, z = tsplit(
        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
    if C is None and M is not None:
        C = M / spow(F_L, 0.25)
    elif C is None:
        raise ValueError('Either "C" or "M" correlate must be defined in '
                         'the "CAM16_specification" argument!')

    # Step 2
    # Computing temporary magnitude quantity :math:`t`.
    t = temporary_magnitude_quantity_inverse(C, J, n)

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

    # Computing achromatic response :math:`A` for the stimulus.
    A = achromatic_response_inverse(A_w, J, surround.c, z)

    # Computing *P_1* to *P_3*.
    P_n = P(surround.N_c, N_cb, e_t, t, A, N_bb)
    _P_1, P_2, _P_3 = tsplit(P_n)

    # Step 3
    # Computing opponent colour dimensions :math:`a` and :math:`b`.
    a, b = tsplit(opponent_colour_dimensions_inverse(P_n, h))

    # Step 4
    # Computing post-adaptation non linear response compression matrix.
    RGB_a = post_adaptation_non_linear_response_compression_matrix(P_2, a, b)

    # Step 5
    # Applying inverse post-adaptation non linear response compression.
    RGB_c = post_adaptation_non_linear_response_compression_inverse(RGB_a, F_L)

    # Step 6
    RGB = RGB_c / D_RGB

    # Step 7
    XYZ = dot_vector(M_16_INVERSE, RGB)

    return from_range_100(XYZ)
コード例 #33
0
ファイル: cie1994.py プロジェクト: yixw/colour
def corresponding_colour(RGB_1, xez_1, xez_2, bRGB_o1, bRGB_o2, Y_o, K, n=1):
    """
    Computes the corresponding colour cone responses of given test sample cone
    responses :math:`RGB_1`.

    Parameters
    ----------
    RGB_1: array_like
        Test sample cone responses :math:`RGB_1`.
    xez_1: array_like
        Intermediate values :math:`\\xi_1`, :math:`\\eta_1`, :math:`\\zeta_1`
        for the test illuminant and background.
    xez_2: array_like
        Intermediate values :math:`\\xi_2`, :math:`\\eta_2`, :math:`\\zeta_2`
        for the reference illuminant and background.
    bRGB_o1: array_like
        Chromatic adaptation exponential factors :math:`\\beta_1(R_{o1})`,
        :math:`\\beta_1(G_{o1})` and :math:`\\beta_2(B_{o1})` of test sample.
    bRGB_o2: array_like
        Chromatic adaptation exponential factors :math:`\\beta_1(R_{o2})`,
        :math:`\\beta_1(G_{o2})` and :math:`\\beta_2(B_{o2})` of reference
        sample.
    Y_o : numeric or array_like
        Luminance factor :math:`Y_o` of achromatic background as percentage
        normalised to domain [18, 100] in **'Reference'** domain-range scale.
    K : numeric or array_like
        Coefficient :math:`K`.
    n : numeric or array_like, optional
        Noise component in fundamental primary system.

    Returns
    -------
    ndarray
        Corresponding colour cone responses of given test sample cone
        responses.

    Examples
    --------
    >>> RGB_1 = np.array([25.82442730, 18.67914220, 4.83901940])
    >>> xez_1 = np.array([1.11857195, 0.93295530, 0.32680879])
    >>> xez_2 = np.array([1.00000372, 1.00000176, 0.99999461])
    >>> bRGB_o1 = np.array([3.74852518, 3.63920879, 2.78924811])
    >>> bRGB_o2 = np.array([3.68102374, 3.68102256, 3.56557351])
    >>> Y_o = 20
    >>> K = 1.0
    >>> corresponding_colour(RGB_1, xez_1, xez_2, bRGB_o1, bRGB_o2, Y_o, K)
    ... # doctest: +ELLIPSIS
    array([ 23.1636901...,  20.0211948...,  16.2001664...])
    """

    R_1, G_1, B_1 = tsplit(RGB_1)
    xi_1, eta_1, zeta_1 = tsplit(xez_1)
    xi_2, eta_2, zeta_2 = tsplit(xez_2)
    bR_o1, bG_o1, bB_o1 = tsplit(bRGB_o1)
    bR_o2, bG_o2, bB_o2 = tsplit(bRGB_o2)
    Y_o = as_float_array(Y_o)
    K = as_float_array(K)

    def RGB_c(x_1, x_2, y_1, y_2, z):
        """
        Computes the corresponding colour cone responses component.
        """

        return ((Y_o * x_2 + n) * spow(K, 1 / y_2) * spow(
            (z + n) / (Y_o * x_1 + n), y_1 / y_2) - n)

    R_2 = RGB_c(xi_1, xi_2, bR_o1, bR_o2, R_1)
    G_2 = RGB_c(eta_1, eta_2, bG_o1, bG_o2, G_1)
    B_2 = RGB_c(zeta_1, zeta_2, bB_o1, bB_o2, B_1)

    RGB_2 = tstack([R_2, G_2, B_2])

    return RGB_2
コード例 #34
0
def logarithmic_function_quasilog(x,
                                  style='linToLog',
                                  base=2,
                                  log_side_slope=1,
                                  lin_side_slope=1,
                                  log_side_offset=0,
                                  lin_side_offset=0):
    """
    Defines the quasilog logarithmic function.

    Parameters
    ----------
    x : numeric
        Linear/non-linear data to undergo encoding/decoding.
    style : unicode, optional
        **{'linToLog', 'logToLin'}**,
        Defines the behaviour for the logarithmic function to operate:

        -   *linToLog*: Applies a logarithm to convert linear data to
            logarithmic data.
        -   *logToLin*: Applies an anti-logarithm to convert logarithmic
            data to linear data.
    base : numeric, optional
        Logarithmic base used for the conversion.
    log_side_slope : numeric, optional
        Slope (or gain) applied to the log side of the logarithmic function.
        The default value is 1.
    lin_side_slope : numeric, optional
        Slope of the linear side of the logarithmic function. The default value
        is 1.
    log_side_offset : numeric, optional
        Offset applied to the log side of the logarithmic function. The default
        value is 0.
    lin_side_offset : numeric, optional
        Offset applied to the linear side of the logarithmic function. The
        default value is 0.

    Returns
    -------
    numeric or ndarray
        Encoded/Decoded data.

    Raises
    ------
    ValueError
        If the *style* is not defined.

    Examples
    --------
    >>> logarithmic_function_quasilog(  # doctest: +ELLIPSIS
    ...    0.18, 'linToLog')
    -2.4739311...
    >>> logarithmic_function_quasilog(  # doctest: +ELLIPSIS
    ...    -2.473931188332412, 'logToLin')
    0.18000000...
    """

    x = as_float_array(x)

    style = style.lower()
    if style == 'lintolog':
        return as_float(
            (log_side_slope *
             (np.log(np.maximum(lin_side_slope * x + lin_side_offset, FLT_MIN))
              / np.log(base)) + log_side_offset))
    elif style == 'logtolin':
        return as_float(((base**(
            (x - log_side_offset) / log_side_slope) - lin_side_offset) /
                         lin_side_slope))
    else:
        raise ValueError(
            'Undefined style used: "{0}", must be one of the following: '
            '"{1}".'.format(style, ', '.join(['linToLog', 'logToLin'])))
コード例 #35
0
def logarithmic_function_camera(
    x: FloatingOrArrayLike,
    style: Union[Literal["cameraLinToLog", "cameraLogToLin"],
                 str] = "cameraLinToLog",
    base: Integer = 2,
    log_side_slope: Floating = 1,
    lin_side_slope: Floating = 1,
    log_side_offset: Floating = 0,
    lin_side_offset: Floating = 0,
    lin_side_break: Floating = 0.005,
    linear_slope: Optional[Floating] = None,
) -> FloatingOrNDArray:
    """
    Define the camera logarithmic function.

    Parameters
    ----------
    x
        Linear/non-linear data to undergo encoding/decoding.
    style
        Defines the behaviour for the logarithmic function to operate:

        -   *cameraLinToLog*: Applies a piece-wise function with logarithmic
            and linear segments on linear values, converting them to non-linear
            values.
        -   *cameraLogToLin*: Applies a piece-wise function with logarithmic
            and linear segments on non-linear values, converting them to linear
            values.
    base
        Logarithmic base used for the conversion.
    log_side_slope
        Slope (or gain) applied to the log side of the logarithmic segment. The
        default value is 1.
    lin_side_slope
        Slope of the linear side of the logarithmic segment. The default value
        is 1.
    log_side_offset
        Offset applied to the log side of the logarithmic segment. The default
        value is 0.
    lin_side_offset
        Offset applied to the linear side of the logarithmic segment. The
        default value is 0.
    lin_side_break
        Break-point, defined in linear space, at which the piece-wise function
        transitions between the logarithmic and linear segments.
    linear_slope
        Slope of the linear portion of the curve. The default value is *None*.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Encoded/Decoded data.

    Examples
    --------
    >>> logarithmic_function_camera(  # doctest: +ELLIPSIS
    ...    0.18, 'cameraLinToLog')
    -2.4739311...
    >>> logarithmic_function_camera(  # doctest: +ELLIPSIS
    ...    -2.4739311883324122, 'cameraLogToLin')
    0.1800000...
    """

    x = as_float_array(x)
    style = validate_method(
        style,
        ["cameraLinToLog", "cameraLogToLin"],
        '"{0}" style is invalid, it must be one of {1}!',
    )

    log_side_break = (
        log_side_slope *
        (np.log(lin_side_slope * lin_side_break + lin_side_offset) /
         np.log(base)) + log_side_offset)

    linear_slope = cast(
        Floating,
        optional(
            linear_slope,
            (log_side_slope *
             (lin_side_slope /
              ((lin_side_slope * lin_side_break + lin_side_offset) *
               np.log(base)))),
        ),
    )

    linear_offset = log_side_break - linear_slope * lin_side_break

    if style == "cameralintolog":
        return as_float(
            np.where(
                x <= lin_side_break,
                linear_slope * x + linear_offset,
                logarithmic_function_quasilog(
                    x,
                    "linToLog",
                    base,
                    log_side_slope,
                    lin_side_slope,
                    log_side_offset,
                    lin_side_offset,
                ),
            ))
    else:  # style == 'cameralogtolin'
        return as_float(
            np.where(
                x <= log_side_break,
                (x - linear_offset) / linear_slope,
                logarithmic_function_quasilog(
                    x,
                    "logToLin",
                    base,
                    log_side_slope,
                    lin_side_slope,
                    log_side_offset,
                    lin_side_offset,
                ),
            ))
コード例 #36
0
def degrees_of_adaptation(LMS, Y_n, v=1 / 3, discount_illuminant=False):
    """
    Computes the degrees of adaptation :math:`p_L`, :math:`p_M` and
    :math:`p_S`.

    Parameters
    ----------
    LMS : array_like
        Cone responses.
    Y_n : numeric or array_like
        Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`.
    v : numeric or array_like, optional
        Exponent :math:`v`.
    discount_illuminant : bool, optional
        Truth value indicating if the illuminant should be discounted.

    Returns
    -------
    ndarray
        Degrees of adaptation :math:`p_L`, :math:`p_M` and :math:`p_S`.

    Examples
    --------
    >>> LMS = np.array([20.00052060, 19.99978300, 19.99883160])
    >>> Y_n = 31.83
    >>> degrees_of_adaptation(LMS, Y_n)  # doctest: +ELLIPSIS
    array([ 0.9799324...,  0.9960035...,  1.0233041...])
    >>> degrees_of_adaptation(LMS, Y_n, 1 / 3, True)
    array([ 1.,  1.,  1.])
    """

    LMS = as_float_array(LMS)
    if discount_illuminant:
        return ones(LMS.shape)

    Y_n = as_float_array(Y_n)
    v = as_float_array(v)

    L, M, S = tsplit(LMS)

    # E illuminant.
    LMS_E = vector_dot(CAT_VON_KRIES, ones(LMS.shape))
    L_E, M_E, S_E = tsplit(LMS_E)

    Ye_n = spow(Y_n, v)

    def m_E(x, y):
        """
        Computes the :math:`m_E` term.
        """

        return (3 * (x / y)) / (L / L_E + M / M_E + S / S_E)

    def P_c(x):
        """
        Computes the :math:`P_L`, :math:`P_M` or :math:`P_S` terms.
        """

        return (1 + Ye_n + x) / (1 + Ye_n + 1 / x)

    p_L = P_c(m_E(L, L_E))
    p_M = P_c(m_E(M, M_E))
    p_S = P_c(m_E(S, S_E))

    p_LMS = tstack([p_L, p_M, p_S])

    return p_LMS
コード例 #37
0
ファイル: ycbcr.py プロジェクト: vidakDK/colour
def RGB_to_YCbCr(RGB,
                 K=YCBCR_WEIGHTS['ITU-R BT.709'],
                 in_bits=10,
                 in_legal=False,
                 in_int=False,
                 out_bits=8,
                 out_legal=True,
                 out_int=False,
                 **kwargs):
    """
    Converts an array of *R'G'B'* values to the corresponding *Y'CbCr* colour
    encoding values array.

    Parameters
    ----------
    RGB : array_like
        Input *R'G'B'* array of floats or integer values.
    K : array_like, optional
        Luma weighting coefficients of red and blue. See
        :attr:`colour.YCBCR_WEIGHTS` for presets. Default is
        *(0.2126, 0.0722)*, the weightings for *ITU-R BT.709*.
    in_bits : int, optional
        Bit depth for integer input, or used in the calculation of the
        denominator for legal range float values, i.e. 8-bit means the float
        value for legal white is *235 / 255*. Default is *10*.
    in_legal : bool, optional
        Whether to treat the input values as legal range. Default is *False*.
    in_int : bool, optional
        Whether to treat the input values as ``in_bits`` integer code values.
        Default is *False*.
    out_bits : int, optional
        Bit depth for integer output, or used in the calculation of the
        denominator for legal range float values, i.e. 8-bit means the float
        value for legal white is *235 / 255*. Ignored if ``out_legal`` and
        ``out_int`` are both *False*. Default is *8*.
    out_legal : bool, optional
        Whether to return legal range values. Default is *True*.
    out_int : bool, optional
        Whether to return values as ``out_bits`` integer code values. Default
        is *False*.

    Other Parameters
    ----------------
    in_range : array_like, optional
        Array overriding the computed range such as
        *in_range = (RGB_min, RGB_max)*. If ``in_range`` is undefined,
        *RGB_min* and *RGB_max* will be computed using :func:`colour.CV_range`
        definition.
    out_range : array_like, optional
        Array overriding the computed range such as
        *out_range = (Y_min, Y_max, C_min, C_max)`. If ``out_range`` is
        undefined, *Y_min*, *Y_max*, *C_min* and *C_max* will be computed
        using :func:`colour.models.rgb.ycbcr.YCbCr_ranges` definition.

    Returns
    -------
    ndarray
        *Y'CbCr* colour encoding array of integer or float values.

    Warning
    -------
    For *Recommendation ITU-R BT.2020*, :func:`colour.RGB_to_YCbCr` definition
    is only applicable to the non-constant luminance implementation.
    :func:`colour.RGB_to_YcCbcCrc` definition should be used for the constant
    luminance case as per :cite:`InternationalTelecommunicationUnion2015h`.

    Notes
    -----

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

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

    -   \\* This definition has input and output integer switches, thus the
        domain-range scale information is only given for the floating point
        mode.
    -   The default arguments, ``**{'in_bits': 10, 'in_legal': False,
        'in_int': False, 'out_bits': 8, 'out_legal': True, 'out_int': False}``
        transform a float *R'G'B'* input array normalised to domain [0, 1]
        (``in_bits`` is ignored) to a float *Y'CbCr* output array where *Y'* is
        normalised to range [16 / 255, 235 / 255] and *Cb* and *Cr* are
        normalised to range [16 / 255, 240./255]. The float values are
        calculated based on an [0, 255] integer range, but no 8-bit
        quantisation or clamping are performed.

    References
    ----------
    :cite:`InternationalTelecommunicationUnion2011e`,
    :cite:`InternationalTelecommunicationUnion2015i`,
    :cite:`SocietyofMotionPictureandTelevisionEngineers1999b`,
    :cite:`Wikipedia2004d`

    Examples
    --------
    >>> RGB = np.array([1.0, 1.0, 1.0])
    >>> RGB_to_YCbCr(RGB)  # doctest: +ELLIPSIS
    array([ 0.9215686...,  0.5019607...,  0.5019607...])

    Matching float output of The Foundry Nuke's Colorspace node set to YCbCr:

    >>> RGB_to_YCbCr(RGB,
    ...              out_range=(16 / 255, 235 / 255, 15.5 / 255, 239.5 / 255))
    ... # doctest: +ELLIPSIS
    array([ 0.9215686...,  0.5       ,  0.5       ])

    Matching float output of The Foundry Nuke's Colorspace node set to YPbPr:

    >>> RGB_to_YCbCr(RGB, out_legal=False, out_int=False)
    ... # doctest: +ELLIPSIS
    array([ 1.,  0.,  0.])

    Creating integer code values as per standard 10-bit SDI:

    >>> RGB_to_YCbCr(RGB, out_legal=True, out_bits=10, out_int=True)
    array([940, 512, 512])

    For JFIF JPEG conversion as per ITU-T T.871
    :cite:`InternationalTelecommunicationUnion2011e`:

    >>> RGB = np.array([102, 0, 51])
    >>> RGB_to_YCbCr(RGB, K=YCBCR_WEIGHTS['ITU-R BT.601'], in_range=(0, 255),
    ...              out_range=(0, 255, 0, 256), out_int=True)
    array([ 36, 136, 175])

    Note the use of 256 for the max *Cb / Cr* value, which is required so that
    the *Cb* and *Cr* output is centered about 128. Using 255 centres it
    about 127.5, meaning that there is no integer code value to represent
    achromatic colours. This does however create the possibility of output
    integer codes with value of 256, which cannot be stored in 8-bit integer
    representation. Recommendation ITU-T T.871 specifies these should be
    clamped to 255.

    These JFIF JPEG ranges are also obtained as follows:

    >>> RGB_to_YCbCr(RGB, K=YCBCR_WEIGHTS['ITU-R BT.601'], in_bits=8,
    ...              in_int=True, out_legal=False, out_int=True)
    array([ 36, 136, 175])
    """

    if in_int:
        RGB = as_float_array(RGB)
    else:
        RGB = to_domain_1(RGB)

    Kr, Kb = K
    RGB_min, RGB_max = kwargs.get('in_range',
                                  CV_range(in_bits, in_legal, in_int))
    Y_min, Y_max, C_min, C_max = kwargs.get(
        'out_range', YCbCr_ranges(out_bits, out_legal, out_int))

    RGB_float = RGB.astype(DEFAULT_FLOAT_DTYPE) - RGB_min
    RGB_float *= 1 / (RGB_max - RGB_min)
    R, G, B = tsplit(RGB_float)

    Y = Kr * R + (1 - Kr - Kb) * G + Kb * B
    Cb = 0.5 * (B - Y) / (1 - Kb)
    Cr = 0.5 * (R - Y) / (1 - Kr)
    Y *= Y_max - Y_min
    Y += Y_min
    Cb *= C_max - C_min
    Cr *= C_max - C_min
    Cb += (C_max + C_min) / 2
    Cr += (C_max + C_min) / 2

    YCbCr = tstack([Y, Cb, Cr])
    YCbCr = np.round(YCbCr).astype(
        DEFAULT_INT_DTYPE) if out_int else from_range_1(YCbCr)

    return YCbCr
コード例 #38
0
ファイル: ohno2013.py プロジェクト: colour-science/colour
def uv_to_CCT_Ohno2013(
    uv: ArrayLike,
    cmfs: Optional[MultiSpectralDistributions] = None,
    start: Floating = CCT_MINIMAL,
    end: Floating = CCT_MAXIMAL,
    count: Integer = CCT_SAMPLES,
    iterations: Integer = CCT_CALCULATION_ITERATIONS,
) -> NDArray:
    """
    Return the correlated colour temperature :math:`T_{cp}` and
    :math:`\\Delta_{uv}` from given *CIE UCS* colourspace *uv* chromaticity
    coordinates, colour matching functions and temperature range using
    *Ohno (2013)* method.

    The ``iterations`` parameter defines the calculations' precision: The
    higher its value, the more planckian tables will be generated through
    cascade expansion in order to converge to the exact solution.

    Parameters
    ----------
    uv
        *CIE UCS* colourspace *uv* chromaticity coordinates.
    cmfs
        Standard observer colour matching functions, default to the
        *CIE 1931 2 Degree Standard Observer*.
    start
        Temperature range start in kelvin degrees.
    end
        Temperature range end in kelvin degrees.
    count
        Temperatures count in the planckian tables.
    iterations
        Number of planckian tables to generate.

    Returns
    -------
    :class:`numpy.ndarray`
        Correlated colour temperature :math:`T_{cp}`, :math:`\\Delta_{uv}`.

    References
    ----------
    :cite:`Ohno2014a`

    Examples
    --------
    >>> from pprint import pprint
    >>> from colour import MSDS_CMFS, SPECTRAL_SHAPE_DEFAULT
    >>> cmfs = (
    ...     MSDS_CMFS['CIE 1931 2 Degree Standard Observer'].
    ...     copy().align(SPECTRAL_SHAPE_DEFAULT)
    ... )
    >>> uv = np.array([0.1978, 0.3122])
    >>> uv_to_CCT_Ohno2013(uv, cmfs)  # doctest: +ELLIPSIS
    array([  6.50747...e+03,   3.22334...e-03])
    """

    uv = as_float_array(uv)

    CCT_D_uv = [
        _uv_to_CCT_Ohno2013(a, cmfs, start, end, count, iterations)
        for a in np.reshape(uv, (-1, 2))
    ]

    return np.reshape(as_float_array(CCT_D_uv), uv.shape)
コード例 #39
0
ファイル: ycbcr.py プロジェクト: vidakDK/colour
def YcCbcCrc_to_RGB(YcCbcCrc,
                    in_bits=10,
                    in_legal=True,
                    in_int=False,
                    is_12_bits_system=False,
                    **kwargs):
    """
    Converts an array of *Yc'Cbc'Crc'* colour encoding values to the
    corresponding *RGB* array of linear values.

    Parameters
    ----------
    YcCbcCrc : array_like
        Input *Yc'Cbc'Crc'* colour encoding array of linear float values.
    in_bits : int, optional
        Bit depth for integer input, or used in the calculation of the
        denominator for legal range float values, i.e. 8-bit means the float
        value for legal white is *235 / 255*. Default is *10*.
    in_legal : bool, optional
        Whether to treat the input values as legal range. Default is *False*.
    in_int : bool, optional
        Whether to treat the input values as ``in_bits`` integer code values.
        Default is *False*.
    is_12_bits_system : bool, optional
        *Recommendation ITU-R BT.2020* EOTF (EOCF) adopts different parameters
        for 10 and 12 bit systems. Default is *False*.

    Other Parameters
    ----------------
    in_range : array_like, optional
        Array overriding the computed range such as
        *in_range = (Y_min, Y_max, C_min, C_max)*. If ``in_range`` is
        undefined, *Y_min*, *Y_max*, *C_min* and *C_max* will be computed using
        :func:`colour.models.rgb.ycbcr.YCbCr_ranges` definition.

    Returns
    -------
    ndarray
        *RGB* array of linear float values.

    Notes
    -----

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

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

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

    Warning
    -------
    This definition is specifically for usage with
    *Recommendation ITU-R BT.2020* when adopting the constant luminance
    implementation.

    References
    ----------
    :cite:`InternationalTelecommunicationUnion2015h`,
    :cite:`Wikipedia2004d`

    Examples
    --------
    >>> YcCbcCrc = np.array([1689, 2048, 2048])
    >>> YcCbcCrc_to_RGB(YcCbcCrc, in_legal=True, in_bits=12, in_int=True,
    ...                 is_12_bits_system=True)
    ... # doctest: +ELLIPSIS
    array([ 0.1800903...,  0.1800903...,  0.1800903...])
    """

    if in_int:
        YcCbcCrc = as_float_array(YcCbcCrc)
    else:
        YcCbcCrc = to_domain_1(YcCbcCrc)

    Yc, Cbc, Crc = tsplit(YcCbcCrc.astype(DEFAULT_FLOAT_DTYPE))
    Y_min, Y_max, C_min, C_max = kwargs.get(
        'in_range', YCbCr_ranges(in_bits, in_legal, in_int))

    Yc -= Y_min
    Cbc -= (C_max + C_min) / 2
    Crc -= (C_max + C_min) / 2
    Yc *= 1 / (Y_max - Y_min)
    Cbc *= 1 / (C_max - C_min)
    Crc *= 1 / (C_max - C_min)
    B = np.where(Cbc <= 0, Cbc * 1.9404 + Yc, Cbc * 1.5816 + Yc)
    R = np.where(Crc <= 0, Crc * 1.7184 + Yc, Crc * 0.9936 + Yc)

    with domain_range_scale('ignore'):
        Yc = eotf_BT2020(Yc, is_12_bits_system=is_12_bits_system)
        B = eotf_BT2020(B, is_12_bits_system=is_12_bits_system)
        R = eotf_BT2020(R, is_12_bits_system=is_12_bits_system)

    G = (Yc - 0.0593 * B - 0.2627 * R) / 0.6780

    RGB = tstack([R, G, B])

    return from_range_1(RGB)
コード例 #40
0
def absolute_luminance_calibration_Lagarde2016(RGB,
                                               measured_illuminance,
                                               colourspace=RGB_COLOURSPACES[
                                                   'sRGB']):
    """
    Performs absolute *Luminance* calibration of given *RGB* panoramic image
    using *Lagarde (2016)* method.

    Parameters
    ----------
    RGB : array_like
        *RGB* panoramic image to calibrate.
    measured_illuminance : numeric
        Measured illuminance :math:`E_v`.
    colourspace : `colour.RGB_Colourspace`, optional
        *RGB* colourspace used for internal *Luminance* computation.

    Returns
    -------
    ndarray
         Absolute *Luminance* calibrated *RGB* panoramic image.

    Examples
    --------
    >>> RGB = np.ones((4, 8, 3))
    >>> absolute_luminance_calibration_Lagarde2016(  # doctest: +ELLIPSIS
    ...     RGB, 500)
    array([[[ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...]],
    <BLANKLINE>
           [[ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...]],
    <BLANKLINE>
           [[ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...]],
    <BLANKLINE>
           [[ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...],
            [ 233.9912506...,  233.9912506...,  233.9912506...]]])
    """

    RGB = as_float_array(RGB)

    E_v = upper_hemisphere_illuminance_Lagarde2016(RGB, colourspace)

    return RGB / E_v * measured_illuminance
コード例 #41
0
def K_coefficient(
    xez_1: ArrayLike,
    xez_2: ArrayLike,
    bRGB_o1: ArrayLike,
    bRGB_o2: ArrayLike,
    Y_o: FloatingOrArrayLike,
    n: FloatingOrArrayLike = 1,
) -> FloatingOrNDArray:
    """
    Compute the coefficient :math:`K` for correcting the difference between
    the test and references illuminances.

    Parameters
    ----------
    xez_1
        Intermediate values :math:`\\xi_1`, :math:`\\eta_1`, :math:`\\zeta_1`
        for the test illuminant and background.
    xez_2
        Intermediate values :math:`\\xi_2`, :math:`\\eta_2`, :math:`\\zeta_2`
        for the reference illuminant and background.
    bRGB_o1
        Chromatic adaptation exponential factors :math:`\\beta_1(R_{o1})`,
        :math:`\\beta_1(G_{o1})` and :math:`\\beta_2(B_{o1})` of test sample.
    bRGB_o2
        Chromatic adaptation exponential factors :math:`\\beta_1(R_{o2})`,
        :math:`\\beta_1(G_{o2})` and :math:`\\beta_2(B_{o2})` of reference
        sample.
    Y_o
        Luminance factor :math:`Y_o` of achromatic background as percentage
        normalised to domain [18, 100] in **'Reference'** domain-range scale.
    n
        Noise component in fundamental primary system.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Coefficient :math:`K`.

    Examples
    --------
    >>> xez_1 = np.array([1.11857195, 0.93295530, 0.32680879])
    >>> xez_2 = np.array([1.00000372, 1.00000176, 0.99999461])
    >>> bRGB_o1 = np.array([3.74852518, 3.63920879, 2.78924811])
    >>> bRGB_o2 = np.array([3.68102374, 3.68102256, 3.56557351])
    >>> Y_o = 20
    >>> K_coefficient(xez_1, xez_2, bRGB_o1, bRGB_o2, Y_o)
    1.0
    """

    xi_1, eta_1, _zeta_1 = tsplit(xez_1)
    xi_2, eta_2, _zeta_2 = tsplit(xez_2)
    bR_o1, bG_o1, _bB_o1 = tsplit(bRGB_o1)
    bR_o2, bG_o2, _bB_o2 = tsplit(bRGB_o2)
    Y_o = as_float_array(Y_o)
    n = as_float_array(n)

    K = spow((Y_o * xi_1 + n) / (20 * xi_1 + n), (2 / 3) * bR_o1) / spow(
        (Y_o * xi_2 + n) / (20 * xi_2 + n), (2 / 3) * bR_o2)

    K *= spow((Y_o * eta_1 + n) / (20 * eta_1 + n), (1 / 3) * bG_o1) / spow(
        (Y_o * eta_2 + n) / (20 * eta_2 + n), (1 / 3) * bG_o2)

    return K
コード例 #42
0
def contrast_sensitivity_function_Barten1999(u,
                                             sigma=sigma_Barten1999(
                                                 0.5 / 60, 0.08 / 60, 2.1),
                                             k=3.0,
                                             T=0.1,
                                             X_0=60,
                                             Y_0=None,
                                             X_max=12,
                                             Y_max=None,
                                             N_max=15,
                                             n=0.03,
                                             p=1.2274 * 10 ** 6,
                                             E=retinal_illuminance_Barten1999(
                                                 20, 2.1),
                                             phi_0=3 * 10 ** -8,
                                             u_0=7):
    """
    Returns the contrast sensitivity :math:`S` of the human eye according to
    the contrast sensitivity function (CSF) described by *Barten (1999)*.

    Contrast sensitivity is defined as the inverse of the modulation threshold
    of a sinusoidal luminance pattern. The modulation threshold of this pattern
    is generally defined by 50% probability of detection. The contrast
    sensitivity function or CSF gives the contrast sensitivity as a function of
    spatial frequency. In the CSF, the spatial frequency is expressed in
    angular units with respect to the eye. It reaches a maximum between 1 and
    10 cycles per degree with a fall off at higher and lower spatial
    frequencies.

    Parameters
    ----------
    u : numeric
        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.
    k : numeric or array_like, optional
        Signal-to-noise (SNR) ratio :math:`k`.
    T : numeric or array_like, optional
        Integration time :math:`T` in seconds of the eye.
    X_0 : numeric or array_like, optional
        Angular size :math:`X_0` in degrees of the object in the x direction.
    Y_0 : numeric or array_like, optional
        Angular size :math:`Y_0` in degrees of the object in the y direction.
    X_max : numeric or array_like, optional
        Maximum angular size :math:`X_{max}` in degrees of the integration
        area in the x direction.
    Y_max : numeric or array_like, optional
        Maximum angular size :math:`Y_{max}` in degrees of the integration
        area in the y direction.
    N_max : numeric or array_like, optional
        Maximum number of cycles :math:`N_{max}` over which the eye can
        integrate the information.
    n : numeric or array_like, optional
        Quantum efficiency of the eye :math:`n`.
    p : numeric or array_like, optional
        Photon conversion factor :math:`p` in
        :math:`photons\\div seconds\\div degrees^2\\div Trolands` that
        depends on the light source.
    E : numeric or array_like, optional
        Retinal illuminance :math:`E` in Trolands.
    phi_0 : numeric or array_like, optional
        Spectral density :math:`\\phi_0` in :math:`seconds degrees^2` of the
        neural noise.
    u_0 : numeric or array_like, optional
        Spatial frequency :math:`u_0` in :math:`cycles\\div degrees` above
        which the lateral inhibition ceases.

    Returns
    -------
    ndarray
        Contrast sensitivity :math:`S`.

    Warnings
    --------
    This definition expects :math:`\\sigma_{0}` and :math:`C_{ab}` used in the
    computation of :math:`\\sigma` 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.

    Notes
    -----
    -   The formula holds for bilateral viewing and for equal dimensions of
        the object in x and y direction. For monocular vision, the contrast
        sensitivity is a factor :math:`\\sqrt{2}` smaller.
    -   *Barten (1999)* CSF default values for the :math:`k`,
        :math:`\\sigma_{0}`, :math:`C_{ab}`, :math:`T`, :math:`X_{max}`,
        :math:`N_{max}`, :math:`n`, :math:`\\phi_{0}` and :math:`u_0` constants
        are valid for a standard observer with good vision and with an age
        between 20 and 30 years.
    -   The other constants have been filled using reference data from
        *Figure 31* in :cite:`InternationalTelecommunicationUnion2015` but
        must be adapted to the current use case.
    -   The product of :math:`u`, the cycles per degree, and :math:`X_0`,
        the number of degrees, gives the number of cycles :math:`P_c` in a
        pattern. Therefore, :math:`X_0` can be made a variable dependent on
        :math:`u` such as :math:`X_0 = P_c / u`.

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

    Examples
    --------
    >>> contrast_sensitivity_function_Barten1999(4)  # doctest: +ELLIPSIS
    360.8691122...

    Reproducing *Figure 31* in \
:cite:`InternationalTelecommunicationUnion2015` illustrating the minimum
    detectable contrast according to *Barten (1999)* model with the assumed
    conditions for UHDTV applications. The minimum detectable contrast
    :math:`MDC` is then defined as follows::

        :math:`MDC = 1 / CSF * 2 * (1 / 1.27)`

    where :math:`2` is used for the conversion from modulation to contrast and
    :math:`1 / 1.27` is used for the conversion from sinusoidal to rectangular
    waves.

    >>> from scipy.optimize import fmin
    >>> settings_BT2246 = {
    ...     'k': 3.0,
    ...     'T': 0.1,
    ...     'X_max': 12,
    ...     'N_max': 15,
    ...     'n': 0.03,
    ...     'p': 1.2274 * 10 ** 6,
    ...     'phi_0': 3 * 10 ** -8,
    ...     'u_0': 7,
    ... }
    >>>
    >>> def maximise_spatial_frequency(L):
    ...     maximised_spatial_frequency = []
    ...     for L_v in L:
    ...         X_0 = 60
    ...         d = pupil_diameter_Barten1999(L_v, X_0)
    ...         sigma = sigma_Barten1999(0.5 / 60, 0.08 / 60, d)
    ...         E = retinal_illuminance_Barten1999(L_v, d, True)
    ...         maximised_spatial_frequency.append(
    ...             fmin(lambda x: (
    ...                     -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))
    >>>
    >>> L = np.logspace(np.log10(0.01), np.log10(100), 10)
    >>> X_0 = Y_0 = 60
    >>> d = pupil_diameter_Barten1999(L, X_0, Y_0)
    >>> sigma = sigma_Barten1999(0.5 / 60, 0.08 / 60, d)
    >>> E = retinal_illuminance_Barten1999(L, d)
    >>> u = maximise_spatial_frequency(L)
    >>> (1 / contrast_sensitivity_function_Barten1999(
    ...     u=u, sigma=sigma, E=E, X_0=X_0, Y_0=Y_0, **settings_BT2246)
    ...  * 2 * (1/ 1.27))
    ... # doctest: +ELLIPSIS
    array([ 0.0207396...,  0.0134885...,  0.0096063...,  0.0077299...,  \
0.0068983...,
            0.0065057...,  0.0062712...,  0.0061198...,  0.0060365...,  \
0.0059984...])
    """

    u = as_float_array(u)
    k = as_float_array(k)
    T = as_float_array(T)
    X_0 = as_float_array(X_0)
    Y_0 = X_0 if Y_0 is None else as_float_array(Y_0)
    X_max = as_float_array(X_max)
    Y_max = X_max if Y_max is None else as_float_array(Y_max)
    N_max = as_float_array(N_max)
    n = as_float_array(n)
    p = as_float_array(p)
    E = as_float_array(E)
    phi_0 = as_float_array(phi_0)
    u_0 = as_float_array(u_0)

    M_opt = optical_MTF_Barten1999(u, sigma)

    M_as = 1 / (maximum_angular_size_Barten1999(u, X_0, X_max, N_max) *
                maximum_angular_size_Barten1999(u, Y_0, Y_max, N_max))

    S = (M_opt / k) / np.sqrt(2 / T * M_as * (1 / (n * p * E) + phi_0 /
                                              (1 - np.exp(-(u / u_0) ** 2))))

    return as_float(S)
コード例 #43
0
def logarithmic_function_basic(x, style='log2', base=2):
    """
    Defines the basic logarithmic function.

    Parameters
    ----------
    x : numeric
        The data to undergo basic logarithmic conversion.
    style : unicode, optional
        **{'log10', 'antiLog10', 'log2', 'antiLog2', 'logB', 'antiLogB'}**,
        Defines the behaviour for the logarithmic function to operate:

        -   *log10*: Applies a base 10 logarithm to the passed value.
        -   *antiLog10*: Applies a base 10 anti-logarithm to the passed value.
        -   *log2*: Applies a base 2 logarithm to the passed value.
        -   *antiLog2*: Applies a base 2 anti-logarithm to the passed value.
        -   *logB*: Applies an arbitrary base logarithm to the passed value.
        -   *antiLogB*: Applies an arbitrary base anti-logarithm to the passed
            value.
    base : numeric, optional
        Logarithmic base used for the conversion.

    Returns
    -------
    numeric or ndarray
        Logarithmically converted data.

    Raises
    ------
    ValueError
        If the *style* is not defined.

    Examples
    --------
    The basic logarithmic function *styles* operate as follows:

    >>> logarithmic_function_basic(0.18)  # doctest: +ELLIPSIS
    -2.4739311...
    >>> logarithmic_function_basic(0.18, 'log10')  # doctest: +ELLIPSIS
    -0.7447274...
    >>> logarithmic_function_basic(  # doctest: +ELLIPSIS
    ...    0.18, 'logB', 3)
    -1.5608767...
    >>> logarithmic_function_basic(  # doctest: +ELLIPSIS
    ...    -2.473931188332412, 'antiLog2')
    0.18000000...
    >>> logarithmic_function_basic(  # doctest: +ELLIPSIS
    ...    -0.7447274948966939, 'antiLog10')
    0.18000000...
    >>> logarithmic_function_basic(  # doctest: +ELLIPSIS
    ...    -1.5608767950073117, 'antiLogB', 3)
    0.18000000...
    """

    x = as_float_array(x)

    style = style.lower()
    if style == 'log10':
        return as_float(np.where(x >= FLT_MIN, np.log10(x), np.log10(FLT_MIN)))
    elif style == 'antilog10':
        return as_float(10**x)
    elif style == 'log2':
        return as_float(np.where(x >= FLT_MIN, np.log2(x), np.log2(FLT_MIN)))
    elif style == 'antilog2':
        return as_float(2**x)
    elif style == 'logb':
        return as_float(np.log(x) / np.log(base))
    elif style == 'antilogb':
        return as_float(base**x)
    else:
        raise ValueError(
            'Undefined style used: "{0}", must be one of the following: '
            '"{1}".'.format(
                style, ', '.join([
                    'log10', 'antiLog10', 'log2', 'antiLog2', 'logB',
                    'antiLogB'
                ])))
コード例 #44
0
def logarithmic_function_camera(x,
                                style='cameraLinToLog',
                                base=2,
                                log_side_slope=1,
                                lin_side_slope=1,
                                log_side_offset=0,
                                lin_side_offset=0,
                                lin_side_break=0.005,
                                linear_slope=None):
    """
    Defines the camera logarithmic function.

    Parameters
    ----------
    x : numeric
        Linear/non-linear data to undergo encoding/decoding.
    style : unicode, optional
        **{'cameraLinToLog', 'cameraLogToLin'}**,
        Defines the behaviour for the logarithmic function to operate:

        -   *cameraLinToLog*: Applies a piece-wise function with logarithmic
            and linear segments on linear values, converting them to non-linear
            values.
        -   *cameraLogToLin*: Applies a piece-wise function with logarithmic
            and linear segments on non-linear values, converting them to linear
            values.
    base : numeric, optional
        Logarithmic base used for the conversion.
    log_side_slope : numeric, optional
        Slope (or gain) applied to the log side of the logarithmic segment. The
        default value is 1.
    lin_side_slope : numeric, optional
        Slope of the linear side of the logarithmic segment. The default value
        is 1.
    log_side_offset : numeric, optional
        Offset applied to the log side of the logarithmic segment. The default
        value is 0.
    lin_side_offset : numeric, optional
        Offset applied to the linear side of the logarithmic segment. The
        default value is 0.
    lin_side_break : numeric
        Break-point, defined in linear space, at which the piece-wise function
        transitions between the logarithmic and linear segments.
    linear_slope : numeric, optional
        Slope of the linear portion of the curve. The default value is *None*.

    Returns
    -------
    numeric or ndarray
        Encoded/Decoded data.

    Raises
    ------
    ValueError
        If the *style* is not defined.

    Examples
    --------
    >>> logarithmic_function_camera(  # doctest: +ELLIPSIS
    ...    0.18, 'cameraLinToLog')
    -2.4739311...
    >>> logarithmic_function_camera(  # doctest: +ELLIPSIS
    ...    -2.4739311883324122, 'cameraLogToLin')
    0.1800000...
    """

    x = as_float_array(x)

    log_side_break = (
        log_side_slope *
        (np.log(lin_side_slope * lin_side_break + lin_side_offset) /
         np.log(base)) + log_side_offset)

    if linear_slope is None:
        linear_slope = (log_side_slope *
                        (lin_side_slope /
                         ((lin_side_slope * lin_side_break + lin_side_offset) *
                          np.log(base))))

    linear_offset = log_side_break - linear_slope * lin_side_break

    style = style.lower()
    if style == 'cameralintolog':
        return as_float(
            np.where(
                x <= lin_side_break, linear_slope * x + linear_offset,
                logarithmic_function_quasilog(x, 'linToLog', base,
                                              log_side_slope, lin_side_slope,
                                              log_side_offset,
                                              lin_side_offset)))
    elif style == 'cameralogtolin':
        return as_float(
            np.where(
                x <= log_side_break,
                (x - linear_offset) / linear_slope,
                logarithmic_function_quasilog(x, 'logToLin', base,
                                              log_side_slope, lin_side_slope,
                                              log_side_offset,
                                              lin_side_offset),
            ))
    else:
        raise ValueError(
            'Undefined style used: "{0}", must be one of the following: '
            '"{1}".'.format(style,
                            ', '.join(['cameraLinToLog', 'cameraLogToLin'])))
コード例 #45
0
ファイル: dominant.py プロジェクト: colour-science/colour
def dominant_wavelength(
    xy: ArrayLike,
    xy_n: ArrayLike,
    cmfs: Optional[MultiSpectralDistributions] = None,
    inverse: bool = False,
) -> Tuple[NDArray, NDArray, NDArray]:
    """
    Return the *dominant wavelength* :math:`\\lambda_d` for given colour
    stimulus :math:`xy` and the related :math:`xy_wl` first and :math:`xy_{cw}`
    second intersection coordinates with the spectral locus.

    In the eventuality where the :math:`xy_wl` first intersection coordinates
    are on the line of purples, the *complementary wavelength* will be computed
    in lieu.

    The *complementary wavelength* is indicated by a negative sign and the
    :math:`xy_{cw}` second intersection coordinates which are set by default to
    the same value than :math:`xy_wl` first intersection coordinates will be
    set to the *complementary dominant wavelength* intersection coordinates
    with the spectral locus.

    Parameters
    ----------
    xy
        Colour stimulus *CIE xy* chromaticity coordinates.
    xy_n
        Achromatic stimulus *CIE xy* chromaticity coordinates.
    cmfs
        Standard observer colour matching functions, default to the
        *CIE 1931 2 Degree Standard Observer*.
    inverse
        Inverse the computation direction to retrieve the
        *complementary wavelength*.

    Returns
    -------
    :class:`tuple`
        *Dominant wavelength*, first intersection point *CIE xy* chromaticity
        coordinates, second intersection point *CIE xy* chromaticity
        coordinates.

    References
    ----------
    :cite:`CIETC1-482004o`, :cite:`Erdogana`

    Examples
    --------
    *Dominant wavelength* computation:

    >>> from colour.colorimetry import MSDS_CMFS
    >>> from pprint import pprint
    >>> cmfs = MSDS_CMFS['CIE 1931 2 Degree Standard Observer']
    >>> xy = np.array([0.54369557, 0.32107944])
    >>> xy_n = np.array([0.31270000, 0.32900000])
    >>> pprint(dominant_wavelength(xy, xy_n, cmfs))  # doctest: +ELLIPSIS
    (array(616...),
     array([ 0.6835474...,  0.3162840...]),
     array([ 0.6835474...,  0.3162840...]))

    *Complementary dominant wavelength* is returned if the first intersection
    is located on the line of purples:

    >>> xy = np.array([0.37605506, 0.24452225])
    >>> pprint(dominant_wavelength(xy, xy_n))  # doctest: +ELLIPSIS
    (array(-509.0),
     array([ 0.4572314...,  0.1362814...]),
     array([ 0.0104096...,  0.7320745...]))
    """

    cmfs, _illuminant = handle_spectral_arguments(cmfs)

    xy = as_float_array(xy)
    xy_n = np.resize(xy_n, xy.shape)

    xy_s = XYZ_to_xy(cmfs.values)

    i_wl, xy_wl = closest_spectral_locus_wavelength(xy, xy_n, xy_s, inverse)
    xy_cwl = xy_wl
    wl = cmfs.wavelengths[i_wl]

    xy_e = (extend_line_segment(xy, xy_n) if inverse else extend_line_segment(
        xy_n, xy))
    intersect = intersect_line_segments(np.concatenate((xy_n, xy_e), -1),
                                        np.hstack([xy_s[0],
                                                   xy_s[-1]])).intersect
    intersect = np.reshape(intersect, wl.shape)

    i_wl_r, xy_cwl_r = closest_spectral_locus_wavelength(
        xy, xy_n, xy_s, not inverse)
    wl_r = -cmfs.wavelengths[i_wl_r]

    wl = np.where(intersect, wl_r, wl)
    xy_cwl = np.where(intersect[..., np.newaxis], xy_cwl_r, xy_cwl)

    return wl, np.squeeze(xy_wl), np.squeeze(xy_cwl)
コード例 #46
0
ファイル: __init__.py プロジェクト: wenh06/colour
def chromatic_adaptation(XYZ, XYZ_w, XYZ_wr, method='Von Kries', **kwargs):
    """
    Adapts given stimulus from test viewing conditions to reference viewing
    conditions.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of stimulus to adapt.
    XYZ_w : array_like
        Test viewing condition *CIE XYZ* tristimulus values of the whitepoint.
    XYZ_wr : array_like
        Reference viewing condition *CIE XYZ* tristimulus values of the
        whitepoint.
    method : unicode, optional
        **{'Von Kries', 'CIE 1994', 'CMCCAT2000', 'Fairchild 1990'}**,
        Computation method.

    Other Parameters
    ----------------
    E_o1 : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Test illuminance :math:`E_{o1}` in :math:`cd/m^2`.
    E_o2 : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Reference illuminance :math:`E_{o2}` in :math:`cd/m^2`.
    L_A1 : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Luminance of test adapting field :math:`L_{A1}` in :math:`cd/m^2`.
    L_A2 : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Luminance of reference adapting field :math:`L_{A2}` in :math:`cd/m^2`.
    Y_n : numeric or array_like
        {:func:`colour.adaptation.chromatic_adaptation_Fairchild1990`},
        Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`.
    Y_o : numeric
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Luminance factor :math:`Y_o` of achromatic background normalised to
        domain [0.18, 1] in **'Reference'** domain-range scale.
    direction : unicode, optional
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        **{'Forward', 'Inverse'}**,
        Chromatic adaptation direction.
    discount_illuminant : bool, optional
        {:func:`colour.adaptation.chromatic_adaptation_Fairchild1990`},
        Truth value indicating if the illuminant should be discounted.
    n : numeric, optional
        {:func:`colour.adaptation.chromatic_adaptation_CIE1994`},
        Noise component in fundamental primary system.
    surround : InductionFactors_CMCCAT2000, optional
        {:func:`colour.adaptation.chromatic_adaptation_CMCCAT2000`},
        Surround viewing conditions induction factors.
    transform : unicode, optional
        {:func:`colour.adaptation.chromatic_adaptation_VonKries`},
        **{'CAT02', 'XYZ Scaling', 'Von Kries', 'Bradford', 'Sharp',
        'Fairchild', 'CMCCAT97', 'CMCCAT2000', 'CAT02 Brill 2008',
        'Bianco 2010', 'Bianco PC 2010'}**,
        Chromatic adaptation transform.

    Returns
    -------
    ndarray
        *CIE XYZ_c* tristimulus values of the stimulus corresponding colour.

    Notes
    -----

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

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

    References
    ----------
    :cite:`CIETC1-321994b`, :cite:`Fairchild1991a`, :cite:`Fairchild2013s`,
    :cite:`Fairchild2013t`, :cite:`Li2002a`, :cite:`Westland2012k`

    Examples
    --------

    *Von Kries* chromatic adaptation:

    >>> import numpy as np
    >>> XYZ = np.array([0.20654008, 0.12197225, 0.05136952])
    >>> XYZ_w = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> XYZ_wr = np.array([0.96429568, 1.00000000, 0.82510460])
    >>> chromatic_adaptation(XYZ, XYZ_w, XYZ_wr)
    ... # doctest: +ELLIPSIS
    array([ 0.2163881...,  0.1257    ,  0.0384749...])

    *CIE 1994* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.2800, 0.2126, 0.0527])
    >>> XYZ_w = np.array([1.09867452, 1.00000000, 0.35591556])
    >>> XYZ_wr = np.array([0.95045593, 1.00000000, 1.08905775])
    >>> Y_o = 0.20
    >>> E_o = 1000
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='CIE 1994', Y_o=Y_o, E_o1=E_o, E_o2=E_o)
    ... # doctest: +ELLIPSIS
    array([ 0.2403379...,  0.2115621...,  0.1764301...])

    *CMCCAT2000* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.2248, 0.2274, 0.0854])
    >>> XYZ_w = np.array([1.1115, 1.0000, 0.3520])
    >>> XYZ_wr = np.array([0.9481, 1.0000, 1.0730])
    >>> L_A = 200
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='CMCCAT2000', L_A1=L_A, L_A2=L_A)
    ... # doctest: +ELLIPSIS
    array([ 0.1952698...,  0.2306834...,  0.2497175...])

    *Fairchild (1990)* chromatic adaptation, requires extra *kwargs*:

    >>> XYZ = np.array([0.1953, 0.2307, 0.2497])
    >>> Y_n = 200
    >>> chromatic_adaptation(
    ...     XYZ, XYZ_w, XYZ_wr, method='Fairchild 1990', Y_n=Y_n)
    ... # doctest: +ELLIPSIS
    array([ 0.2332526...,  0.2332455...,  0.7611593...])
    """

    function = CHROMATIC_ADAPTATION_METHODS[method]

    domain_range_reference = get_domain_range_scale() == 'reference'
    domain_100 = (chromatic_adaptation_CIE1994,
                  chromatic_adaptation_CMCCAT2000,
                  chromatic_adaptation_Fairchild1990)

    if function in domain_100 and domain_range_reference:
        XYZ = as_float_array(XYZ) * 100
        XYZ_w = as_float_array(XYZ_w) * 100
        XYZ_wr = as_float_array(XYZ_wr) * 100
        if kwargs.get('Y_o'):
            kwargs['Y_o'] = kwargs['Y_o'] * 100

    kwargs.update({'XYZ_w': XYZ_w, 'XYZ_wr': XYZ_wr})

    if function is chromatic_adaptation_CIE1994:
        from colour import XYZ_to_xy

        kwargs.update({'xy_o1': XYZ_to_xy(XYZ_w), 'xy_o2': XYZ_to_xy(XYZ_wr)})

    elif function is chromatic_adaptation_Fairchild1990:
        kwargs.update({'XYZ_n': XYZ_w, 'XYZ_r': XYZ_wr})

    XYZ_c = function(XYZ, **filter_kwargs(function, **kwargs))

    if function in domain_100 and domain_range_reference:
        XYZ_c /= 100

    return XYZ_c
コード例 #47
0
ファイル: dominant.py プロジェクト: colour-science/colour
def closest_spectral_locus_wavelength(
        xy: ArrayLike,
        xy_n: ArrayLike,
        xy_s: ArrayLike,
        inverse: Boolean = False) -> Tuple[NDArray, NDArray]:
    """
    Return the coordinates and closest spectral locus wavelength index to the
    point where the line defined by the given achromatic stimulus :math:`xy_n`
    to colour stimulus :math:`xy_n` *CIE xy* chromaticity coordinates
    intersects the spectral locus.

    Parameters
    ----------
    xy
        Colour stimulus *CIE xy* chromaticity coordinates.
    xy_n
        Achromatic stimulus *CIE xy* chromaticity coordinates.
    xy_s
        Spectral locus *CIE xy* chromaticity coordinates.
    inverse
        The intersection will be computed using the colour stimulus :math:`xy`
        to achromatic stimulus :math:`xy_n` inverse direction.

    Returns
    -------
    :class:`tuple`
        Closest wavelength index, intersection point *CIE xy* chromaticity
        coordinates.

    Raises
    ------
    ValueError
        If no closest spectral locus wavelength index and coordinates found.

    Examples
    --------
    >>> from colour.colorimetry import MSDS_CMFS
    >>> cmfs = MSDS_CMFS['CIE 1931 2 Degree Standard Observer']
    >>> xy = np.array([0.54369557, 0.32107944])
    >>> xy_n = np.array([0.31270000, 0.32900000])
    >>> xy_s = XYZ_to_xy(cmfs.values)
    >>> ix, intersect = closest_spectral_locus_wavelength(xy, xy_n, xy_s)
    >>> print(ix) #
    256
    >>> print(intersect) # doctest: +ELLIPSIS
    [ 0.6835474...  0.3162840...]
    """

    xy = as_float_array(xy)
    xy_n = np.resize(xy_n, xy.shape)
    xy_s = as_float_array(xy_s)

    xy_e = (extend_line_segment(xy, xy_n) if inverse else extend_line_segment(
        xy_n, xy))

    # Closing horse-shoe shape to handle line of purples intersections.
    xy_s = np.vstack([xy_s, xy_s[0, :]])

    xy_wl = intersect_line_segments(
        np.concatenate((xy_n, xy_e), -1),
        np.hstack([xy_s, np.roll(xy_s, 1, axis=0)]),
    ).xy
    # Extracting the first intersection per-wavelength.
    xy_wl = np.sort(xy_wl, 1)[:, 0, :]

    if not len(xy_wl):
        raise ValueError(
            f"No closest spectral locus wavelength index and coordinates "
            f'found for "{xy}" colour stimulus and "{xy_n}" achromatic '
            f'stimulus "xy" chromaticity coordinates!')

    i_wl = np.argmin(scipy.spatial.distance.cdist(xy_wl, xy_s), axis=-1)

    i_wl = np.reshape(i_wl, xy.shape[0:-1])
    xy_wl = np.reshape(xy_wl, xy.shape)

    return i_wl, xy_wl
コード例 #48
0
def read_LUT_SonySPI1D(path):
    """
    Reads given *Sony* *.spi1d* *LUT* file.

    Parameters
    ----------
    path : unicode
        *LUT* path.

    Returns
    -------
    LUT1D or LUT2D
        :class:`LUT1D` or :class:`LUT2D` class instance.

    Examples
    --------
    Reading a 1D *Sony* *.spi1d* *LUT*:

    >>> import os
    >>> path = os.path.join(
    ...     os.path.dirname(__file__), 'tests', 'resources', 'sony_spi1d',
    ...     'oetf_reverse_sRGB_1D.spi1d')
    >>> print(read_LUT_SonySPI1D(path))
    LUT1D - oetf reverse sRGB 1D
    ----------------------------
    <BLANKLINE>
    Dimensions : 1
    Domain     : [-0.1  1.5]
    Size       : (16,)
    Comment 01 : Generated by "Colour 0.3.11".
    Comment 02 : "colour.models.oetf_reverse_sRGB".

    Reading a 2D *Sony* *.spi1d* *LUT*:

    >>> path = os.path.join(
    ...     os.path.dirname(__file__), 'tests', 'resources', 'sony_spi1d',
    ...     'oetf_reverse_sRGB_2D.spi1d')
    >>> print(read_LUT_SonySPI1D(path))
    LUT2D - oetf reverse sRGB 2D
    ----------------------------
    <BLANKLINE>
    Dimensions : 2
    Domain     : [[-0.1 -0.1 -0.1]
                  [ 1.5  1.5  1.5]]
    Size       : (16, 3)
    Comment 01 : Generated by "Colour 0.3.11".
    Comment 02 : "colour.models.oetf_reverse_sRGB".
    """

    title = path_to_title(path)
    domain_min, domain_max = np.array([0, 1])
    dimensions = 1
    table = []

    comments = []

    with open(path) as spi1d_file:
        lines = spi1d_file.readlines()
        for line in lines:
            line = line.strip()

            if len(line) == 0:
                continue

            if line.startswith('#'):
                comments.append(line[1:].strip())
                continue

            tokens = line.split()
            if tokens[0] == 'Version':
                continue
            if tokens[0] == 'From':
                domain_min, domain_max = parse_array(tokens[1:])
            elif tokens[0] == 'Length':
                continue
            elif tokens[0] == 'Components':
                component = DEFAULT_INT_DTYPE(tokens[1])
                assert component in (1, 3), (
                    'Only 1 or 3 components are supported!')

                dimensions = 1 if component == 1 else 2
            elif tokens[0] in ('{', '}'):
                continue
            else:
                table.append(parse_array(tokens))

    table = as_float_array(table)
    if dimensions == 1:
        return LUT1D(np.squeeze(table),
                     title,
                     np.array([domain_min, domain_max]),
                     comments=comments)
    elif dimensions == 2:
        return LUT2D(table,
                     title,
                     np.array([[domain_min, domain_min, domain_min],
                               [domain_max, domain_max, domain_max]]),
                     comments=comments)
コード例 #49
0
def chromatic_adaptation_Fairchild1990(XYZ_1,
                                       XYZ_n,
                                       XYZ_r,
                                       Y_n,
                                       discount_illuminant=False):
    """
    Adapts given stimulus *CIE XYZ_1* tristimulus values from test viewing
    conditions to reference viewing conditions using *Fairchild (1990)*
    chromatic adaptation model.

    Parameters
    ----------
    XYZ_1 : array_like
        *CIE XYZ_1* tristimulus values of test sample / stimulus.
    XYZ_n : array_like
        Test viewing condition *CIE XYZ_n* tristimulus values of whitepoint.
    XYZ_r : array_like
        Reference viewing condition *CIE XYZ_r* tristimulus values of
        whitepoint.
    Y_n : numeric or array_like
        Luminance :math:`Y_n` of test adapting stimulus in :math:`cd/m^2`.
    discount_illuminant : bool, optional
        Truth value indicating if the illuminant should be discounted.

    Returns
    -------
    ndarray
        Adapted *CIE XYZ_2* tristimulus values of stimulus.

    Notes
    -----

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``XYZ_1``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_n``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+
    | ``XYZ_r``  | [0, 100]              | [0, 1]        |
    +------------+-----------------------+---------------+

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

    References
    ----------
    :cite:`Fairchild1991a`, :cite:`Fairchild2013s`

    Examples
    --------
    >>> XYZ_1 = np.array([19.53, 23.07, 24.97])
    >>> XYZ_n = np.array([111.15, 100.00, 35.20])
    >>> XYZ_r = np.array([94.81, 100.00, 107.30])
    >>> Y_n = 200
    >>> chromatic_adaptation_Fairchild1990(XYZ_1, XYZ_n, XYZ_r, Y_n)
    ... # doctest: +ELLIPSIS
    array([ 23.3252634...,  23.3245581...,  76.1159375...])
    """

    XYZ_1 = to_domain_100(XYZ_1)
    XYZ_n = to_domain_100(XYZ_n)
    XYZ_r = to_domain_100(XYZ_r)
    Y_n = as_float_array(Y_n)

    LMS_1 = vector_dot(MATRIX_XYZ_TO_RGB_FAIRCHILD1990, XYZ_1)
    LMS_n = vector_dot(MATRIX_XYZ_TO_RGB_FAIRCHILD1990, XYZ_n)
    LMS_r = vector_dot(MATRIX_XYZ_TO_RGB_FAIRCHILD1990, XYZ_r)

    p_LMS = degrees_of_adaptation(
        LMS_1, Y_n, discount_illuminant=discount_illuminant)

    a_LMS_1 = p_LMS / LMS_n
    a_LMS_2 = p_LMS / LMS_r

    A_1 = row_as_diagonal(a_LMS_1)
    A_2 = row_as_diagonal(a_LMS_2)

    LMSp_1 = vector_dot(A_1, LMS_1)

    c = 0.219 - 0.0784 * np.log10(Y_n)
    C = row_as_diagonal(tstack([c, c, c]))

    LMS_a = vector_dot(C, LMSp_1)
    LMSp_2 = vector_dot(np.linalg.inv(C), LMS_a)

    LMS_c = vector_dot(np.linalg.inv(A_2), LMSp_2)
    XYZ_c = vector_dot(MATRIX_RGB_TO_XYZ_FAIRCHILD1990, LMS_c)

    return from_range_100(XYZ_c)
コード例 #50
0
def logarithmic_function_basic(
    x: FloatingOrArrayLike,
    style: Union[Literal["log10", "antiLog10", "log2", "antiLog2", "logB",
                         "antiLogB"], str, ] = "log2",
    base: Integer = 2,
) -> FloatingOrNDArray:
    """
    Define the basic logarithmic function.

    Parameters
    ----------
    x
        The data to undergo basic logarithmic conversion.
    style
        Defines the behaviour for the logarithmic function to operate:

        -   *log10*: Applies a base 10 logarithm to the passed value.
        -   *antiLog10*: Applies a base 10 anti-logarithm to the passed value.
        -   *log2*: Applies a base 2 logarithm to the passed value.
        -   *antiLog2*: Applies a base 2 anti-logarithm to the passed value.
        -   *logB*: Applies an arbitrary base logarithm to the passed value.
        -   *antiLogB*: Applies an arbitrary base anti-logarithm to the passed
            value.
    base
        Logarithmic base used for the conversion.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Logarithmically converted data.

    Examples
    --------
    The basic logarithmic function *styles* operate as follows:

    >>> logarithmic_function_basic(0.18)  # doctest: +ELLIPSIS
    -2.4739311...
    >>> logarithmic_function_basic(0.18, 'log10')  # doctest: +ELLIPSIS
    -0.7447274...
    >>> logarithmic_function_basic(  # doctest: +ELLIPSIS
    ...    0.18, 'logB', 3)
    -1.5608767...
    >>> logarithmic_function_basic(  # doctest: +ELLIPSIS
    ...    -2.473931188332412, 'antiLog2')
    0.18000000...
    >>> logarithmic_function_basic(  # doctest: +ELLIPSIS
    ...    -0.7447274948966939, 'antiLog10')
    0.18000000...
    >>> logarithmic_function_basic(  # doctest: +ELLIPSIS
    ...    -1.5608767950073117, 'antiLogB', 3)
    0.18000000...
    """

    x = as_float_array(x)
    style = validate_method(
        style,
        ["log10", "antiLog10", "log2", "antiLog2", "logB", "antiLogB"],
        '"{0}" style is invalid, it must be one of {1}!',
    )

    if style == "log10":
        return as_float(np.where(x >= FLT_MIN, np.log10(x), np.log10(FLT_MIN)))
    elif style == "antilog10":
        return as_float(10**x)
    elif style == "log2":
        return as_float(np.where(x >= FLT_MIN, np.log2(x), np.log2(FLT_MIN)))
    elif style == "antilog2":
        return as_float(2**x)
    elif style == "logb":
        return as_float(np.log(x) / np.log(base))
    else:  # style == 'antilogb'
        return as_float(base**x)
コード例 #51
0
ファイル: ycbcr.py プロジェクト: vidakDK/colour
def YCbCr_to_RGB(YCbCr,
                 K=YCBCR_WEIGHTS['ITU-R BT.709'],
                 in_bits=8,
                 in_legal=True,
                 in_int=False,
                 out_bits=10,
                 out_legal=False,
                 out_int=False,
                 **kwargs):
    """
    Converts an array of *Y'CbCr* colour encoding values to the corresponding
    *R'G'B'* values array.

    Parameters
    ----------
    YCbCr : array_like
        Input *Y'CbCr* colour encoding array of integer or float values.
    K : array_like, optional
        Luma weighting coefficients of red and blue. See
        :attr:`colour.YCBCR_WEIGHTS` for presets. Default is
        *(0.2126, 0.0722)*, the weightings for *ITU-R BT.709*.
    in_bits : int, optional
        Bit depth for integer input, or used in the calculation of the
        denominator for legal range float values, i.e. 8-bit means the float
        value for legal white is *235 / 255*. Default is *10*.
    in_legal : bool, optional
        Whether to treat the input values as legal range. Default is *False*.
    in_int : bool, optional
        Whether to treat the input values as ``in_bits`` integer code values.
        Default is *False*.
    out_bits : int, optional
        Bit depth for integer output, or used in the calculation of the
        denominator for legal range float values, i.e. 8-bit means the float
        value for legal white is *235 / 255*. Ignored if ``out_legal`` and
        ``out_int`` are both *False*. Default is *8*.
    out_legal : bool, optional
        Whether to return legal range values. Default is *True*.
    out_int : bool, optional
        Whether to return values as ``out_bits`` integer code values. Default
        is *False*.

    Other Parameters
    ----------------
    in_range : array_like, optional
        Array overriding the computed range such as
        *in_range = (Y_min, Y_max, C_min, C_max)*. If ``in_range`` is
        undefined, *Y_min*, *Y_max*, *C_min* and *C_max* will be computed using
        :func:`colour.models.rgb.ycbcr.YCbCr_ranges` definition.
    out_range : array_like, optional
        Array overriding the computed range such as
        *out_range = (RGB_min, RGB_max)*. If ``out_range`` is undefined,
        *RGB_min* and *RGB_max* will be computed using :func:`colour.CV_range`
        definition.

    Returns
    -------
    ndarray
        *R'G'B'* array of integer or float values.

    Notes
    -----

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

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

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

    Warning
    -------
    For *Recommendation ITU-R BT.2020*, :func:`colour.YCbCr_to_RGB`
    definition is only applicable to the non-constant luminance implementation.
    :func:`colour.YcCbcCrc_to_RGB` definition should be used for the constant
    luminance case as per :cite:`InternationalTelecommunicationUnion2015h`.

    References
    ----------
    :cite:`InternationalTelecommunicationUnion2011e`,
    :cite:`InternationalTelecommunicationUnion2015i`,
    :cite:`SocietyofMotionPictureandTelevisionEngineers1999b`,
    :cite:`Wikipedia2004d`

    Examples
    --------
    >>> YCbCr = np.array([502, 512, 512])
    >>> YCbCr_to_RGB(YCbCr, in_bits=10, in_legal=True, in_int=True)
    array([ 0.5,  0.5,  0.5])
    """

    if in_int:
        YCbCr = as_float_array(YCbCr)
    else:
        YCbCr = to_domain_1(YCbCr)

    Y, Cb, Cr = tsplit(YCbCr.astype(DEFAULT_FLOAT_DTYPE))
    Kr, Kb = K
    Y_min, Y_max, C_min, C_max = kwargs.get(
        'in_range', YCbCr_ranges(in_bits, in_legal, in_int))
    RGB_min, RGB_max = kwargs.get('out_range',
                                  CV_range(out_bits, out_legal, out_int))

    Y -= Y_min
    Cb -= (C_max + C_min) / 2
    Cr -= (C_max + C_min) / 2
    Y *= 1 / (Y_max - Y_min)
    Cb *= 1 / (C_max - C_min)
    Cr *= 1 / (C_max - C_min)
    R = Y + (2 - 2 * Kr) * Cr
    B = Y + (2 - 2 * Kb) * Cb
    G = (Y - Kr * R - Kb * B) / (1 - Kr - Kb)

    RGB = tstack([R, G, B])
    RGB *= RGB_max - RGB_min
    RGB += RGB_min
    RGB = np.round(RGB).astype(DEFAULT_INT_DTYPE) if out_int else from_range_1(
        RGB)

    return RGB
コード例 #52
0
ファイル: ciecam02.py プロジェクト: JSHpuff/colour
def XYZ_to_CIECAM02(XYZ,
                    XYZ_w,
                    L_A,
                    Y_b,
                    surround=VIEWING_CONDITIONS_CIECAM02['Average'],
                    discount_illuminant=False):
    """
    Computes the *CIECAM02* colour appearance model correlates from given
    *CIE XYZ* tristimulus values.

    This is the *forward* implementation.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of test sample / stimulus.
    XYZ_w : array_like
        *CIE XYZ* tristimulus values of reference white.
    L_A : numeric or array_like
        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 : numeric or array_like
        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 : InductionFactors_CIECAM02, optional
        Surround viewing conditions induction factors.
    discount_illuminant : bool, optional
        Truth value indicating if the illuminant should be discounted.

    Returns
    -------
    CAM_Specification_CIECAM02
        *CIECAM02* 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_CIECAM02.J`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.C`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.h`` | [0, 360]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.s`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.Q`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.M`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.H`` | [0, 400]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+

    References
    ----------
    :cite:`Fairchild2004c`, :cite:`Luo2013`, :cite:`Moroneya`,
    :cite:`Wikipedia2007a`

    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_CIECAM02['Average']
    >>> XYZ_to_CIECAM02(XYZ, XYZ_w, L_A, Y_b, surround)  # doctest: +ELLIPSIS
    CAM_Specification_CIECAM02(J=41.7310911..., C=0.1047077..., \
h=219.0484326..., s=2.3603053..., Q=195.3713259..., M=0.1088421..., \
H=278.0607358..., 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)

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

    # Converting *CIE XYZ* tristimulus values to *CMCCAT2000* transform
    # sharpened *RGB* values.
    RGB = vector_dot(CAT_CAT02, XYZ)
    RGB_w = vector_dot(CAT_CAT02, XYZ_w)

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

    # Computing full chromatic adaptation.
    RGB_c = full_chromatic_adaptation_forward(RGB, RGB_w, Y_w, D)
    RGB_wc = full_chromatic_adaptation_forward(RGB_w, RGB_w, Y_w, D)

    # Converting to *Hunt-Pointer-Estevez* colourspace.
    RGB_p = RGB_to_rgb(RGB_c)
    RGB_pw = RGB_to_rgb(RGB_wc)

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

    # 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)

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

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

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

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

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

    # 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_CIECAM02(
        from_range_100(J), from_range_100(C), from_range_degrees(h),
        from_range_100(s), from_range_100(Q), from_range_100(M),
        from_range_degrees(H, 400), None)
コード例 #53
0
def oetf_ARIBSTDB67(
    E: FloatingOrArrayLike,
    r: FloatingOrArrayLike = 0.5,
    constants: Structure = CONSTANTS_ARIBSTDB67,
) -> FloatingOrNDArray:
    """
    Define *ARIB STD-B67 (Hybrid Log-Gamma)* opto-electrical transfer
    function (OETF).

    Parameters
    ----------
    E
        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
        Video level corresponding to reference white level.
    constants
        *ARIB STD-B67 (Hybrid Log-Gamma)* constants.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.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]        |
    +------------+-----------------------+---------------+

    -   This definition uses the *mirror* negative number handling mode of
        :func:`colour.models.gamma_function` definition to the sign of negative
        numbers.

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

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

    E = to_domain_1(E)
    r = as_float_array(r)

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

    E_p = np.where(E <= 1, r * gamma_function(E, 0.5, "mirror"),
                   a * np.log(E - b) + c)

    return as_float(from_range_1(E_p))
コード例 #54
0
def lightness(Y, method='CIE 1976', **kwargs):
    """
    Returns the *Lightness* :math:`L` using given method.

    Parameters
    ----------
    Y : numeric or array_like
        *luminance* :math:`Y`.
    method : unicode, optional
        **{'CIE 1976', 'Glasser 1958', 'Wyszecki 1963', 'Fairchild 2010',
        'Fairchild 2011'}**,
        Computation method.

    Other Parameters
    ----------------
    Y_n : numeric or array_like, optional
        {:func:`colour.colorimetry.lightness_CIE1976`},
        White reference *luminance* :math:`Y_n`.
    epsilon : numeric or array_like, optional
        {:func:`colour.colorimetry.lightness_Fairchild2010`,
        :func:`colour.colorimetry.lightness_Fairchild2011`},
        :math:`\\epsilon` exponent.

    Returns
    -------
    numeric or array_like
        *Lightness* :math:`L`.

    Notes
    -----

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

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

    References
    ----------
    :cite:`Fairchild2010`, :cite:`Fairchild2011`, :cite:`Glasser1958a`,
    :cite:`Lindbloom2003d`, :cite:`Wikipedia2007c`, :cite:`Wyszecki1963b`,
    :cite:`Wyszecki2000bd`

    Examples
    --------
    >>> lightness(12.19722535)  # doctest: +ELLIPSIS
    41.5278758...
    >>> lightness(12.19722535, Y_n=100)  # doctest: +ELLIPSIS
    41.5278758...
    >>> lightness(12.19722535, Y_n=95)  # doctest: +ELLIPSIS
    42.5199307...
    >>> lightness(12.19722535, method='Glasser 1958')  # doctest: +ELLIPSIS
    39.8351264...
    >>> lightness(12.19722535, method='Wyszecki 1963')  # doctest: +ELLIPSIS
    40.5475745...
    >>> lightness(12.19722535, epsilon=0.710, method='Fairchild 2011')
    ... # doctest: +ELLIPSIS
    29.8295108...
    """

    Y = as_float_array(Y)

    function = LIGHTNESS_METHODS[method]

    domain_range_reference = get_domain_range_scale() == 'reference'
    domain_1 = (lightness_Fairchild2010, lightness_Fairchild2011)

    if function in domain_1 and domain_range_reference:
        Y = Y / 100

    return function(Y, **filter_kwargs(function, **kwargs))
コード例 #55
0
def exponent_hdr_CIELab(Y_s, Y_abs, method='Fairchild 2011'):
    """
    Computes *hdr-CIELAB* colourspace *Lightness* :math:`\\epsilon` exponent
    using *Fairchild and Wyble (2010)* or *Fairchild and Chen (2011)* method.

    Parameters
    ----------
    Y_s : numeric or array_like
        Relative luminance :math:`Y_s` of the surround.
    Y_abs : numeric or array_like
        Absolute luminance :math:`Y_{abs}` of the scene diffuse white in
        :math:`cd/m^2`.
    method : unicode, optional
        **{'Fairchild 2011', 'Fairchild 2010'}**,
        Computation method.

    Returns
    -------
    array_like
        *hdr-CIELAB* colourspace *Lightness* :math:`\\epsilon` exponent.

    Notes
    -----

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

    Examples
    --------
    >>> exponent_hdr_CIELab(0.2, 100)  # doctest: +ELLIPSIS
    0.4738510...
    >>> exponent_hdr_CIELab(0.2, 100, method='Fairchild 2010')
    ... # doctest: +ELLIPSIS
    1.8360198...
    """

    Y_s = to_domain_1(Y_s)
    Y_abs = as_float_array(Y_abs)

    method_l = method.lower()
    assert method.lower() in [
        m.lower() for m in HDR_CIELAB_METHODS
    ], ('"{0}" method is invalid, must be one of {1}!'.format(
        method, HDR_CIELAB_METHODS))

    if method_l == 'fairchild 2010':
        epsilon = 1.50
    else:
        epsilon = 0.58

    sf = 1.25 - 0.25 * (Y_s / 0.184)
    lf = np.log(318) / np.log(Y_abs)
    if method_l == 'fairchild 2010':
        epsilon *= sf * lf
    else:
        epsilon /= sf * lf

    return epsilon
コード例 #56
0
ファイル: models.py プロジェクト: ajun73/Work_Code
def plot_RGB_chromaticities_in_chromaticity_diagram(
        RGB,
        colourspace='sRGB',
        chromaticity_diagram_callable=(
            plot_RGB_colourspaces_in_chromaticity_diagram),
        method='CIE 1931',
        scatter_parameters=None,
        **kwargs):
    """
    Plots given *RGB* colourspace array in the *Chromaticity Diagram* according
    to given method.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    colourspace : optional, unicode
        *RGB* colourspace of the *RGB* array.
    chromaticity_diagram_callable : callable, optional
        Callable responsible for drawing the *Chromaticity Diagram*.
    method : unicode, optional
        **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**,
        *Chromaticity Diagram* method.
    scatter_parameters : dict, optional
        Parameters for the :func:`plt.scatter` definition, if ``c`` is set to
        *RGB*, the scatter will use given ``RGB`` colours.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
        :func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definitions.

    Returns
    -------
    tuple
        Current figure and axes.

    Examples
    --------
    >>> RGB = np.random.random((128, 128, 3))
    >>> plot_RGB_chromaticities_in_chromaticity_diagram(
    ...     RGB, 'ITU-R BT.709')
    ... # doctest: +SKIP

    .. image:: ../_static/Plotting_\
Plot_RGB_Chromaticities_In_Chromaticity_Diagram_Plot.png
        :align: center
        :alt: plot_RGB_chromaticities_in_chromaticity_diagram
    """

    RGB = as_float_array(RGB).reshape(-1, 3)

    settings = {'uniform': True}
    settings.update(kwargs)

    figure, axes = artist(**settings)

    method = method.upper()

    scatter_settings = {
        's': 40,
        'c': 'RGB',
        'marker': 'o',
        'alpha': 0.85,
    }
    if scatter_parameters is not None:
        scatter_settings.update(scatter_parameters)

    settings = dict(kwargs)
    settings.update({'axes': axes, 'standalone': False})

    colourspace = first_item(filter_RGB_colourspaces(colourspace).values())
    settings['colourspaces'] = (['^{0}$'.format(colourspace.name)] +
                                settings.get('colourspaces', []))

    chromaticity_diagram_callable(**settings)

    use_RGB_colours = scatter_settings['c'].upper() == 'RGB'
    if use_RGB_colours:
        RGB = RGB[RGB[:, 1].argsort()]
        scatter_settings['c'] = np.clip(
            RGB_to_RGB(RGB,
                       colourspace,
                       COLOUR_STYLE_CONSTANTS.colour.colourspace,
                       apply_encoding_cctf=True).reshape(-1, 3), 0, 1)

    XYZ = RGB_to_XYZ(RGB, colourspace.whitepoint, colourspace.whitepoint,
                     colourspace.RGB_to_XYZ_matrix)

    if method == 'CIE 1931':
        ij = XYZ_to_xy(XYZ, colourspace.whitepoint)
    elif method == 'CIE 1960 UCS':
        ij = UCS_to_uv(XYZ_to_UCS(XYZ))

    elif method == 'CIE 1976 UCS':
        ij = Luv_to_uv(XYZ_to_Luv(XYZ, colourspace.whitepoint),
                       colourspace.whitepoint)

    axes.scatter(ij[..., 0], ij[..., 1], **scatter_settings)

    settings.update({'standalone': True})
    settings.update(kwargs)

    return render(**settings)
コード例 #57
0
ファイル: models.py プロジェクト: ajun73/Work_Code
def plot_pointer_gamut(method='CIE 1931', **kwargs):
    """
    Plots *Pointer's Gamut* according to given method.

    Parameters
    ----------
    method : unicode, optional
        **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**,
        Plotting method.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`, :func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definitions.

    Returns
    -------
    tuple
        Current figure and axes.

    Examples
    --------
    >>> plot_pointer_gamut()  # doctest: +SKIP

    .. image:: ../_static/Plotting_Plot_Pointer_Gamut.png
        :align: center
        :alt: plot_pointer_gamut
    """

    settings = {'uniform': True}
    settings.update(kwargs)

    figure, axes = artist(**settings)

    method = method.upper()

    if method == 'CIE 1931':

        def XYZ_to_ij(XYZ, *args):
            """
            Converts given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return XYZ_to_xy(XYZ, *args)

        def xy_to_ij(xy):
            """
            Converts given *xy* chromaticity coordinates to *ij* chromaticity
            coordinates.
            """

            return xy

    elif method == 'CIE 1960 UCS':

        def XYZ_to_ij(XYZ, *args):
            """
            Converts given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return UCS_to_uv(XYZ_to_UCS(XYZ))

        def xy_to_ij(xy):
            """
            Converts given *xy* chromaticity coordinates to *ij* chromaticity
            coordinates.
            """

            return xy_to_UCS_uv(xy)

    elif method == 'CIE 1976 UCS':

        def XYZ_to_ij(XYZ, *args):
            """
            Converts given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return Luv_to_uv(XYZ_to_Luv(XYZ, *args), *args)

        def xy_to_ij(xy):
            """
            Converts given *xy* chromaticity coordinates to *ij* chromaticity
            coordinates.
            """

            return xy_to_Luv_uv(xy)

    else:
        raise ValueError(
            'Invalid method: "{0}", must be one of '
            '{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}'.format(
                method))

    ij = xy_to_ij(as_float_array(POINTER_GAMUT_BOUNDARIES))
    alpha_p = COLOUR_STYLE_CONSTANTS.opacity.high
    colour_p = COLOUR_STYLE_CONSTANTS.colour.darkest
    axes.plot(ij[..., 0],
              ij[..., 1],
              label='Pointer\'s Gamut',
              color=colour_p,
              alpha=alpha_p)
    axes.plot((ij[-1][0], ij[0][0]), (ij[-1][1], ij[0][1]),
              color=colour_p,
              alpha=alpha_p)

    XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA),
                     POINTER_GAMUT_ILLUMINANT)
    ij = XYZ_to_ij(XYZ, POINTER_GAMUT_ILLUMINANT)
    axes.scatter(ij[..., 0],
                 ij[..., 1],
                 alpha=alpha_p / 2,
                 color=colour_p,
                 marker='+')

    settings.update({'axes': axes})
    settings.update(kwargs)

    return render(**settings)
コード例 #58
0
ファイル: cam16.py プロジェクト: zachlewis/colour
def XYZ_to_CAM16(XYZ,
                 XYZ_w,
                 L_A,
                 Y_b,
                 surround=CAM16_VIEWING_CONDITIONS['Average'],
                 discount_illuminant=False):
    """
    Computes the *CAM16* colour appearance model correlates from given
    *CIE XYZ* tristimulus values.

    This is the *forward* implementation.

    Parameters
    ----------
    XYZ : array_like
        *CIE XYZ* tristimulus values of test sample / stimulus.
    XYZ_w : array_like
        *CIE XYZ* tristimulus values of reference white.
    L_A : numeric or array_like
        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 : numeric or array_like
        Relative luminance of background :math:`Y_b` in :math:`cd/m^2`.
    surround : CAM16_InductionFactors, optional
        Surround viewing conditions induction factors.
    discount_illuminant : bool, optional
        Truth value indicating if the illuminant should be discounted.

    Returns
    -------
    CAM16_Specification
        *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** |
    +===========================+=======================+===============+
    | ``CAM16_specification.J`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.C`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.h`` | [0, 360]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.s`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.Q`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.M`` | [0, 100]              | [0, 1]        |
    +---------------------------+-----------------------+---------------+
    | ``CAM16_specification.H`` | [0, 360]              | [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 = CAM16_VIEWING_CONDITIONS['Average']
    >>> XYZ_to_CAM16(XYZ, XYZ_w, L_A, Y_b, surround)  # doctest: +ELLIPSIS
    CAM16_Specification(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 = dot_vector(M_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 np.ones(L_A.shape))

    n, F_L, N_bb, N_cb, z = tsplit(
        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 = dot_vector(M_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 CAM16_Specification(from_range_100(J), from_range_100(C),
                               from_range_degrees(h), from_range_100(s),
                               from_range_100(Q), from_range_100(M),
                               from_range_degrees(H), None)
コード例 #59
0
ファイル: ciecam02.py プロジェクト: JSHpuff/colour
def CIECAM02_to_XYZ(specification,
                    XYZ_w,
                    L_A,
                    Y_b,
                    surround=VIEWING_CONDITIONS_CIECAM02['Average'],
                    discount_illuminant=False):
    """
    Converts from *CIECAM02* specification to *CIE XYZ* tristimulus values.

    This is the *inverse* implementation.

    Parameters
    ----------
    specification : CAM_Specification_CIECAM02
        *CIECAM02* colour appearance model specification. Correlate of
        *Lightness* :math:`J`, correlate of *chroma* :math:`C` or correlate of
        *colourfulness* :math:`M` and *hue* angle :math:`h` in degrees must be
        specified, e.g. :math:`JCh` or :math:`JMh`.
    XYZ_w : array_like
        *CIE XYZ* tristimulus values of reference white.
    L_A : numeric or array_like
        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 : numeric or array_like
        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 : InductionFactors_CIECAM02, optional
        Surround viewing conditions.
    discount_illuminant : bool, optional
        Discount the illuminant.

    Returns
    -------
    XYZ : ndarray
        *CIE XYZ* tristimulus values.

    Raises
    ------
    ValueError
        If neither *C* or *M* correlates have been defined in the
        ``CAM_Specification_CIECAM02`` argument.

    Warnings
    --------
    The output range of that definition is non standard!

    Notes
    -----

    +----------------------------------+-----------------------\
+---------------+
    | **Domain**                       | **Scale - Reference** \
| **Scale - 1** |
    +==================================+=======================\
+===============+
    | ``CAM_Specification_CIECAM02.J`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.C`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.h`` | [0, 360]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.s`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.Q`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.M`` | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``CAM_Specification_CIECAM02.H`` | [0, 360]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+
    | ``XYZ_w``                        | [0, 100]              \
| [0, 1]        |
    +----------------------------------+-----------------------\
+---------------+

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

    -   ``CAM_Specification_CIECAM02`` can also be passed as a compatible
        argument to :func:`colour.utilities.as_namedtuple` definition.

    References
    ----------
    :cite:`Fairchild2004c`, :cite:`Luo2013`, :cite:`Moroneya`,
    :cite:`Wikipedia2007a`

    Examples
    --------
    >>> specification = CAM_Specification_CIECAM02(J=41.731091132513917,
    ...                                        C=0.104707757171031,
    ...                                        h=219.048432658311780)
    >>> XYZ_w = np.array([95.05, 100.00, 108.88])
    >>> L_A = 318.31
    >>> Y_b = 20.0
    >>> CIECAM02_to_XYZ(specification, XYZ_w, L_A, Y_b)  # doctest: +ELLIPSIS
    array([ 19.01...,  20...  ,  21.78...])
    """

    J, C, h, _s, _Q, M, _H, _HC = as_namedtuple(specification,
                                                CAM_Specification_CIECAM02)
    J = to_domain_100(J)
    C = to_domain_100(C) if C is not None else C
    h = to_domain_degrees(h)
    M = to_domain_100(M) if M is not None else M
    L_A = as_float_array(L_A)
    XYZ_w = to_domain_100(XYZ_w)
    _X_w, Y_w, _Z_w = tsplit(XYZ_w)

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

    if C is None and M is not None:
        C = M / spow(F_L, 0.25)
    elif C is None:
        raise ValueError('Either "C" or "M" correlate must be defined in '
                         'the "CAM_Specification_CIECAM02" argument!')

    # Converting *CIE XYZ* tristimulus values to *CMCCAT2000* transform
    # sharpened *RGB* values.
    RGB_w = vector_dot(CAT_CAT02, XYZ_w)

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

    # Computing full chromatic adaptation.
    RGB_wc = full_chromatic_adaptation_forward(RGB_w, RGB_w, Y_w, D)

    # Converting to *Hunt-Pointer-Estevez* colourspace.
    RGB_pw = RGB_to_rgb(RGB_wc)

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

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

    # Computing temporary magnitude quantity :math:`t`.
    t = temporary_magnitude_quantity_inverse(C, J, n)

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

    # Computing achromatic response :math:`A` for the stimulus.
    A = achromatic_response_inverse(A_w, J, surround.c, z)

    # Computing *P_1* to *P_3*.
    P_n = P(surround.N_c, N_cb, e_t, t, A, N_bb)
    _P_1, P_2, _P_3 = tsplit(P_n)

    # Computing opponent colour dimensions :math:`a` and :math:`b`.
    a, b = tsplit(opponent_colour_dimensions_inverse(P_n, h))

    # Computing post-adaptation non linear response compression matrix.
    RGB_a = matrix_post_adaptation_non_linear_response_compression(P_2, a, b)

    # Applying inverse post-adaptation non linear response compression.
    RGB_p = post_adaptation_non_linear_response_compression_inverse(RGB_a, F_L)

    # Converting to *Hunt-Pointer-Estevez* colourspace.
    RGB_c = rgb_to_RGB(RGB_p)

    # Applying inverse full chromatic adaptation.
    RGB = full_chromatic_adaptation_inverse(RGB_c, RGB_w, Y_w, D)

    # Converting *CMCCAT2000* transform sharpened *RGB* values to *CIE XYZ*
    # tristimulus values.
    XYZ = vector_dot(CAT02_INVERSE_CAT, RGB)

    return from_range_100(XYZ)
コード例 #60
0
def logarithmic_function_quasilog(
    x: FloatingOrArrayLike,
    style: Union[Literal["linToLog", "logToLin"], str] = "linToLog",
    base: Integer = 2,
    log_side_slope: Floating = 1,
    lin_side_slope: Floating = 1,
    log_side_offset: Floating = 0,
    lin_side_offset: Floating = 0,
) -> FloatingOrNDArray:
    """
    Define the quasilog logarithmic function.

    Parameters
    ----------
    x
        Linear/non-linear data to undergo encoding/decoding.
    style
        Defines the behaviour for the logarithmic function to operate:

        -   *linToLog*: Applies a logarithm to convert linear data to
            logarithmic data.
        -   *logToLin*: Applies an anti-logarithm to convert logarithmic
            data to linear data.
    base
        Logarithmic base used for the conversion.
    log_side_slope
        Slope (or gain) applied to the log side of the logarithmic function.
        The default value is 1.
    lin_side_slope
        Slope of the linear side of the logarithmic function. The default value
        is 1.
    log_side_offset
        Offset applied to the log side of the logarithmic function. The default
        value is 0.
    lin_side_offset
        Offset applied to the linear side of the logarithmic function. The
        default value is 0.

    Returns
    -------
    :class:`numpy.floating` or :class:`numpy.ndarray`
        Encoded/Decoded data.

    Examples
    --------
    >>> logarithmic_function_quasilog(  # doctest: +ELLIPSIS
    ...    0.18, 'linToLog')
    -2.4739311...
    >>> logarithmic_function_quasilog(  # doctest: +ELLIPSIS
    ...    -2.473931188332412, 'logToLin')
    0.18000000...
    """

    x = as_float_array(x)
    style = validate_method(
        style,
        ["lintolog", "logtolin"],
        '"{0}" style is invalid, it must be one of {1}!',
    )

    if style == "lintolog":
        return as_float(log_side_slope * (
            np.log(np.maximum(lin_side_slope * x + lin_side_offset, FLT_MIN)) /
            np.log(base)) + log_side_offset)
    else:  # style == 'logtolin'
        return as_float((base**(
            (x - log_side_offset) / log_side_slope) - lin_side_offset) /
                        lin_side_slope)