Exemple #1
0
def check_dimensions(data, xyzw, caller='cat.apply()'):
    """
    Check if dimensions of data and xyzw match. 
    
    | Does nothing when they do, but raises error if dimensions don't match.
    
    Args:
        :data: 
            | ndarray with color data.
        :xyzw: 
            | ndarray with white point tristimulus values.
        :caller: 
            | str with caller function for error handling, optional
        
    Returns:
        :returns: 
            | ndarray with input color data, 
            | Raises error if dimensions don't match.
    """
    xyzw = np2d(xyzw)
    data = np2d(data)
    if ((xyzw.shape[0] > 1) & (data.shape[0] != xyzw.shape[0]) &
        (data.ndim == 2)):
        raise Exception(
            '{}: Cannot match dim of xyzw with data: xyzw.shape[0]>1 & != data.shape[0]'
            .format(caller))
Exemple #2
0
def xyz_to_wuv(xyz, xyzw = _COLORTF_DEFAULT_WHITE_POINT, **kwargs):
    """
    Convert XYZ tristimulus values CIE 1964 U*V*W* color space.

    Args:
        :xyz: 
            | ndarray with tristimulus values
        :xyzw: 
            | ndarray with tristimulus values of white point, optional
              (Defaults to luxpy._COLORTF_DEFAULT_WHITE_POINT)

    Returns:
        :wuv: 
            | ndarray with W*U*V* values
    """
    xyz = np2d(xyz)
    xyzw = np2d(xyzw)
    Yuv = xyz_to_Yuv(xyz) # convert to cie 1976 u'v'
    Yuvw = xyz_to_Yuv(xyzw)
    Y, u, v = asplit(Yuv)
    Yw, uw, vw = asplit(Yuvw)
    W = 25.0*(Y**(1/3)) - 17.0
    U = 13.0*W*(u - uw)
    V = 13.0*W*(v - vw)*(2.0/3.0) # *(2/3) to  convert to cie 1960 u, v
    return ajoin((W,U,V))
Exemple #3
0
def wuv_to_xyz(wuv,xyzw = _COLORTF_DEFAULT_WHITE_POINT, **kwargs):
    """
    Convert CIE 1964 U*V*W* color space coordinates to XYZ tristimulus values.

    Args:
        :wuv: 
            | ndarray with W*U*V* values
        :xyzw: 
            | ndarray with tristimulus values of white point, optional
              (Defaults to luxpy._COLORTF_DEFAULT_WHITE_POINT)

    Returns:
        :xyz: 
            | ndarray with tristimulus values
	 """
    wuv = np2d(wuv)
    xyzw = np2d(xyzw)

    Yuvw = xyz_to_Yuv(xyzw) # convert to cie 1976 u'v'
    Yw, uw, vw = asplit(Yuvw)
    vw = (2.0/3.0)*vw # convert to cie 1960 u, v
    W,U,V = asplit(wuv)
    Y = ((W + 17.0) / 25.0)**3.0
    u = uw + U/(13.0*W)
    v = (vw + V/(13.0*W)) * (3.0/2.0)
    Yuv = ajoin((Y,u,v)) # = 1976 u',v'
    return Yuv_to_xyz(Yuv)
Exemple #4
0
 def objfcn(uv_offset, uv0, cct, duv, out = 1):#, cieobs = cieobs, wl = wl, mode = mode):
     uv0 = np2d(uv0 + uv_offset)
     Yuv0 = np.concatenate((np2d([100.0]), uv0),axis=1)
     cct_min, duv_min = xyz_to_cct(Yuv_to_xyz(Yuv0),cieobs = cieobs, out = 'cct,duv',wl = wl, mode = mode, accuracy = accuracy, force_out_of_lut = force_out_of_lut, upper_cct_max = upper_cct_max, approx_cct_temp = approx_cct_temp)
     F = np.sqrt(((100.0*(cct_min[0] - cct[0])/(cct[0]))**2.0) + (((duv_min[0] - duv[0])/(duv[0]))**2.0))
     if out == 'F':
         return F
     else:
         return np.concatenate((cct_min, duv_min, np2d(F)),axis = 1) 
