Spaces:
Sleeping
Sleeping
T.Masuda
commited on
Commit
•
9692d43
1
Parent(s):
75bb6e1
create app
Browse files- app.py +41 -0
- equalize.py +133 -0
- examples/example1.jpg +0 -0
- requirements.txt +2 -0
app.py
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from equalize import Equalize
|
3 |
+
|
4 |
+
def set_levels(image):
|
5 |
+
if image is None:
|
6 |
+
return 0, 0, 0
|
7 |
+
eq = Equalize(0, 0, 0)
|
8 |
+
eq.set_level(image)
|
9 |
+
return round(eq.level[Equalize.R], 2), round(eq.level[Equalize.G], 2), round(eq.level[Equalize.B], 2)
|
10 |
+
|
11 |
+
def equalize(image, level_r, level_g, level_b):
|
12 |
+
eq = Equalize(level_r, level_g, level_b)
|
13 |
+
dest = eq.filter(image)
|
14 |
+
return dest
|
15 |
+
|
16 |
+
with gr.Blocks(title='image color equalizer') as app:
|
17 |
+
gr.Markdown('# Image Color Equalizer')
|
18 |
+
|
19 |
+
with gr.Row():
|
20 |
+
with gr.Column():
|
21 |
+
image = gr.Image(type='pil')
|
22 |
+
level_r = gr.Slider(maximum=1.0, value=0.0, step=0.01, label='R level')
|
23 |
+
level_g = gr.Slider(maximum=1.0, value=0.0, step=0.01, label='G level')
|
24 |
+
level_b = gr.Slider(maximum=1.0, value=0.0, step=0.01, label='B level')
|
25 |
+
inputs = [image, level_r, level_g, level_b]
|
26 |
+
clear = gr.ClearButton([image, level_r, level_g, level_b])
|
27 |
+
btn = gr.Button(value='Submit')
|
28 |
+
with gr.Column():
|
29 |
+
outputs = [gr.Image(label='output', type='pil')]
|
30 |
+
|
31 |
+
clear.add(inputs + outputs)
|
32 |
+
btn.click(equalize, inputs=inputs, outputs=outputs, concurrency_limit=20)
|
33 |
+
image.change(set_levels, inputs=[image], outputs=[level_r, level_g, level_b], concurrency_limit=20)
|
34 |
+
|
35 |
+
gr.Examples(
|
36 |
+
[['examples/example1.jpg']],
|
37 |
+
[image],
|
38 |
+
#cache_examples=True
|
39 |
+
)
|
40 |
+
|
41 |
+
app.launch()
|
equalize.py
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Self
|
2 |
+
from PIL import Image
|
3 |
+
|
4 |
+
class Equalize:
|
5 |
+
MIN_LEVEL = 0.0
|
6 |
+
MAX_LEVEL = 1.0
|
7 |
+
R = 0
|
8 |
+
G = 1
|
9 |
+
B = 2
|
10 |
+
|
11 |
+
@property
|
12 |
+
def level(self):
|
13 |
+
return self._level
|
14 |
+
|
15 |
+
@property
|
16 |
+
def level_b(self) -> float:
|
17 |
+
return self._level[Equalize.B]
|
18 |
+
|
19 |
+
@property
|
20 |
+
def level_g(self) -> float:
|
21 |
+
return self._level[Equalize.G]
|
22 |
+
|
23 |
+
@property
|
24 |
+
def level_r(self) -> float:
|
25 |
+
return self._level[Equalize.R]
|
26 |
+
|
27 |
+
def __init__(self, level_b: float, level_g: float, level_r: float) -> None:
|
28 |
+
if level_b < Equalize.MIN_LEVEL or level_b > Equalize.MAX_LEVEL:
|
29 |
+
raise ValueError('level_b')
|
30 |
+
if level_g < Equalize.MIN_LEVEL or level_g > Equalize.MAX_LEVEL:
|
31 |
+
raise ValueError('level_g')
|
32 |
+
if level_r < Equalize.MIN_LEVEL or level_r > Equalize.MAX_LEVEL:
|
33 |
+
raise ValueError('level_r')
|
34 |
+
self._level = [level_b, level_g, level_r]
|
35 |
+
|
36 |
+
@staticmethod
|
37 |
+
def from_level(level: float) -> Self:
|
38 |
+
return Equalize(level, level, level)
|
39 |
+
|
40 |
+
def set_level(self, image: Image) -> Image:
|
41 |
+
src = image.convert('RGB')
|
42 |
+
dest = Image.new('RGB', src.size)
|
43 |
+
width, height = src.size
|
44 |
+
histogram = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]]
|
45 |
+
src_bytes = src.tobytes()
|
46 |
+
dest_bytes = bytearray(0 for _ in range(width * 3 * height))
|
47 |
+
for y in range(height):
|
48 |
+
for x in range(width):
|
49 |
+
i = y * width * 3 + x * 3
|
50 |
+
histogram[Equalize.R][src_bytes[i]] += 1
|
51 |
+
histogram[Equalize.G][src_bytes[i + 1]] += 1
|
52 |
+
histogram[Equalize.B][src_bytes[i + 2]] += 1
|
53 |
+
self._level = self._get_auto_level(histogram)
|
54 |
+
|
55 |
+
def filter(self, image: Image) -> Image:
|
56 |
+
src = image.convert('RGB')
|
57 |
+
dest = Image.new('RGB', src.size)
|
58 |
+
width, height = src.size
|
59 |
+
histogram = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]]
|
60 |
+
src_bytes = src.tobytes()
|
61 |
+
dest_bytes = bytearray(0 for _ in range(width * 3 * height))
|
62 |
+
for y in range(height):
|
63 |
+
for x in range(width):
|
64 |
+
i = y * width * 3 + x * 3
|
65 |
+
histogram[Equalize.R][src_bytes[i]] += 1
|
66 |
+
histogram[Equalize.G][src_bytes[i + 1]] += 1
|
67 |
+
histogram[Equalize.B][src_bytes[i + 2]] += 1
|
68 |
+
eqmap = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]]
|
69 |
+
self._create_map(histogram, eqmap)
|
70 |
+
for y in range(height):
|
71 |
+
for x in range(width):
|
72 |
+
i = y * width * 3 + x * 3
|
73 |
+
dest_bytes[i] = eqmap[Equalize.R][src_bytes[i]]
|
74 |
+
dest_bytes[i + 1] = eqmap[Equalize.G][src_bytes[i + 1]]
|
75 |
+
dest_bytes[i + 2] = eqmap[Equalize.B][src_bytes[i + 2]]
|
76 |
+
dest.frombytes(dest_bytes)
|
77 |
+
return dest
|
78 |
+
|
79 |
+
def _get_auto_level(self, histogram: [[int]]) -> [float, float, float]:
|
80 |
+
mapbgr = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]]
|
81 |
+
b = 0
|
82 |
+
g = 0
|
83 |
+
r = 0
|
84 |
+
for i in range(256):
|
85 |
+
b += histogram[Equalize.B][i]
|
86 |
+
mapbgr[Equalize.B][i] = b
|
87 |
+
g += histogram[Equalize.G][i]
|
88 |
+
mapbgr[Equalize.G][i] = g
|
89 |
+
r += histogram[Equalize.R][i]
|
90 |
+
mapbgr[Equalize.R][i] = r
|
91 |
+
|
92 |
+
threshold = 64
|
93 |
+
level = [1.0, 1.0, 1.0]
|
94 |
+
for color in range(3):
|
95 |
+
map = mapbgr[color]
|
96 |
+
low = map[0]
|
97 |
+
high = map[255]
|
98 |
+
max_diff = 0
|
99 |
+
for i in range(256):
|
100 |
+
diff = abs(int((map[i] - low) * 255 / max(high - low, 1)) - i)
|
101 |
+
if diff > max_diff:
|
102 |
+
max_diff = diff
|
103 |
+
if max_diff > threshold:
|
104 |
+
level[color] = threshold / max_diff
|
105 |
+
return level
|
106 |
+
|
107 |
+
def _create_map(self, histogram: [[int]], eqmap: [[int]]) -> None:
|
108 |
+
mapbgr = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]]
|
109 |
+
b = 0
|
110 |
+
g = 0
|
111 |
+
r = 0
|
112 |
+
for i in range(256):
|
113 |
+
b += histogram[Equalize.B][i]
|
114 |
+
mapbgr[Equalize.B][i] = b
|
115 |
+
g += histogram[Equalize.G][i]
|
116 |
+
mapbgr[Equalize.G][i] = g
|
117 |
+
r += histogram[Equalize.R][i]
|
118 |
+
mapbgr[Equalize.R][i] = r
|
119 |
+
|
120 |
+
for color in range(3):
|
121 |
+
map = mapbgr[color]
|
122 |
+
low = map[0]
|
123 |
+
high = map[255]
|
124 |
+
level = self.level[color]
|
125 |
+
for i in range(256):
|
126 |
+
c = i
|
127 |
+
if level > Equalize.MIN_LEVEL:
|
128 |
+
value = int((map[i] - low) * 255 / max(high - low, 1))
|
129 |
+
if level == Equalize.MAX_LEVEL:
|
130 |
+
c = value
|
131 |
+
else:
|
132 |
+
c = i + int((value - i) * level)
|
133 |
+
eqmap[color][i] = c
|
examples/example1.jpg
ADDED
requirements.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
pillow
|