def xyz2lab(xyz_img, white_ref=whitepoint.D50):
    """Converts from XYZ to CIELAB (aka, L*a*b*).

    The white_ref is the whitepoint of the XYZ color space, and defaults to
    D50. Use any other whitepoint.WhitePoint object as a reference if needed.
    The whitepoint values whould be on the same order as the XYZ values. For
    example, if XYZ ranges from [0..1], the whitepoint should have values close
    to 1.
    """
    #default is D50 whitepoint for XYZ colors; Lab is device independent
    assert(isinstance(xyz_img, numpy.ndarray))

    #compute the XYZ relative to the whitepoint; note that this assumes the
    #whitepoint and the XYZ have the same scale.
    X, Y, Z = imageutils.split3(xyz_img)
    xr = X / white_ref.X
    yr = Y / white_ref.Y
    zr = Z / white_ref.Z
    #note: xr, yr, zr are scaled so that they are close to [0..1] range;
    #it is possible to have values >1, that's not an error.
    fy = lab_inverse_compand(yr)
    L = 116.0 * fy - 16.0
    a = 500.0 * (lab_inverse_compand(xr) - fy)
    b = 200.0 * (fy - lab_inverse_compand(zr))
    return imageutils.cat3(L, a, b)
def luv2lch(luv_img):
    """Converts CIELUV to a LCh representation.

    L: luminance
    C: chroma
    h: hue (in radians)
    """
    assert(isinstance(luv_img, numpy.ndarray))
    L, u, v = imageutils.split3(luv_img)
    C = numpy.sqrt(u**2 + v**2)
    h = numpy.arctan2(v, u)
    return imageutils.cat3(L, C, h)
def lab2xyz(lab_img, white_ref=whitepoint.D50):
    """Converts CIELAB's L*a*b* to XYZ.

    The white_ref is the whitepoint of the XYZ color space; use any
    whitepoint.WhitePoint object as a reference if needed. The default is D50.
    """
    assert(isinstance(lab_img, numpy.ndarray))
    L, a, b = imageutils.split3(lab_img)
    fy = (L + 16.) / 116.
    fx = a / 500. + fy
    fz = fy - b / 200.
    xr = _lab_finv(fx)
    zr = _lab_finv(fz)
    yr = _lab_yinv(L)
    return imageutils.cat3(xr * white_ref.X,
                           yr * white_ref.Y,
                           zr * white_ref.Z)
def luv2xyz(luv_img, white_ref=whitepoint.D50):
    """Converts CIELUV to XYZ.

    The white_ref is the whitepoint of the XYZ colorspace, and defaults to D50.
    Use any other whitepoint.WhitePoint object as needed.
    """
    #equation from wikipedia->CIELUV
    assert(isinstance(luv_img, numpy.ndarray))
    L, u, v = imageutils.split3(luv_img)
    f_a = lambda x: ((x + 16.) / 116.) ** 3.
    f_b = lambda x: x / _lab_kappa
    threshold = _lab_kappa * _lab_epsilon
    Y = white_ref.Y * _bilevel_func(L, f_a, f_b, threshold)
    u_ref = _uprime(*white_ref.XYZ)
    v_ref = _vprime(*white_ref.XYZ)
    uprime = _safe_divide(u, 13. * L) + u_ref
    vprime = _safe_divide(v, 13. * L) + v_ref
    X = Y * _safe_divide(9. * uprime, 4. * vprime)
    Z = Y * _safe_divide(12. - 3. * uprime - 20. * vprime, 4. * vprime)
    return imageutils.cat3(X, Y, Z)
def xyz2luv(xyz_img, white_ref=whitepoint.D50):
    """Converts XYZ to CIELUV (aka, L*u*v*).

    A whitepoint reference of D50 is assumed for the XYZ values. Any other
    whitepoint, as a whitepoint.WhitePoint object, can be used -- and should
    have the same scale as the XYZ values.
    """
    assert(isinstance(xyz_img, numpy.ndarray))
    X, Y, Z = imageutils.split3(xyz_img)
    yr = Y / white_ref.Y
    uprime = _uprime(X, Y, Z)
    vprime = _vprime(X, Y, Z)
    uprime_ref = _uprime(*white_ref.XYZ)
    vprime_ref = _vprime(*white_ref.XYZ)
    f_a = lambda y: 116. * y ** (1 / 3.) - 16.
    f_b = lambda y: y * _lab_kappa
    L = _bilevel_func(yr, f_a, f_b, _lab_epsilon)
    u = 13.0 * L * (uprime - uprime_ref)
    v = 13.0 * L * (vprime - vprime_ref)
    return imageutils.cat3(L, u, v)