Exemple #5
0
def normalize_3x3_matrix(M, xyz0=np.array([[1.0, 1.0, 1.0]])):
    """
    Normalize 3x3 matrix M to xyz0 -- > [1,1,1]
    If M.shape == (1,9): M is reshaped to (3,3)
    
    Args:
        :M: 
            | ndarray((3,3) or ndarray((1,9))
        :xyz0: 
            | 2darray, optional 
        
    Returns:
        :returns: 
            | normalized matrix such that M*xyz0 = [1,1,1]
    """
    M = np2d(M)
    if M.shape[-1] == 9:
        M = M.reshape(3, 3)
    if xyz0.shape[0] == 1:
        return np.dot(np.diagflat(1 / (np.dot(M, xyz0.T))), M)
    else:
        return np.concatenate([
            np.dot(np.diagflat(1 / (np.dot(M, xyz0[1].T))), M)
            for i in range(xyz0.shape[0])
        ],
                              axis=0).reshape(xyz0.shape[0], 3, 3)
def xyz_to_lms(xyz, cieobs=_CIEOBS, M=None, **kwargs):
    """
    Convert XYZ tristimulus values to LMS cone fundamental responses.

    Args:
        :xyz: 
            | ndarray with tristimulus values
        :cieobs: 
            | _CIEOBS or str, optional
        :M: 
            | None, optional
            | Conversion matrix for xyz to lms.
            |   If None: use the one defined by :cieobs:

    Returns:
        :lms: 
            | ndarray with LMS cone fundamental responses
    """
    xyz = np2d(xyz)

    if M is None:
        M = _CMF[cieobs]['M']

    # convert xyz to lms:
    if len(xyz.shape) == 3:
        lms = np.einsum('ij,klj->kli', M, xyz)
    else:
        lms = np.einsum('ij,lj->li', M, xyz)
    return lms
def lms_to_xyz(lms, cieobs=_CIEOBS, M=None, **kwargs):
    """
    Convert LMS cone fundamental responses to XYZ tristimulus values.

    Args:
        :lms: 
            | ndarray with LMS cone fundamental responses
        :cieobs:
            | _CIEOBS or str, optional
        :M: 
            | None, optional
            | Conversion matrix for xyz to lms.
            |   If None: use the one defined by :cieobs:

    Returns:
        :xyz: 
            | ndarray with tristimulus values
    """
    lms = np2d(lms)

    if M is None:
        M = _CMF[cieobs]['M']

    # convert from lms to xyz:
    if len(lms.shape) == 3:
        xyz = np.einsum('ij,klj->kli', np.linalg.inv(M), lms)
    else:
        xyz = np.einsum('ij,lj->li', np.linalg.inv(M), lms)

    return xyz
Exemple #8
0
def xyz_to_cct_mcamy(xyzw):
    """
    Convert XYZ tristimulus values to correlated color temperature (CCT) using 
    the mccamy approximation.
    
    | Only valid for approx. 3000 < T < 9000, if < 6500, error < 2 K.
    
    Args:
        :xyzw: 
            | ndarray of tristimulus values
        
    Returns:
        :cct: 
            | ndarray of correlated color temperatures estimates
            
    References:
        1. `McCamy, Calvin S. (April 1992). 
        "Correlated color temperature as an explicit function of 
        chromaticity coordinates".
        Color Research & Application. 17 (2): 142–144.
        <http://onlinelibrary.wiley.com/doi/10.1002/col.5080170211/abstract>`_
	 """
    Yxy = xyz_to_Yxy(xyzw)
    #axis_of_v3 = len(xyzw.shape)-1
    n = (Yxy[:, 1] - 0.3320) / (Yxy[:, 2] - 0.1858)
    return np2d(-449.0 * (n**3) + 3525.0 * (n**2) - 6823.3 * n + 5520.33).T
