Ejemplo n.º 1
0
 def from_xyz100(self, xyz):
     # x, y, z = (xyz.T / self.whitepoint).T
     # In nit units, ranging from 0 to 10000?
     x, y, z = xyz
     x_ = self.b * x - (self.b - 1) * z
     y_ = self.g * y - (self.g - 1) * x
     lms = npx.dot(self.M1, [x_, y_, z])
     lms_ = ((self.c1 + self.c2 * (lms / 10000)**self.n) /
             (1 + self.c3 * (lms / 10000)**self.n))**self.p
     iz, az, bz = npx.dot(self.M2, lms_)
     jz = (1 + self.d) * iz / (1 + self.d * iz) - self.d0
     return np.array([jz, az, bz])
Ejemplo n.º 2
0
 def to_xyz100(self, data, description):
     """Input: J or Q; C, M or s; H or h"""
     rgb_c = compute_to(data, description, self)
     # Step 6: Calculate R, G and B
     # rgb = (rgb_c.T / self.D_RGB).T
     # Step 7: Calculate X, Y and Z
     # xyz = self.solve_M16(rgb)
     return npx.dot(self.invM_, rgb_c)
Ejemplo n.º 3
0
 def from_xyz100(self, xyz):
     # Step 1: Calculate 'cone' responses
     # rgb = dot(self.M16, xyz)
     # Step 2: Complete the color adaptation of the illuminant in
     #         the corresponding cone response space
     # rgb_c = (rgb.T * self.D_RGB).T
     rgb_c = npx.dot(self.M_, xyz)
     return compute_from(rgb_c, self)
Ejemplo n.º 4
0
    def from_xyz100(self, xyz):
        # Step 1: Calculate 'cone' responses
        rgb = npx.dot(self.M16, xyz)
        # Step 2: Complete the color adaptation of the illuminant in
        #         the corresponding cone response space
        rgb_c = (rgb.T * self.D_RGB).T

        # Step 3: Calculate the post-adaptation cone response (resulting in
        #         dynamic range compression)
        alpha = (self.F_L * abs(rgb_c) / 100)**0.42
        rgb_a = np.sign(rgb_c) * 400 * alpha / (alpha + 27.13) + 0.1

        # Step 4
        a = npx.dot(np.array([1, -12 / 11, 1 / 11]), rgb_a)
        b = npx.dot(np.array([1 / 9, 1 / 9, -2 / 9]), rgb_a)
        # Make sure that h is in [0, 360]
        h = np.rad2deg(np.arctan2(b, a)) % 360

        # Step 5: Calculate eccentricity (e_t) and hue composition (H), using
        #         the unique hue data given in Table 2.4.
        h_ = (h - self.h[0]) % 360 + self.h[0]
        e_t = (np.cos(np.deg2rad(h_) + 2) + 3.8) / 4
        i = np.searchsorted(self.h, h_) - 1
        beta = (h_ - self.h[i]) * self.e[i + 1]
        H = self.H[i] + 100 * beta / (beta + self.e[i] * (self.h[i + 1] - h_))

        # Step 6
        A = (npx.dot(np.array([2, 1, 1 / 20]), rgb_a) - 0.305) * self.N_bb

        # Step 7: Calculate the correlate of lightness
        J = 100 * (A / self.A_w)**(self.c * self.z)

        # Step 8: Calculate the correlate of brightness
        sqrt_J_100 = np.sqrt(J / 100)
        Q = (4 / self.c) * sqrt_J_100 * (self.A_w + 4) * self.F_L**0.25

        # Step 9: Calculate the correlates of chroma (C), colourfulness (M)
        #          and saturation (s)
        #
        t = (50000 / 13 * e_t * self.N_c * self.N_cb * np.sqrt(a**2 + b**2) /
             npx.dot(np.array([1, 1, 21 / 20]), rgb_a))
        C = t**0.9 * (1.64 - 0.29**self.n)**0.73 * sqrt_J_100
        M = C * self.F_L**0.25
        s = 100 * np.sqrt(M / Q)

        return np.array([J, C, H, h, M, s, Q])
Ejemplo n.º 5
0
        def f_df(omega):
            omega = np.full_like(ap, omega)
            cbrt_RGB = np.array([omega, omega + ap, omega + bp])
            # A = np.array([[-13.7, 17.7, -4], [1.7, 8, -9.7], [0.0, 1.0, 0.0]])
            # Ainv = np.linalg.inv(A)
            # rhs = np.array(
            #     [np.full(omega.shape, a), np.full(omega.shape, b), omega]
            # )
            # cbrt_RGB = dot(Ainv, rhs)
            # # a = -13.7 * np.cbrt(R) + 17.7 * np.cbrt(G) - 4 * np.cbrt(B)
            # # b = 1.7 * np.cbrt(R) + 8 * np.cbrt(G) - 9.7 * np.cbrt(B)

            RGB = cbrt_RGB**3
            xyz100 = npx.dot(self.Minv, RGB)

            X, Y, _ = xyz100
            sum_xyz = np.sum(xyz100, axis=0)
            x = X / sum_xyz
            y = Y / sum_xyz
            K = (4.4934 * x**2 + 4.3034 * y**2 - 4.276 * x * y - 1.3744 * x -
                 2.5643 * y + 1.8103)
            f = Y * K - Y0

            # df/domega
            # dcbrt_RGB = 1.0
            # dRGB = 3 * cbrt_RGB ** 2 * dcbrt_RGB
            dRGB = 3 * cbrt_RGB**2
            dxyz100 = npx.dot(self.Minv, dRGB)

            dX, dY, _ = dxyz100
            dsum_xyz = np.sum(dxyz100, axis=0)
            dx = (dX * sum_xyz - X * dsum_xyz) / sum_xyz**2
            dy = (dY * sum_xyz - Y * dsum_xyz) / sum_xyz**2
            dK = (4.4934 * 2 * x * dx + 4.3034 * 2 * y * dy - 4.276 *
                  (dx * y + x * dy) - 1.3744 * dx - 2.5643 * dy)
            df = dY * K + Y * dK
            return f, df, xyz100
