-
Notifications
You must be signed in to change notification settings - Fork 0
/
color_gradient.py
72 lines (55 loc) · 2.67 KB
/
color_gradient.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import numpy as np
class Color:
def __init__(self, r, g, b):
self.r = r
self.g = g
self.b = b
def rgb(self):
return (self.r, self.g, self.b)
def bgr(self):
return (self.b, self.g, self.r)
def hex(self):
return f"#{self.r:02x}{self.g:02x}{self.b:02x}"
def __add__(self, other):
return Color(self.r + other.r, self.g + other.g, self.b + other.b)
def __mul__(self, other):
return Color(self.r * other, self.g * other, self.b * other)
def __truediv__(self, other):
return Color(self.r / other, self.g / other, self.b / other)
def __str__(self):
return f"({self.r}, {self.g}, {self.b})"
def __repr__(self):
return self.__str__()
def __eq__(self, other):
return self.r == other.r and self.g == other.g and self.b == other.b
def __hash__(self):
return hash((self.r, self.g, self.b))
class Gradient:
def __init__(self, grad: "dict[float, Color]"):
self.points = list(grad.keys())
self.colors = list(grad.values())
self.points, self.colors = zip(*sorted(zip(self.points, self.colors)))
def __call__(self, t):
if t < self.points[0]:
return self.colors[0]
if t > self.points[-1]:
return self.colors[-1]
for i in range(len(self.points) - 1):
if t >= self.points[i] and t <= self.points[i + 1]:
return self.colors[i] + (self.colors[i + 1] - self.colors[i]) * (t - self.points[i]) / (self.points[i + 1] - self.points[i])
def apply_to_grayscale_image(self, img):
zero_to_one = img.astype(np.float32).copy() / 255
result = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)
#print(np.min(zero_to_one), np.max(zero_to_one))
result[zero_to_one <= self.points[0]] = self.colors[0].bgr()
result[zero_to_one >= self.points[-1]] = self.colors[-1].bgr()
for i in range(len(self.points) - 1):
minimum = self.points[i]
maximum = self.points[i + 1]
target_indices = np.logical_and(zero_to_one > minimum, zero_to_one <= maximum)
rmin, gmin, bmin = self.colors[i].rgb()
rmax, gmax, bmax = self.colors[i + 1].rgb()
result[target_indices, 2] = rmin + (rmax - rmin) * (zero_to_one[target_indices] - minimum) / (maximum - minimum)
result[target_indices, 1] = gmin + (gmax - gmin) * (zero_to_one[target_indices] - minimum) / (maximum - minimum)
result[target_indices, 0] = bmin + (bmax - bmin) * (zero_to_one[target_indices] - minimum) / (maximum - minimum)
return result