Exemple #9
0
def parse_x1x2_parameters(x,
                          target_shape,
                          catmode,
                          expand_2d_to_3d=None,
                          default=[1.0, 1.0]):
    """
   Parse input parameters x and make them the target_shape for easy calculation. 
   
   | Input in main function can now be a single value valid for all xyzw or 
     an array with a different value for each xyzw.
   
   Args:
        :x: 
            | list[float, float] or ndarray
        :target_shape: 
            | tuple with shape information
        :catmode: 
            | '1>0>2, optional
            |    -'1>0>2': Two-step CAT 
            |      from illuminant 1 to baseline illuminant 0 to illuminant 2.
            |    -'1>0': One-step CAT 
            |      from illuminant 1 to baseline illuminant 0.
            |    -'0>2': One-step CAT 
            |      from baseline illuminant 0 to illuminant 2. 
        :expand_2d_to_3d: 
            | None, optional 
            | [will be removed in future, serves no purpose]
            | Expand :x: from 2 to 3 dimensions.
        :default:
            | [1.0,1.0], optional
            | Default values for :x:
    
   Returns:
       :returns: 
           | (ndarray, ndarray) for x10 and x20

   """
    if x is None:
        x10 = np.ones(target_shape) * default[0]
        if (catmode == '1>0>2') | (catmode == '1>2'):
            x20 = np.ones(target_shape) * default[1]
        else:
            x20 = np.ones(target_shape) * np.nan
    else:
        x = np2d(x)
        if (catmode == '1>0>2') | (catmode == '1>2'):
            if x.shape[-1] == 2:
                x10 = np.ones(target_shape) * x[..., 0]
                x20 = np.ones(target_shape) * x[..., 1]
            else:
                x10 = np.ones(target_shape) * x
                x20 = x10.copy()
        elif catmode == '1>0':
            x10 = np.ones(target_shape) * x[..., 0]
            x10 = np.ones(target_shape) * np.nan
    return x10, x20
Exemple #10
0
def mahalanobis2(x, y=None, mu=None, sigmainv=None):
    """
    Evaluate the squared mahalanobis distance with center mu and shape 
    and orientation determined by sigmainv. 
    
    Args: 
        :x: 
            | scalar or list or ndarray (.ndim = 1 or 2) with x(y)-coordinates 
              at which to evaluate the mahalanobis distance squared.
        :y: 
            | None or scalar or list or ndarray (.ndim = 1) with y-coordinates 
              at which to evaluate the mahalanobis distance squared, optional.
            | If :y: is None, :x: should be a 2d array.
        :mu: 
            | None or ndarray (.ndim = 2) with center coordinates of the 
              mahalanobis ellipse, optional. 
            | None defaults to ndarray([0,0]).
        :sigmainv:
            | None or ndarray with 'inverse covariance matrix', optional 
            | Determines the shape and orientation of the PD.
            | None default to np.eye(2).
    Returns:
         :returns: 
             | ndarray with magnitude of mahalanobis2(x,y)

    """
    if mu is None:
        mu = np.zeros(2)
    if sigmainv is None:
        sigmainv = np.eye(2)

    x = np2d(x)

    if y is not None:
        x = x - mu[0]  # center data on mu
        y = np2d(y) - mu[1]  # center data on mu
    else:
        x = x - mu  # center data on mu
        x, y = asplit(x)
    return (sigmainv[0, 0] * (x**2.0) + sigmainv[1, 1] * (y**2.0) +
            2.0 * sigmainv[0, 1] * (x * y))
def Vrb_mb_to_xyz(Vrb,
                  cieobs=_CIEOBS,
                  scaling=[1, 1],
                  M=None,
                  Minverted=False,
                  **kwargs):
    """
    Convert V,r,b (Macleod-Boynton) color coordinates to XYZ tristimulus values.

    | Macleod Boynton: V = R+G, r = R/V, b = B/V
    | Note that R,G,B ~ L,M,S

    Args:
        :Vrb: 
            | ndarray with V,r,b (Macleod-Boynton) color coordinates
        :cieobs:
            | luxpy._CIEOBS, optional
            | CMF set to use when getting the default M, which is
              the xyz to lms conversion matrix.
        :scaling:
            | list of scaling factors for r and b dimensions.
        :M: 
            | None, optional
            | Conversion matrix for going from XYZ to RGB (LMS)
            |   If None, :cieobs: determines the M (function does inversion)
        :Minverted:
            | False, optional
            | Bool that determines whether M should be inverted.

    Returns:
        :xyz: 
            | ndarray with tristimulus values

    Reference:
        1. `MacLeod DI, and Boynton RM (1979).
           Chromaticity diagram showing cone excitation by stimuli of equal luminance.
           J. Opt. Soc. Am. 69, 1183–1186.
           <https://www.osapublishing.org/josa/abstract.cfm?uri=josa-69-8-1183>`_
    """
    Vrb = np2d(Vrb)
    RGB = np.empty(Vrb.shape)
    RGB[..., 0] = Vrb[..., 1] * Vrb[..., 0] / scaling[0]
    RGB[..., 2] = Vrb[..., 2] * Vrb[..., 0] / scaling[1]
    RGB[..., 1] = Vrb[..., 0] - RGB[..., 0]
    if M is None:
        M = _CMF[cieobs]['M']
    if Minverted == False:
        M = np.linalg.inv(M)

    if len(RGB.shape) == 3:
        return np.einsum('ij,klj->kli', M, RGB)
    else:
        return np.einsum('ij,lj->li', M, RGB)
