def ipt_jch(start, amount, saturation, luminosity): # Generate colors k = 360/amount colors = [(luminosity, saturation, start + i*k) for i in range(amount)] # From lch to IPT ans = ((l/100, c/100*cos(radians(h)), c/100*sin(radians(h))) for l, c, h in colors) # From IPT to XYZ1 ans = (convert_color(IPTColor(i, p, t), XYZColor, target_illuminant="d65") for i, p, t in ans) ipt_colors = (color.get_value_tuple() for color in ans) # From JCh to XYZ1 ans = (cspace_convert(color, "JCh", "XYZ1") for color in colors) jch_colors = (color.tolist() for color in ans) # Compute average ans = (((x1 + x2)/2, (y1 + y2)/2 , (z1 + z2)/2) for (x1, y1, z1), (x2, y2, z2) in zip(ipt_colors, jch_colors)) # From XYZ1 to sRGB1 ans = (cspace_convert(color, "XYZ1", "sRGB1") for color in ans) ans = ((color.tolist() for color in ans)) ans = (sRGBColor(*color) for color in ans) return to_hex_rgb(ans)
def XYZ_to_IPT(cobj, *args, **kwargs): """ Converts XYZ to IPT. NOTE: XYZ values need to be adapted to 2 degree D65 Reference: Fairchild, M. D. (2013). Color appearance models, 3rd Ed. (pp. 271-272). John Wiley & Sons. """ if cobj.illuminant != "d65" or cobj.observer != "2": raise ValueError("XYZColor for XYZ->IPT conversion needs to be D65 adapted.") xyz_values = numpy.array(cobj.get_value_tuple()) lms_values = numpy.dot(IPTColor.conversion_matrices["xyz_to_lms"], xyz_values) lms_prime = numpy.sign(lms_values) * numpy.abs(lms_values) ** 0.43 ipt_values = numpy.dot(IPTColor.conversion_matrices["lms_to_ipt"], lms_prime) return IPTColor(*ipt_values)
def ipt(l, c, h): i = l/100 p = c/100*cos(radians(h)) t = c/100*sin(radians(h)) return convert_color(IPTColor(i, p, t), sRGBColor, target_illuminant="d65")
def setUp(self): self.color = IPTColor(0.5, 0.5, 0.5)
def test_conversion_to_ipt(self): self.color.set_illuminant('D65') ipt = convert_color(self.color, IPTColor) self.assertColorMatch(ipt, IPTColor(0.5063, -0.3183, -0.1160))