Ejemplo n.º 6
0
 def to_xyz100(self, srgb1_linear):
     # Note: The Y value is often used for grayscale conversion.
     # 0.2126 * R_linear + 0.7152 * G_linear + 0.0722 * B_linear
     return 100 * npx.dot(self.invM, srgb1_linear)
Ejemplo n.º 7
0
 def to_xyz100(self, lab):
     return npx.dot(self.M1inv, npx.dot(self.M2inv, lab)**3) * 100
Ejemplo n.º 8
0
 def from_xyz100(self, xyz100):
     xyz = np.asarray(xyz100) / 100
     return npx.dot(self.M2, np.cbrt(npx.dot(self.M1, xyz)))
Ejemplo n.º 9
0
    def to_xyz100(self, data, description):
        """Input: J or Q; C, M or s; H or h"""
        if description[0] == "J":
            J = data[0]
            # Q perhaps needed for C
            Q = (4 / self.c) * np.sqrt(
                J / 100) * (self.A_w + 4) * self.F_L**0.25
        else:
            # Step 1–1: Compute J from Q (if start from Q)
            assert description[0] == "Q"
            Q = data[0]
            J = 6.25 * (self.c * Q / (self.A_w + 4) / self.F_L**0.25)**2

        # Step 1–2: Calculate C from M or s
        if description[1] == "C":
            C = data[1]
        elif description[1] == "M":
            M = data[1]
            C = M / self.F_L**0.25
        else:
            assert description[1] == "s"
            s = data[1]
            C = (s / 100)**2 * Q / self.F_L**0.25

        if description[2] == "h":
            h = data[2]
        else:
            assert description[2] == "H"
            # Step 1–3: Calculate h from H (if start from H)
            H = data[2]
            i = np.searchsorted(self.H, H) - 1
            Hi = self.H[i]
            hi, hi1 = self.h[i], self.h[i + 1]
            ei, ei1 = self.e[i], self.e[i + 1]
            h_ = ((H - Hi) * (ei1 * hi - ei * hi1) - 100 * hi * ei1) / (
                (H - Hi) * (ei1 - ei) - 100 * ei1)
            h = np.mod(h_, 360)

        h = np.deg2rad(h)

        # Step 2: Calculate t, et , p1, p2 and p3
        A = self.A_w * (J / 100)**(1 / self.c / self.z)

        # Step 3: Calculate a and b
        t = (C / np.sqrt(J / 100) / (1.64 - 0.29**self.n)**0.73)**(1 / 0.9)
        e_t = 0.25 * (np.cos(h + 2) + 3.8)

        one_over_t = 1 / t
        one_over_t = np.select([np.isnan(one_over_t), True],
                               [np.inf, one_over_t])

        p1 = (50000.0 / 13) * self.N_c * self.N_cb * e_t * one_over_t
        p2 = A / self.N_bb + 0.305
        p3 = 21 / 20

        sin_h = np.sin(h)
        cos_h = np.cos(h)

        num = p2 * (2 + p3) * (460.0 / 1403)
        denom_part2 = (2 + p3) * (220.0 / 1403)
        denom_part3 = (-27.0 / 1403) + p3 * (6300.0 / 1403)

        a = np.empty_like(h)
        b = np.empty_like(h)

        small_cos = np.abs(sin_h) >= np.abs(cos_h)
        b[small_cos] = num[small_cos] / (
            p1[small_cos] / sin_h[small_cos] +
            (denom_part2 * cos_h[small_cos] / sin_h[small_cos]) + denom_part3)
        a[small_cos] = b[small_cos] * cos_h[small_cos] / sin_h[small_cos]
        a[~small_cos] = num[~small_cos] / (
            p1[~small_cos] / cos_h[~small_cos] + denom_part2 +
            (denom_part3 * sin_h[~small_cos] / cos_h[~small_cos]))
        b[~small_cos] = a[~small_cos] * sin_h[~small_cos] / cos_h[~small_cos]

        # Step 4: Calculate RGB_a_
        rgb_a_ = (npx.dot(
            np.array([[460, 451, 288], [460, -891, -261], [460, -220, -6300]]),
            np.array([p2, a, b]),
        ) / 1403)

        # Step 5: Calculate RGB_
        rgb_c = (np.sign(rgb_a_ - 0.1) * 100 / self.F_L *
                 ((27.13 * abs(rgb_a_ - 0.1)) /
                  (400 - abs(rgb_a_ - 0.1)))**(1 / 0.42))

        # Step 6: Calculate R, G and B
        rgb = (rgb_c.T / self.D_RGB).T

        # Step 7: Calculate X, Y and Z
        xyz = npx.dot(self.invM16, rgb)
        return xyz