Exemple #12
0
def xyz_to_cct_HA(xyzw):
    """
    Convert XYZ tristimulus values to correlated color temperature (CCT). 
    
    Args:
        :xyzw: 
            | ndarray of tristimulus values
        
    Returns:
        :cct: 
            | ndarray of correlated color temperatures estimates
    
    References:
        1. `Hernández-Andrés, Javier; Lee, RL; Romero, J (September 20, 1999). 
        Calculating Correlated Color Temperatures Across the Entire Gamut 
        of Daylight and Skylight Chromaticities.
        Applied Optics. 38 (27), 5703–5709. P
        <https://www.osapublishing.org/ao/abstract.cfm?uri=ao-38-27-5703>`_
            
    Notes: 
        According to paper small error from 3000 - 800 000 K, but a test with 
        Planckians showed errors up to 20% around 500 000 K; 
        e>0.05 for T>200 000, e>0.1 for T>300 000, ...
    """
    if len(xyzw.shape)>2:
        raise Exception('xyz_to_cct_HA(): Input xyzw.ndim must be <= 2 !')
        
    out_of_range_code = np.nan
    xe = [0.3366, 0.3356]
    ye = [0.1735, 0.1691]
    A0 = [-949.86315, 36284.48953]
    A1 = [6253.80338, 0.00228]
    t1 = [0.92159, 0.07861]
    A2 = [28.70599, 5.4535*1e-36]
    t2 = [0.20039, 0.01543]
    A3 = [0.00004, 0.0]
    t3 = [0.07125,1.0]
    cct_ranges = np.array([[3000.0,50000.0],[50000.0,800000.0]])
    
    Yxy = xyz_to_Yxy(xyzw)
    CCT = np.ones((1,Yxy.shape[0]))*out_of_range_code
    for i in range(2):
        n = (Yxy[:,1]-xe[i])/(Yxy[:,2]-ye[i])
        CCT_i = np2d(np.array(A0[i] + A1[i]*np.exp(np.divide(-n,t1[i])) + A2[i]*np.exp(np.divide(-n,t2[i])) + A3[i]*np.exp(np.divide(-n,t3[i]))))
        p = (CCT_i >= (1.0-0.05*(i == 0))*cct_ranges[i][0]) & (CCT_i < (1.0+0.05*(i == 0))*cct_ranges[i][1])
        CCT[p] = CCT_i[p]
        p = (CCT_i < (1.0-0.05)*cct_ranges[0][0]) #smaller than smallest valid CCT value
        CCT[p] = -1
   
    if (np.isnan(CCT.sum()) == True) | (np.any(CCT == -1)):
        print("Warning: xyz_to_cct_HA(): one or more CCTs out of range! --> (CCT < 3 kK,  CCT >800 kK) coded as (-1, NaN) 's")
    return CCT.T
def xyz_to_xyz(xyz, **kwargs):
    """
    Convert XYZ tristimulus values to XYZ tristimulus values.

    Args:
        :xyz: 
            | ndarray with tristimulus values

    Returns:
        :xyz: 
            | ndarray with tristimulus values
    """
    return np2d(xyz)
def xyz_to_wuv(xyz, xyzw=_COLORTF_DEFAULT_WHITE_POINT, **kwargs):
    """
    Convert XYZ tristimulus values CIE 1964 U*V*W* color space.

    Args:
        :xyz: 
            | ndarray with tristimulus values
        :xyzw: 
            | ndarray with tristimulus values of white point, optional
              (Defaults to luxpy._COLORTF_DEFAULT_WHITE_POINT)

    Returns:
        :wuv: 
            | ndarray with W*U*V* values
    """
    Yuv = xyz_to_Yuv(np2d(xyz))  # convert to cie 1976 u'v'
    Yuvw = xyz_to_Yuv(np2d(xyzw))
    wuv = np.empty(xyz.shape)
    wuv[..., 0] = 25.0 * (Yuv[..., 0]**(1 / 3)) - 17.0
    wuv[..., 1] = 13.0 * wuv[..., 0] * (Yuv[..., 1] - Yuvw[..., 1])
    wuv[..., 2] = 13.0 * wuv[..., 0] * (Yuv[..., 2] - Yuvw[..., 2]) * (
        2.0 / 3.0)  #*(2/3) to convert to cie 1960 u, v
    return wuv
