Exemplo n.º 1
0
def main():
    """A simple test case."""
    x = [0, 1 / 3, 1]
    y = floatX([[51, 51, 127], [51, 127, 51], [255, 102, 51]]) / 255
    # x = [0, 0.5, 1]
    # y = floatX([[20, 80, 120], [40, 60, 160], [255, 255, 200]]) / 255
    g = Gradient(x, y, bg=BgColors.LIGHT)
    x_out, y_out, _ = g.make_gradient(steps=30, bg=BgColors.LIGHT)
    g.print_stdout(x_out, y_out)
Exemplo n.º 2
0
def srgb_to_ucs(RGB, Y_w, L_A, Y_b, F, c, N_c):
    """Converts sRGB (gamma=2.2) colors to CAM02-UCS (Luo et al. 2006) Jab."""
    XYZ_w = T.dot([[1, 1, 1]], M_SRGB_to_XYZ) * Y_w
    RGB_w = T.dot(XYZ_w, M_CAT02)
    # D = T.clip(F * (1 - (1/3.6) * T.exp((-L_A - 42) / 92)), 0, 1)
    D = floatX([1, 1, 1])  # Discount the illuminant fully
    k = 1 / (5 * L_A + 1)
    D_rgb = D * Y_w / RGB_w + 1 - D
    F_L = 0.2 * k**4 * (5 * L_A) + 0.1 * (1 - k**4)**2 * (5 * L_A)**(1/3)
    n = Y_b / Y_w
    z = 1.48 + T.sqrt(n)
    N_bb = 0.725 * (1/n)**0.2
    N_cb = N_bb
    RGB_wc = D_rgb * RGB_w
    RGB_wp = T.dot(T.dot(RGB_wc, M_CAT02_inv), M_HPE)
    RGB_aw_i = (F_L * RGB_wp / 100)**0.42
    RGB_aw = 400 * RGB_aw_i / (RGB_aw_i + 27.13) + 0.1
    A_w = (T.sum(RGB_aw * [2, 1, 1/20], axis=-1) - 0.305) * N_bb

    RGB_linear = T.maximum(EPS, RGB)**2.2
    XYZ = T.dot(RGB_linear, M_SRGB_to_XYZ) * Y_w
    RGB_ = T.dot(XYZ, M_CAT02)
    RGB_c = D_rgb * RGB_
    RGB_p = T.dot(T.dot(RGB_c, M_CAT02_inv), M_HPE)
    RGB_ap_p_i = (F_L * RGB_p / 100)**0.42
    RGB_ap_n_i = (-F_L * RGB_p / 100)**0.42
    RGB_ap_p = 400 * RGB_ap_p_i / (RGB_ap_p_i + 27.13) + 0.1
    RGB_ap_n = -400 * RGB_ap_n_i / (RGB_ap_n_i + 27.13) + 0.1
    RGB_ap = T.switch(RGB_ap_p >= 0, RGB_ap_p, RGB_ap_n)

    a = T.sum(RGB_ap * [1, -12/11, 1/11], axis=-1)
    b = T.sum(RGB_ap * [1/9, 1/9, -2/9], axis=-1)
    h = T.rad2deg(T.arctan2(b, a))
    h_p = T.switch(h < 0, h + 360, h)
    e_t = (T.cos(h_p * np.pi / 180 + 2) + 3.8) / 4

    A = (T.sum(RGB_ap * [2, 1, 1/20], axis=-1) - 0.305) * N_bb
    J = 100 * T.maximum(0, A / A_w)**(c * z)
    t_num = 50000/13 * N_c * N_cb * e_t * T.sqrt(a**2 + b**2)
    t = t_num / T.sum(RGB_ap * [1, 1, 21/20], axis=-1)
    C = t**0.9 * T.sqrt(J / 100) * (1.64 - 0.29**n)**0.73
    M = C * F_L**0.25

    K_L, c_1, c_2 = 1, 0.007, 0.0228
    J_p = (1 + 100 * c_1) * J / (1 + c_1 * J)
    M_p = (1 / c_2) * T.log(1 + c_2 * M)
    a_Mp = M_p * T.cos(T.deg2rad(h_p))
    b_Mp = M_p * T.sin(T.deg2rad(h_p))
    return T.stack([J_p, a_Mp, b_Mp], axis=-1)
