-
Notifications
You must be signed in to change notification settings - Fork 28
/
BEASF.py
96 lines (82 loc) · 3.11 KB
/
BEASF.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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import numpy as np
import copy
def subhist(image_pdf, minimum, maximum, normalize):
"""
Compute the subhistogram between [minimum, maximum] of a given histogram image_pdf
:param image_pdf: numpy.array
:param minimum: int
:param maximum: int
:param normalize: boolean
:return: numpy.array
"""
hi = np.zeros(shape=image_pdf.shape)
total = 0
for idx in range(minimum, maximum+1):
total += image_pdf[idx]
hi[idx] = image_pdf[idx]
if normalize:
for idx in range(minimum, maximum+1):
hi[idx] /= total
return hi
def CDF(hist):
"""
Compute the CDF of the input histogram
:param hist: numpy.array()
:return: numpy.array()
"""
cdf = np.zeros(shape=hist.shape)
cdf[0] = hist[0]
for idx in range(1, len(hist)):
cdf[idx] = cdf[idx - 1] + hist[idx]
return cdf
def BEASF(image, gamma):
"""
Compute the Bi-Histogram Equalization with Adaptive Sigmoid Functions algorithm (BEASF)
A python implementation of the original MATLAB code:
https://mathworks.com/matlabcentral/fileexchange/47517-beasf-image-enhancer-for-gray-scale-images
The algorithm is introduced by E. F. Arriaga-Garcia et al., in the research paper:
https://ieeexplore.ieee.org/document/6808563
:param image: numpy.ndarray
:param gamma: float [0, 1]
:return: numpy.ndarray
"""
m = int(np.mean(image, dtype=np.int32))
h = np.histogram(image, bins=256)[0] / (image.shape[0] * image.shape[1])
h_lower = subhist(image_pdf=h, minimum=0, maximum=m, normalize=True)
h_upper = subhist(image_pdf=h, minimum=m, maximum=255, normalize=True)
cdf_lower = CDF(hist=h_lower)
cdf_upper = CDF(hist=h_upper)
# Find x | CDF(x) = 0.5
half_low = 0
for idx in range(0, m+2):
if cdf_lower[idx] > 0.5:
half_low = idx
break
half_up = 0
for idx in range(m, 256):
if cdf_upper[idx + 1] > 0.5:
half_up = idx
break
# sigmoid CDF creation
tones_low = np.arange(0, m+1, 1)
x_low = 5.0 * (tones_low - half_low) / m # shift & scale intensity x to place sigmoid [-2.5, 2.5]
s_low = 1 / (1 + np.exp(-gamma * x_low)) # lower sigmoid
tones_up = np.arange(m, 256, 1)
x_up = 5.0 * (tones_up - half_up) / (255 - m) # shift & scale intensity x to place sigmoid [-2.5, 2.5]
s_up = 1 / (1 + np.exp(-gamma * x_up)) # upper sigmoid
mapping_vector = np.zeros(shape=(256,))
for idx in range(0, m+1):
mapping_vector[idx] = np.int32(m * s_low[idx])
minimum = mapping_vector[0]
maximum = mapping_vector[m]
for idx in range(0, m+1):
mapping_vector[idx] = np.int32((m / (maximum - minimum)) * (mapping_vector[idx] - minimum))
for idx in range(m+1, 256):
mapping_vector[idx] = np.int32(m + (255 - m) * s_up[idx - m - 1])
minimum = mapping_vector[m + 1]
maximum = mapping_vector[255]
for idx in range(m+1, 256):
mapping_vector[idx] = (255 - m) * (mapping_vector[idx] - minimum) / (maximum - minimum) + m
res = copy.deepcopy(image)
res[:, :] = mapping_vector[image[:, :]]
return res