File size: 3,850 Bytes
9692d43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
from PIL import Image

class Equalize:
	MIN_LEVEL = 0.0
	MAX_LEVEL = 1.0
	R = 0
	G = 1
	B = 2

	@property
	def level(self):
		return self._level

	@property
	def level_b(self) -> float:
		return self._level[Equalize.B]

	@property
	def level_g(self) -> float:
		return self._level[Equalize.G]

	@property
	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 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