Exemplo n.º 3
0
def main():
    """A simple test case."""
    rgb1, rgb2 = T.matrices('rgb1', 'rgb2')
    jab1 = srgb_to_ucs(rgb1, 100, 20, 20, **Surrounds.AVERAGE)
    jab2 = srgb_to_ucs(rgb2, 100, 20, 20, **Surrounds.AVERAGE)
    loss = delta_e(jab1, jab2)**2
    grad_ = T.grad(loss, rgb2)
    grad = theano.function([rgb1, rgb2], grad_)

    # Inversion of CAM02-UCS via gradient descent
    target = floatX([[0.25, 0.25, 1]])
    x = np.zeros_like(target) + 0.5
    print(x)
    for i in range(1500):
        g = grad(target, x)
        x -= 1e-6 * g
        if i % 100 == 99:
            print(x)
Exemplo n.º 4
0
 def __init__(self,
              x,
              y,
              colorspace='rgb',
              periodic=False,
              bg=BgColors.NEUTRAL,
              compile_only=False):
     if compile_only:
         self.x, self.y, self.bg = None, None, None
         self.make_gradient()
         return
     self.y = np.atleast_2d(y)
     if self.y.ndim != 2 or self.y.shape[-1] != 3:
         raise ValueError(
             'y.ndim must be 2 and y.shape[-1] must be 3 (RGB/JMH).')
     self.x = np.linspace(0, 1, len(y)) if x is None else floatX(x)
     self.colorspace = colorspace.lower()
     self.periodic = periodic
     self.bg = bg
Exemplo n.º 5
0
def grad_request(msg, send):
    if msg['steps'] > 1024:
        send({'_': 'error', 'text': 'Limit 1024 steps.'})
        return

    parser = Parser()
    try:
        parser.parse(msg['spec'])
    except ParseBaseException as err:
        send({'_': 'error', 'text': str(err)})
        return

    if len(parser.grad_points) < 2:
        send({'_': 'error', 'text': 'At least two colors are required.'})
        return
    else:
        x = [point[0] for point in parser.grad_points]
        y = [point[1] for point in parser.grad_points]
        y = floatX(y) / 255 if parser.colorspace == 'rgb' else y
        g = Gradient(x,
                     y,
                     colorspace=parser.colorspace,
                     periodic=bool(msg['periodic']))
        x_out, y_out, s = g.make_gradient(steps=msg['steps'],
                                          interpolator=msg['interpolator'],
                                          callback=lambda x: send({
                                              '_': 'progress',
                                              'text': x
                                          }))
        send({'_': 'progress', 'text': s})
        css_data_url = 'data:text/css,' + urllib.parse.quote(
            g.to_css(x_out, y_out))
        csv_data_url = 'data:text/csv,' + urllib.parse.quote(
            g.to_csv(x_out, y_out))
        send({
            '_': 'result',
            'html': g.to_html(x_out, y_out),
            'asCSS': css_data_url,
            'asCSV': csv_data_url
        })