def xyz_to_srgb(xyz, gamma=2.4, **kwargs):
    """
    Calculates IEC:61966 sRGB values from xyz.

    Args:
        :xyz: 
            | ndarray with relative tristimulus values.
        :gamma: 
            | 2.4, optional
            | compression in sRGB

    Returns:
        :rgb: 
            | ndarray with R,G,B values (uint8).
    """

    xyz = np2d(xyz)

    # define 3x3 matrix
    M = np.array([[3.2404542, -1.5371385, -0.4985314],
                  [-0.9692660, 1.8760108, 0.0415560],
                  [0.0556434, -0.2040259, 1.0572252]])

    if len(xyz.shape) == 3:
        srgb = np.einsum('ij,klj->kli', M, xyz / 100)
    else:
        srgb = np.einsum('ij,lj->li', M, xyz / 100)

    # perform clipping:
    srgb[np.where(srgb > 1)] = 1
    srgb[np.where(srgb < 0)] = 0

    # test for the dark colours in the non-linear part of the function:
    dark = np.where(srgb <= 0.0031308)

    # apply gamma function:
    g = 1 / gamma

    # and scale to range 0-255:
    rgb = srgb.copy()
    rgb = (1.055 * rgb**g - 0.055) * 255

    # non-linear bit for dark colours
    rgb[dark] = (srgb[dark].copy() * 12.92) * 255

    # clip to range:
    rgb[rgb > 255] = 255
    rgb[rgb < 0] = 0

    return rgb
Exemple #16
0
def Vrb_mb_to_xyz(Vrb,cieobs = _CIEOBS, scaling = [1,1], M = None, Minverted = False, **kwargs):
    """
    Convert V,r,b (Macleod-Boynton) color coordinates to XYZ tristimulus values.

    | Macleod Boynton: V = R+G, r = R/V, b = B/V
    | Note that R,G,B ~ L,M,S

    Args:
        :Vrb: 
            | ndarray with V,r,b (Macleod-Boynton) color coordinates
        :cieobs:
            | luxpy._CIEOBS, optional
            | CMF set to use when getting the default M, which is
              the xyz to lms conversion matrix.
        :scaling:
            | list of scaling factors for r and b dimensions.
        :M: 
            | None, optional
            | Conversion matrix for going from XYZ to RGB (LMS)
            |   If None, :cieobs: determines the M (function does inversion)
        :Minverted:
            | False, optional
            | Bool that determines whether M should be inverted.

    Returns:
        :xyz: 
            | ndarray with tristimulus values

    Reference:
        1. `MacLeod DI, and Boynton RM (1979).
           Chromaticity diagram showing cone excitation by stimuli of equal luminance.
           J. Opt. Soc. Am. 69, 1183–1186.
           <https://www.osapublishing.org/josa/abstract.cfm?uri=josa-69-8-1183>`_
    """
    Vrb = np2d(Vrb)

    V,r,b = asplit(Vrb)
    R = r*V / scaling[0]
    B = b*V / scaling[1]
    G = V-R
    if M is None:
        M = _CMF[cieobs]['M']
    if Minverted == False:
        M = np.linalg.inv(M)
    X, Y, Z = [M[i,0]*R + M[i,1]*G + M[i,2]*B for i in range(3)]
    return ajoin((X,Y,Z))
def xyz_to_Vrb_mb(xyz, cieobs=_CIEOBS, scaling=[1, 1], M=None, **kwargs):
    """
    Convert XYZ tristimulus values to V,r,b (Macleod-Boynton) color coordinates.

    | Macleod Boynton: V = R+G, r = R/V, b = B/V
    | Note that R,G,B ~ L,M,S

    Args:
        :xyz: 
            | ndarray with tristimulus values
        :cieobs: 
            | luxpy._CIEOBS, optional
            | CMF set to use when getting the default M, which is
              the xyz to lms conversion matrix.
        :scaling:
            | list of scaling factors for r and b dimensions.
        :M: 
            | None, optional
            | Conversion matrix for going from XYZ to RGB (LMS)
            |   If None, :cieobs: determines the M (function does inversion)

    Returns:
        :Vrb: 
            | ndarray with V,r,b (Macleod-Boynton) color coordinates

    Reference:
        1. `MacLeod DI, and Boynton RM (1979).
           Chromaticity diagram showing cone excitation by stimuli of equal luminance.
           J. Opt. Soc. Am. 69, 1183–1186.
           <https://www.osapublishing.org/josa/abstract.cfm?uri=josa-69-8-1183>`_
    """
    xyz = np2d(xyz)

    if M is None:
        M = _CMF[cieobs]['M']

    if len(xyz.shape) == 3:
        RGB = np.einsum('ij,klj->kli', M, xyz)
    else:
        RGB = np.einsum('ij,lj->li', M, xyz)
    Vrb = np.empty(xyz.shape)
    Vrb[..., 0] = RGB[..., 0] + RGB[..., 1]
    Vrb[..., 1] = RGB[..., 0] / Vrb[..., 0] * scaling[0]
    Vrb[..., 2] = RGB[..., 2] / Vrb[..., 0] * scaling[1]
    return Vrb
