Spaces:
Sleeping
Sleeping
from typing import Self | |
from PIL import Image | |
class Equalize: | |
MIN_LEVEL = 0.0 | |
MAX_LEVEL = 1.0 | |
R = 0 | |
G = 1 | |
B = 2 | |
def level(self): | |
return self._level | |
def level_b(self) -> float: | |
return self._level[Equalize.B] | |
def level_g(self) -> float: | |
return self._level[Equalize.G] | |
def level_r(self) -> float: | |
return self._level[Equalize.R] | |
def __init__(self, level_b: float, level_g: float, level_r: float) -> None: | |
if level_b < Equalize.MIN_LEVEL or level_b > Equalize.MAX_LEVEL: | |
raise ValueError('level_b') | |
if level_g < Equalize.MIN_LEVEL or level_g > Equalize.MAX_LEVEL: | |
raise ValueError('level_g') | |
if level_r < Equalize.MIN_LEVEL or level_r > Equalize.MAX_LEVEL: | |
raise ValueError('level_r') | |
self._level = [level_b, level_g, level_r] | |
def from_level(level: float) -> Self: | |
return Equalize(level, level, level) | |
def set_level(self, image: Image) -> Image: | |
src = image.convert('RGB') | |
dest = Image.new('RGB', src.size) | |
width, height = src.size | |
histogram = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]] | |
src_bytes = src.tobytes() | |
dest_bytes = bytearray(0 for _ in range(width * 3 * height)) | |
for y in range(height): | |
for x in range(width): | |
i = y * width * 3 + x * 3 | |
histogram[Equalize.R][src_bytes[i]] += 1 | |
histogram[Equalize.G][src_bytes[i + 1]] += 1 | |
histogram[Equalize.B][src_bytes[i + 2]] += 1 | |
self._level = self._get_auto_level(histogram) | |
def filter(self, image: Image) -> Image: | |
src = image.convert('RGB') | |
dest = Image.new('RGB', src.size) | |
width, height = src.size | |
histogram = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]] | |
src_bytes = src.tobytes() | |
dest_bytes = bytearray(0 for _ in range(width * 3 * height)) | |
for y in range(height): | |
for x in range(width): | |
i = y * width * 3 + x * 3 | |
histogram[Equalize.R][src_bytes[i]] += 1 | |
histogram[Equalize.G][src_bytes[i + 1]] += 1 | |
histogram[Equalize.B][src_bytes[i + 2]] += 1 | |
eqmap = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]] | |
self._create_map(histogram, eqmap) | |
for y in range(height): | |
for x in range(width): | |
i = y * width * 3 + x * 3 | |
dest_bytes[i] = eqmap[Equalize.R][src_bytes[i]] | |
dest_bytes[i + 1] = eqmap[Equalize.G][src_bytes[i + 1]] | |
dest_bytes[i + 2] = eqmap[Equalize.B][src_bytes[i + 2]] | |
dest.frombytes(dest_bytes) | |
return dest | |
def _get_auto_level(self, histogram: [[int]]) -> [float, float, float]: | |
mapbgr = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]] | |
b = 0 | |
g = 0 | |
r = 0 | |
for i in range(256): | |
b += histogram[Equalize.B][i] | |
mapbgr[Equalize.B][i] = b | |
g += histogram[Equalize.G][i] | |
mapbgr[Equalize.G][i] = g | |
r += histogram[Equalize.R][i] | |
mapbgr[Equalize.R][i] = r | |
threshold = 64 | |
level = [1.0, 1.0, 1.0] | |
for color in range(3): | |
map = mapbgr[color] | |
low = map[0] | |
high = map[255] | |
max_diff = 0 | |
for i in range(256): | |
diff = abs(int((map[i] - low) * 255 / max(high - low, 1)) - i) | |
if diff > max_diff: | |
max_diff = diff | |
if max_diff > threshold: | |
level[color] = threshold / max_diff | |
return level | |
def _create_map(self, histogram: [[int]], eqmap: [[int]]) -> None: | |
mapbgr = [[0 for _ in range(256)], [0 for _ in range(256)], [0 for _ in range(256)]] | |
b = 0 | |
g = 0 | |
r = 0 | |
for i in range(256): | |
b += histogram[Equalize.B][i] | |
mapbgr[Equalize.B][i] = b | |
g += histogram[Equalize.G][i] | |
mapbgr[Equalize.G][i] = g | |
r += histogram[Equalize.R][i] | |
mapbgr[Equalize.R][i] = r | |
for color in range(3): | |
map = mapbgr[color] | |
low = map[0] | |
high = map[255] | |
level = self.level[color] | |
for i in range(256): | |
c = i | |
if level > Equalize.MIN_LEVEL: | |
value = int((map[i] - low) * 255 / max(high - low, 1)) | |
if level == Equalize.MAX_LEVEL: | |
c = value | |
else: | |
c = i + int((value - i) * level) | |
eqmap[color][i] = c | |