Exemplo n.º 6
0
    def make_gradient(self,
                      steps=30,
                      interpolator='PchipInterpolator',
                      bg=BgColors.NEUTRAL,
                      diff_weight=1e4,
                      callback=None):
        global opfunc

        start = time.perf_counter()

        def _loss(y, ideal_jab, ideal_diff):
            jab = ucs.symbolic.srgb_to_ucs(y, 80, 16,
                                           ucs.srgb_to_xyz(bg)[1] * 80,
                                           **Surrounds.AVERAGE)
            diff = jab[1:, :] - jab[:-1, :]
            ucs_loss = T.sum(T.sqr(jab - ideal_jab))
            diff_loss = T.mean(T.sqr(diff - ideal_diff))
            return ucs_loss + diff_loss * diff_weight

        if opfunc is None:
            rgb, _ideal_jab, _ideal_diff = T.matrices('rgb', 'ideal_jab',
                                                      'ideal_diff')
            loss_sym = _loss(rgb, _ideal_jab, _ideal_diff)
            grad_sym = T.grad(loss_sym, rgb)

            # Ensure this function is compiled
            ucs.srgb_to_ucs([1, 1, 1])

            print('Building opfunc()...', file=sys.stderr)
            opfunc = theano.function([rgb, _ideal_jab, _ideal_diff],
                                     [loss_sym, grad_sym],
                                     allow_input_downcast=True,
                                     on_unused_input='ignore')
            print('Done building functions in {:.3g} seconds.'.format(
                time.perf_counter() - start),
                  file=sys.stderr)

        # If the method was called only to precompile Theano functions, return early
        if self.x is None:
            return

        if self.colorspace == 'rgb':
            conds = Conditions(Y_w=100, Y_b=ucs.srgb_to_xyz(self.bg)[1] * 100)
            jmh = ucs.jab_to_jmh(ucs.srgb_to_ucs(self.y, conds))
        elif self.colorspace == 'jmh':
            jmh = self.y.copy()
            jmh[:, 2] = ucs.H_to_h(self.y[:, 2])
        else:
            raise ValueError('colorspace must be RGB or JMH')
        jmh[:, 2] = np.rad2deg(np.unwrap(np.deg2rad(jmh[:, 2])))
        if self.periodic:
            jmh[-1] = jmh[0]
            interp = interpolate.CubicSpline(self.x,
                                             jmh,
                                             axis=0,
                                             bc_type='periodic')
        else:
            if not hasattr(interpolate, interpolator):
                raise ValueError(
                    'interpolator must exist in scipy.interpolate')
            interp = getattr(interpolate, interpolator)(self.x, jmh, axis=0)
        ideal_jmh = np.zeros((steps, 3))
        x = np.linspace(self.x[0], self.x[-1], steps)
        for i, n in enumerate(x):
            ideal_jmh[i] = interp(n)
        ideal_jab = ucs.jmh_to_jab(ideal_jmh)
        ideal_diff = ideal_jab[1:, :] - ideal_jab[:-1, :]

        y = floatX(np.random.uniform(-1e-8, 1e-8, size=ideal_jab.shape)) + 0.5
        opt = AdamOptimizer(y,
                            opfunc=lambda y: opfunc(y, ideal_jab, ideal_diff),
                            proj=lambda y: np.clip(y, 0, 1))
        for i in opt:
            if i % 100 == 0:
                loss_ = float(opfunc(y, ideal_jab, ideal_diff)[0])
                if callback is not None:
                    callback('Iteration {:d}, loss = {:.3f}'.format(i, loss_))

        # i = 0
        # y_shape = y.shape
        # def lbfgs_callback(y_opt):
        #     nonlocal i
        #     i += 1
        #     if i % 100 == 0:
        #         loss_ = float(opfunc(y_opt.reshape(y_shape), ideal_jab, ideal_diff)[0])
        #         if callback is not None:
        #             callback('Iteration {:d}, loss = {:.3f}'.format(i, loss_))

        # y = lbfgs(y, lambda y: opfunc(y, ideal_jab, ideal_diff), callback=lbfgs_callback)

        done = time.perf_counter()
        s = (
            'Loss was {:.3f} after {:d} iterations; make_gradient() took {:.3f} seconds.'
        ).format(
            float(opfunc(y, ideal_jab, ideal_diff)[0]),
            i,
            done - start,
        )
        return x, y, s
Exemplo n.º 7
0
class BgColors:
    """Specifies three different background colors that work well with CIECAM02."""
    DARK = floatX([0.2] * 3)
    NEUTRAL = floatX([0.5] * 3)
    LIGHT = floatX([0.8] * 3)