Exemple #18
0
def lab_to_xyz(lab, xyzw = None, cieobs = _CIEOBS, **kwargs):
    """
    Convert CIE 1976 L*a*b* (CIELAB) color coordinates to XYZ tristimulus values.

    Args:
        :lab: 
            | ndarray with CIE 1976 L*a*b* (CIELAB) color coordinates
        :xyzw:
            | None or ndarray with tristimulus values of white point, optional
            | None defaults to xyz of CIE D65 using the :cieobs: observer.
        :cieobs:
            | luxpy._CIEOBS, optional
            | CMF set to use when calculating xyzw.

    Returns:
        :xyz: 
            | ndarray with tristimulus values
    """
    lab = np2d(lab)

    if xyzw is None:
        xyzw = spd_to_xyz(_CIE_ILLUMINANTS['D65'],cieobs = cieobs)

    # make xyzw same shape as data:
    xyzw = xyzw*np.ones(lab.shape)

    # set knee point of function:
    k=(24/116) #(24/116)**3**(1/3)

    # get L*, a*, b* and Xw, Yw, Zw:
    L,a,b = asplit(lab)
    Xw,Yw,Zw = asplit(xyzw)

    fy = (L + 16.0) / 116.0
    fx = a / 500.0 + fy
    fz = fy - b/200.0

    # apply 3rd power:
    X,Y,Z = [xw*(x**3.0) for (x,xw) in ((fx,Xw),(fy,Yw),(fz,Zw))]

    # Now calculate T where T/Tn is below the knee point:
    p,q,r = [np.where(x<k) for x in (fx,fy,fz)]
    X[p],Y[q],Z[r] = [np.squeeze(xw[xp]*((x[xp] - 16.0/116.0) / (841/108))) for (x,xw,xp) in ((fx,Xw,p),(fy,Yw,q),(fz,Zw,r))]

    return ajoin((X,Y,Z))
Exemple #19
0
def normalize_3x3_matrix(M, xyz0 = np.array([[1.0,1.0,1.0]])):
    """
    Normalize 3x3 matrix M to xyz0 -- > [1,1,1]
    If M.shape == (1,9): M is reshaped to (3,3)
    
    Args:
        :M: 
            | ndarray((3,3) or ndarray((1,9))
        :xyz0: 
            | 2darray, optional 
        
    Returns:
        :returns: 
            | normalized matrix such that M*xyz0 = [1,1,1]
    """
    M = np2d(M)
    if M.shape[-1]==9:
        M = M.reshape(3,3)
    return np.dot(np.diagflat(1/(np.dot(M,xyz0.T))),M)
Exemple #20
0
def xyz_to_Yxy(xyz, **kwargs):
    """
    Convert XYZ tristimulus values CIE Yxy chromaticity values.

    Args:
        :xyz: 
            | ndarray with tristimulus values

    Returns:
        :Yxy: 
            | ndarray with Yxy chromaticity values
              (Y value refers to luminance or luminance factor)
    """
    xyz = np2d(xyz)
    X,Y,Z = asplit(xyz)
    sumxyz = X + Y + Z
    x = X / sumxyz
    y = Y / sumxyz
    return ajoin((Y,x,y))
Exemple #21
0
def Yxy_to_xyz(Yxy, **kwargs):
    """
    Convert CIE Yxy chromaticity values to XYZ tristimulus values.

    Args:
        :Yxy: 
            | ndarray with Yxy chromaticity values
              (Y value refers to luminance or luminance factor)

    Returns:
        :xyz: 
            | ndarray with tristimulus values
    """
    Yxy = np2d(Yxy)

    Y,x,y = asplit(Yxy)
    X = Y*x/y
    Z = Y*(1.0-x-y)/y
    return ajoin((X,Y,Z))
Exemple #22
0
def Yuv_to_xyz2(Yuv, **kwargs):
    """
    Convert CIE 1976 Yu'v' chromaticity values to XYZ tristimulus values.

    Args:
        :Yuv: 
            | ndarray with CIE 1976 Yu'v' chromaticity values
              (Y value refers to luminance or luminance factor)

    Returns:
        :xyz: 
            | ndarray with tristimulus values
    """
    Yuv = np2d(Yuv)
    xyz = Yuv.astype(np.float)
    xyz[...,1] = Yuv[...,0]
    xyz[...,0] = Yuv[...,0]*(9.0*Yuv[...,1])/(4.0*Yuv[...,2])
    xyz[...,2] = Yuv[...,0]*(12.0 - 3.0*Yuv[...,1] - 20.0*Yuv[...,2])/(4.0*Yuv[...,2])
    return xyz
def Yxy_to_xyz(Yxy, **kwargs):
    """
    Convert CIE Yxy chromaticity values to XYZ tristimulus values.

    Args:
        :Yxy: 
            | ndarray with Yxy chromaticity values
              (Y value refers to luminance or luminance factor)

    Returns:
        :xyz: 
            | ndarray with tristimulus values
    """
    Yxy = np2d(Yxy)
    xyz = np.empty(Yxy.shape)
    xyz[..., 1] = Yxy[..., 0]
    xyz[..., 0] = Yxy[..., 0] * Yxy[..., 1] / Yxy[..., 2]
    xyz[..., 2] = Yxy[..., 0] * (1.0 - Yxy[..., 1] - Yxy[..., 2]) / Yxy[..., 2]
    return xyz
Exemple #24
0
def Yuv_to_xyz(Yuv, **kwargs):
    """
    Convert CIE 1976 Yu'v' chromaticity values to XYZ tristimulus values.

    Args:
        :Yuv: 
            | ndarray with CIE 1976 Yu'v' chromaticity values
              (Y value refers to luminance or luminance factor)

    Returns:
        :xyz: 
            | ndarray with tristimulus values
    """
    Yuv = np2d(Yuv)

    Y,u,v = asplit(Yuv)
    X = Y*(9.0*u)/(4.0*v)
    Z = Y*(12.0 - 3.0*u - 20.0*v)/(4.0*v)
    return ajoin((X,Y,Z))
def xyz_to_lab(xyz, xyzw=None, cieobs=_CIEOBS, **kwargs):
    """
    Convert XYZ tristimulus values to CIE 1976 L*a*b* (CIELAB) coordinates.

    Args:
        :xyz: 
            | ndarray with tristimulus values
        :xyzw:
            | None or ndarray with tristimulus values of white point, optional
            | None defaults to xyz of CIE D65 using the :cieobs: observer.
        :cieobs:
            | luxpy._CIEOBS, optional
            | CMF set to use when calculating xyzw.

    Returns:
        :lab: 
            | ndarray with CIE 1976 L*a*b* (CIELAB) color coordinates
    """
    xyz = np2d(xyz)

    if xyzw is None:
        xyzw = spd_to_xyz(_CIE_ILLUMINANTS['D65'], cieobs=cieobs)

    # get and normalize (X,Y,Z) to white point:
    XYZr = xyz / xyzw

    # Apply cube-root compression:
    fXYZr = XYZr**(1.0 / 3.0)

    # Check for T/Tn <= 0.008856: (Note (24/116)**3 = 0.008856)
    pqr = XYZr <= (24 / 116)**3

    # calculate f(T) for T/Tn <= 0.008856: (Note:(1/3)*((116/24)**2) = 841/108 = 7.787)
    fXYZr[pqr] = ((841 / 108) * XYZr[pqr] + 16.0 / 116.0)

    # calculate L*, a*, b*:
    Lab = np.empty(xyz.shape)
    Lab[..., 0] = 116.0 * (fXYZr[..., 1]) - 16.0
    Lab[pqr[..., 1], 0] = 903.3 * XYZr[pqr[..., 1], 1]
    Lab[..., 1] = 500.0 * (fXYZr[..., 0] - fXYZr[..., 1])
    Lab[..., 2] = 200.0 * (fXYZr[..., 1] - fXYZr[..., 2])
    return Lab
Exemple #26
0
def luv_to_xyz(luv, xyzw = None, cieobs = _CIEOBS, **kwargs):
    """
    Convert CIE 1976 L*u*v* (CIELUVB) coordinates to XYZ tristimulus values.

    Args:
        :luv: 
            | ndarray with CIE 1976 L*u*v* (CIELUV) color coordinates
        :xyzw:
            | None or ndarray with tristimulus values of white point, optional
            | None defaults to xyz of CIE D65 using the :cieobs: observer.
        :cieobs: 
            | luxpy._CIEOBS, optional
            | CMF set to use when calculating xyzw.

    Returns:
        :xyz: 
            | ndarray with tristimulus values
    """
    luv = np2d(luv)


    if xyzw is None:
        xyzw = spd_to_xyz(_CIE_ILLUMINANTS['D65'],cieobs = cieobs)

    # Make xyzw same shape as luv:
    Yuvw = todim(xyz_to_Yuv(xyzw), luv.shape, equal_shape = True)

    # Get Yw, uw,vw:
    Yw,uw,vw = asplit(Yuvw)

    # calculate u'v' from u*,v*:
    L,u,v = asplit(luv)
    up,vp = [(x / (13*L)) + xw for (x,xw) in ((u,uw),(v,vw))]
    up[np.where(L == 0.0)] = 0.0
    vp[np.where(L == 0.0)] = 0.0

    fy = (L + 16.0) / 116.0
    Y = Yw*(fy**3.0)
    p = np.where((Y/Yw) < ((6.0/29.0)**3.0))
    Y[p] = Yw[p]*(L[p]/((29.0/3.0)**3.0))

    return Yuv_to_xyz(ajoin((Y,up,vp)))
Exemple #27
0
def rms(data,axis = 0, keepdims = False):
    """
    Calculate root-mean-square along axis.
    
    Args:
        :data: 
            | list of values or ndarray
        :axis:
            | 0, optional
            | Axis along which to calculate rms.
        :keepdims:
            | False or True, optional
            | Keep original dimensions of array.
    
    Returns:
        :returns:
            | ndarray with rms values.
    """
    data = np2d(data)
    return np.sqrt(np.power(data,2).mean(axis=axis, keepdims = keepdims))
Exemple #28
0
def geomean(data, axis = 0, keepdims = False):
    """
    Calculate geometric mean along axis.
    
    Args:
        :data:
            | list of values or ndarray
        :axis:
            | 0, optional
            | Axis along which to calculate geomean.
        :keepdims:
            | False or True, optional
            | Keep original dimensions of array.
    
    Returns:
        :returns:
            | ndarray with geomean values. 
    """
    data = np2d(data)
    return np.power(data.prod(axis=axis, keepdims = keepdims),1/data.shape[axis])
def xyz_to_Yuv(xyz, **kwargs):
    """
    Convert XYZ tristimulus values CIE 1976 Yu'v' chromaticity values.

    Args:
        :xyz: 
            | ndarray with tristimulus values

    Returns:
        :Yuv: 
            | ndarray with CIE 1976 Yu'v' chromaticity values
              (Y value refers to luminance or luminance factor)
    """
    xyz = np2d(xyz)
    Yuv = np.empty(xyz.shape)
    denom = xyz[..., 0] + 15.0 * xyz[..., 1] + 3.0 * xyz[..., 2]
    Yuv[..., 0] = xyz[..., 1]
    Yuv[..., 1] = 4.0 * xyz[..., 0] / denom
    Yuv[..., 2] = 9.0 * xyz[..., 1] / denom
    return Yuv
def xyz_to_Yxy(xyz, **kwargs):
    """
    Convert XYZ tristimulus values CIE Yxy chromaticity values.

    Args:
        :xyz: 
            | ndarray with tristimulus values

    Returns:
        :Yxy: 
            | ndarray with Yxy chromaticity values
              (Y value refers to luminance or luminance factor)
    """
    xyz = np2d(xyz)
    Yxy = np.empty(xyz.shape)
    sumxyz = xyz[..., 0] + xyz[..., 1] + xyz[..., 2]
    Yxy[..., 0] = xyz[..., 1]
    Yxy[..., 1] = xyz[..., 0] / sumxyz
    Yxy[..., 2] = xyz[..., 1] / sumxyz
    return Yxy