├── __init__.py
├── image_enhancement
├── __init__.py
├── quantitation.py
├── utils.py
├── histogram.py
└── image_enhancement.py
├── images
├── couple-FLH.jpg
├── couple-GHE.jpg
├── couple-AGCCPF.jpg
├── couple-AGCWD.jpg
├── couple-BBHE.jpg
├── couple-BHEPL.jpg
├── couple-BPHEME.jpg
├── couple-BUBOHE.jpg
├── couple-DCRGC.jpg
├── couple-DSIHE.jpg
├── couple-FHSABP.jpg
├── couple-QBHE.jpg
├── couple-RLBHE.jpg
├── couple-RMSHE.jpg
├── couple-RSIHE.jpg
├── couple-WTHE.jpg
├── couple-origin.jpg
├── couple-MMBEBHE.jpg
├── couple-RSWHE-D.jpg
└── couple-RSWHE-M.jpg
├── renovate.json
├── .gitignore
├── setup.py
├── LICENSE
└── README.md
/__init__.py:
--------------------------------------------------------------------------------
1 | from . import image_enhancement
--------------------------------------------------------------------------------
/image_enhancement/__init__.py:
--------------------------------------------------------------------------------
1 | from . import image_enhancement
2 | from . import quantitation
--------------------------------------------------------------------------------
/images/couple-FLH.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-FLH.jpg
--------------------------------------------------------------------------------
/images/couple-GHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-GHE.jpg
--------------------------------------------------------------------------------
/images/couple-AGCCPF.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-AGCCPF.jpg
--------------------------------------------------------------------------------
/images/couple-AGCWD.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-AGCWD.jpg
--------------------------------------------------------------------------------
/images/couple-BBHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-BBHE.jpg
--------------------------------------------------------------------------------
/images/couple-BHEPL.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-BHEPL.jpg
--------------------------------------------------------------------------------
/images/couple-BPHEME.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-BPHEME.jpg
--------------------------------------------------------------------------------
/images/couple-BUBOHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-BUBOHE.jpg
--------------------------------------------------------------------------------
/images/couple-DCRGC.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-DCRGC.jpg
--------------------------------------------------------------------------------
/images/couple-DSIHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-DSIHE.jpg
--------------------------------------------------------------------------------
/images/couple-FHSABP.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-FHSABP.jpg
--------------------------------------------------------------------------------
/images/couple-QBHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-QBHE.jpg
--------------------------------------------------------------------------------
/images/couple-RLBHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-RLBHE.jpg
--------------------------------------------------------------------------------
/images/couple-RMSHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-RMSHE.jpg
--------------------------------------------------------------------------------
/images/couple-RSIHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-RSIHE.jpg
--------------------------------------------------------------------------------
/images/couple-WTHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-WTHE.jpg
--------------------------------------------------------------------------------
/images/couple-origin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-origin.jpg
--------------------------------------------------------------------------------
/images/couple-MMBEBHE.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-MMBEBHE.jpg
--------------------------------------------------------------------------------
/images/couple-RSWHE-D.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-RSWHE-D.jpg
--------------------------------------------------------------------------------
/images/couple-RSWHE-M.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nguyen-Hoang-Nam/image-enhancement/HEAD/images/couple-RSWHE-M.jpg
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:recommended"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | tests/
2 | result/
3 | __pycache__/
4 | .pypirc
5 | test.py
6 |
7 | build
8 | # sphinx build directory
9 | _build
10 | # setup.py dist directory
11 | dist
12 | doc/build
13 | doc/cdoc/build
14 | # Egg metadata
15 | *.egg-info
16 | # The shelf plugin uses this dir
17 | ./.shelf
18 | MANIFEST
19 | .cache
20 | pip-wheel-metadata
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 |
3 | setup(
4 | name='image_enhancement',
5 | version='0.2.1',
6 | url='https://github.com/Nguyen-Hoang-Nam/image-enhancement',
7 | license='MIT',
8 | author='Nguyen Hoang Nam',
9 | author_email='nguyenhoangnam.dev@gmail.com',
10 | description='🌈 Library to enhance image',
11 | packages=find_packages(exclude=['tests', 'images']),
12 | long_description=open('README.md').read(),
13 | long_description_content_type="text/markdown",
14 | install_requires=["numpy", "opencv-python"],
15 | zip_safe=False
16 | )
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Nguyen Hoang Nam
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/image_enhancement/quantitation.py:
--------------------------------------------------------------------------------
1 | import math
2 | import numpy as np
3 |
4 | class Quantitation:
5 | # Absolute Mean Brightness Error
6 | def AMBE(self, image_input, image_output):
7 | return abs(np.mean(image_input) - np.mean(image_output))
8 |
9 | # Mean Square Error
10 | def MSE(self, image_input, image_output):
11 | err = np.sum((image_input.astype("float") - image_output.astype("float")) ** 2)
12 | err /= float(image_input.shape[0] * image_input.shape[1])
13 |
14 | return err
15 |
16 | # Peak Signal to Noise Ratio
17 | def PSNR(self, image_input, image_output):
18 | return 10 * math.log10(255 * 255 / MSE(image_input, image_output))
19 |
20 | # Entropy
21 | def Entropy(self, image_output):
22 | pdf, _ = np.histogram(image_output, 256, [0, 255])
23 | pdf = pdf / float(image_output.shape[0] * image_output.shape[1])
24 |
25 | ent = 0
26 | for probility in pdf:
27 | ent += probility * math.log2(probility)
28 |
29 | return -ent
30 |
31 | # Contrast improvement index
32 | def CII(self, image_input, image_output):
33 | return 0
34 |
35 | # Tenengrad measure
36 | def T(self, input_input, image_output):
37 | return 0
38 |
--------------------------------------------------------------------------------
/image_enhancement/utils.py:
--------------------------------------------------------------------------------
1 | import math
2 | import numpy as np
3 | import cv2 as cv
4 |
5 | class Utils:
6 | def __init__(self, image, color_space = 'HSV'):
7 | self.image = image
8 | self.color_space = color_space
9 |
10 | def image_gray(self):
11 | if (self.color_space == 'HSV'):
12 | image_hsv = cv.cvtColor(self.image, cv.COLOR_BGR2HSV)
13 | self.image_color = image_hsv
14 |
15 | return image_hsv[:, :, 2]
16 | elif (self.color_space == 'Gray'):
17 | image_gray = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY)
18 | self.image_color = image_gray
19 |
20 | return image_gray
21 | else:
22 | self.image_color = self.image
23 | return self.image
24 |
25 | def LUT_image(self, LUT):
26 | if (self.color_space == 'HSV'):
27 | for i in range(0, len(self.image_color)):
28 | for j in range(0, len(self.image_color[0])):
29 | self.image_color[i][j][2] = LUT[self.image_color[i][j][2]]
30 |
31 | return cv.cvtColor(self.image_color, cv.COLOR_HSV2BGR)
32 | elif (self.color_space == 'Gray'):
33 | return LUT[self.image_color]
34 | else:
35 | return self.image_color
36 |
37 | def is_gray_image(self):
38 | blue, gree, red = cv2.split(self.image)
39 |
40 | difference_red_green = np.count_nonzero(abs(red - green))
41 | difference_green_blue = np.count_nonzero(abs(green - blue))
42 | difference_blue_red = np.count_nonzero(abs(blue - red))
43 |
44 | difference_sum = float(difference_red_green + difference_green_blue + difference_blue_red)
45 |
46 | ratio = diff_sum / self.image.size
47 |
48 | if ratio>0.005:
49 | return False
50 | else:
51 | return True
52 |
53 | def minimum_mean_brightness_error(self, image_1d):
54 | length = len(image_1d)
55 |
56 | unique_1d = np.unique(image_1d)
57 | max_1d = len(unique_1d)
58 |
59 | histogram, _ = np.histogram(image_1d, 256, [0, 255])
60 |
61 | mean = 0
62 | for i in range(0, len(unique_1d)):
63 | mean += i * histogram[unique_1d[i]]
64 |
65 | smbe = max_1d * (length - histogram[unique_1d[0]]) - 2 * mean
66 | asmbe = abs(smbe)
67 | position = 0
68 | for i in range(1, len(unique_1d)):
69 | smbe += (length - max_1d * histogram[unique_1d[i]])
70 | if asmbe > abs(smbe):
71 | asmbe = abs(smbe)
72 | position = i
73 |
74 | return unique_1d[position]
75 |
76 |
77 |
78 |
79 | def RGB_TO_HSI(image):
80 | with np.errstate(divide='ignore', invalid='ignore'):
81 | #Load image with 32 bit floats as variable type
82 | bgr = np.float32(img) / 255
83 |
84 | #Separate color channels
85 | blue = bgr[:,:,0]
86 | green = bgr[:,:,1]
87 | red = bgr[:,:,2]
88 |
89 | minimum = np.minimum(np.minimum(red, green), blue)
90 | maximum = np.maximum(np.maximum(red, green), blue)
91 | delta = maximum - minimum
92 |
93 | intensity = np.divide(blue + green + red, 3)
94 |
95 | if intensity == 0:
96 | saturation = 0
97 | else:
98 | saturation = 1 - 3 * np.divide(minimum, red + green + blue)
99 |
100 | sqrt_calc = np.sqrt(((red - green) * (red - green)) + ((red - blue) * (green - blue)))
101 | if (green >= blue).any():
102 | hue = np.arccos((1 / 2 * ((red-green) + (red - blue)) / sqrt_calc))
103 | else:
104 | hue = 2 * math.pi - np.arccos((1 / 2 * ((red-green) + (red - blue)) / sqrt_calc))
105 |
106 | hue = hue * 180 / math.pi
107 |
108 | #Merge channels into picture and return image
109 | hsi = cv2.merge((intensity, saturation, hue))
110 | return hsi
111 |
112 | def pdf(image, parameter = 'HSI'):
113 | if parameter == 'GRAY':
114 | image_gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
115 | image_1d = image_gray.flatten()
116 |
117 | histogram, _ = np.histogram(image_1d, 256, [0, 256])
118 | elif parameter == 'INTENSITY':
119 | image_hsi = RGB_TO_HSI(image)
120 |
121 | intensity = image_hsi[:, :, 0]
122 | intensity_1d = intensity.flatten()
123 |
124 | return histogram
125 |
--------------------------------------------------------------------------------
/image_enhancement/histogram.py:
--------------------------------------------------------------------------------
1 | import math
2 | import numpy as np
3 |
4 | class Histogram:
5 |
6 | def cdf_matching(self, input_cdf, output_cdf):
7 | ratio = input_cdf[255] / output_cdf[255]
8 | output_cdf = output_cdf * ratio
9 |
10 | LUT = np.array([])
11 | position_new = 0
12 | for i in range(0, 256):
13 | while output_cdf[position_new] < input_cdf[i]:
14 | position_new += 1
15 |
16 | LUT = np.append(LUT, position_new)
17 |
18 | return LUT
19 |
20 | def histogram_specification(self, input_histogram, output_histogram):
21 | input_cdf = input_histogram.cumsum()
22 | output_cdf = output_histogram.cumsum()
23 |
24 | return self.cdf_matching(input_cdf, output_cdf)
25 |
26 | def sub_histogram_equalization(self, histogram, range_min = 0, range_max = 255):
27 | cdf = histogram.cumsum()
28 | cdf_mask = np.ma.masked_equal(cdf, 0)
29 |
30 | # Scale cdf to [range_min, range_max]
31 | scale_cdf_mask = ((cdf_mask - cdf_mask.min()) * (range_max - range_min) / (cdf_mask.max() - cdf_mask.min())) + range_min
32 | LUT = np.ma.filled(scale_cdf_mask, 0).astype('uint8')
33 |
34 | return LUT
35 |
36 | def histogram_equalization(self, image_1d, range_min = 0, range_max = 255):
37 | histogram, _ = np.histogram(image_1d, range_max - range_min + 1, [range_min, range_max])
38 |
39 | return self.sub_histogram_equalization(histogram, range_min, range_max)
40 |
41 | def histogram_equalization_threshold(self, image_1d, threshold, start = 0, end = 255):
42 | lower_filter = image_1d <= threshold
43 | lower_1d = image_1d[lower_filter]
44 |
45 | upper_filter = image_1d > threshold
46 | upper_1d = image_1d[upper_filter]
47 |
48 | lower_input_lut = np.array([])
49 | if start > 0:
50 | for i in range(0, start):
51 | lower_input_lut = np.append(lower_input_lut, i)
52 |
53 | upper_input_lut = np.array([])
54 | if end < 255:
55 | for i in range(end + 1, 256):
56 | upper_input_lut = np.append(upper_input_lut, i)
57 |
58 | lower_LUT = self.histogram_equalization(lower_1d, start, threshold)
59 | upper_LUT = self.histogram_equalization(upper_1d, threshold + 1, end)
60 |
61 | lower_LUT = np.concatenate((lower_input_lut, lower_LUT))
62 | upper_LUT = np.concatenate((upper_LUT, upper_input_lut))
63 |
64 | LUT = np.concatenate((lower_LUT, upper_LUT))
65 |
66 | return LUT
67 |
68 | def histogram_equalization_recursively(self, image_1d, separate_func, recursive, start = 0, end = 255):
69 | if recursive > 0:
70 | separate = separate_func(image_1d)
71 | separate = math.floor(separate)
72 |
73 | lower_filter = image_1d <= separate
74 | lower_1d = image_1d[lower_filter]
75 |
76 | lower_equalization = self.histogram_equalization_recursively(lower_1d, separate_func, recursive - 1, start, separate)
77 |
78 | upper_filter = image_1d > separate
79 | upper_1d = image_1d[upper_filter]
80 |
81 | upper_equalization = self.histogram_equalization_recursively(upper_1d, separate_func, recursive - 1, separate + 1, end)
82 |
83 | return np.concatenate((lower_equalization, upper_equalization))
84 | else:
85 | return self.histogram_equalization(image_1d, start, end)
86 |
87 | def histogram_segmentation(self, image_1d, separate_func, recursive, start = 0, end = 255):
88 | if recursive > 0:
89 | separate = separate_func(image_1d)
90 | separate = math.floor(separate)
91 |
92 | lower_filter = image_1d <= separate
93 | lower_1d = image_1d[lower_filter]
94 |
95 | lower_equalization = self.histogram_segmentation(lower_1d, separate_func, recursive - 1, start, separate)
96 |
97 | upper_filter = image_1d > separate
98 | upper_1d = image_1d[upper_filter]
99 |
100 | upper_equalization = self.histogram_segmentation(upper_1d, separate_func, recursive - 1, separate + 1, end)
101 |
102 | return lower_equalization + upper_equalization
103 | else:
104 | sub_histogram, _ = np.histogram(image_1d, end - start + 1, [start, end])
105 | return [sub_histogram]
106 |
107 |
108 | # def histogram_weighting_mean(cdf, start = 0, end = 255):
109 | # weighting_mean = 0
110 | # for i in range(start, end + 1):
111 | # weighting_mean += i * cdf[i]
112 |
113 | # weighting_mean = weighting_mean / np.sum(cdf)
114 | # weighting_mean = math.floor(weighting_mean)
115 |
116 | # if weighting_mean == 255:
117 | # return [weighting_mean]
118 | # else:
119 | # lower = histogram_weighting_mean(cdf, start, weighting_mean)
120 | # upper = histogram_weighting_mean(cdf, weighting_mean + 1, end)
121 |
122 | # return lower + upper
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Image Enhancement
2 |
3 | Base on multiple papers about image enhancement, I create this library as API to call them easily. Image enhancement makes color of images more equalization by automatic or parameters.
4 |
5 |
6 |
7 | (a) **Origin**, (b) **GHE**, (c) **BBHE**, (d) **QBHE**, (e) **DSIHE**, (f) **MMBEBHE**, (g) **RMSHE**, (h) **BUBOHE**, (i) **BPHEME**, (j) **RSIHE**, (k) **WTHE**, (l) **RSWHE-D**, (m) **RSWHE-M**, (n) **FHSABP**, (o) **BHEPL**, (p) **RLBHE**, (q) **DCRGC**, (r) **AGCWD**, (s) **AGCCPF**, (t) **FLH**
8 |
9 | ## Installation
10 |
11 | ```bash
12 | pip install image-enhancement
13 | ```
14 |
15 | ## Usage
16 |
17 | ```python
18 | from image_enhancement import image_enhancement
19 | import cv2 as cv
20 |
21 | input = cv.imread('input.jpg')
22 |
23 | ie = image_enhancement.IE(input, 'HSV')
24 | output = ie.GHE()
25 |
26 | cv.imwrite('output.jpg', output)
27 | ```
28 |
29 | ## IE (Image Enhancement)
30 |
31 | Entry point to call image enhancement functions. Currently, there are three main groups, histogram equalization, gamma correction and other.
32 |
33 | ```python
34 | from image_enhancement import image_enhancement
35 |
36 | ie = image_enhancement.IE(image, color_space = 'HSV')
37 | ```
38 |
39 | ### Histogram Equalization
40 |
41 | #### GHE (Global Histogram Equalization)
42 |
43 | This function is similar to `equalizeHist(image)` in opencv.
44 |
45 | ```python
46 | ie.GHE()
47 | ```
48 |
49 | #### BBHE (Brightness Preserving Histogram Equalization)
50 |
51 | Kim, Yeong-Taeg.
52 |
53 | Contrast enhancement using brightness preserving bi-histogram equalization.
54 |
55 | IEEE transactions on Consumer Electronics 43, no. 1 (1997): 1-8.
56 |
57 | ```python
58 | ie.BBHE()
59 | ```
60 |
61 | #### QBHE (Quantized Bi-Histogram Equalization)
62 |
63 | Kim, Yeong-Taeg.
64 |
65 | Quantized bi-histogram equalization.
66 |
67 | In 1997 IEEE International Conference on Acoustics, Speech, and Signal Processing, vol. 4, pp. 2797-2800. IEEE, 1997.
68 |
69 | ```python
70 | ie.QBHE(number_gray)
71 | ```
72 |
73 | #### DSIHE (Dualistic Sub-Image Histogram Equalization)
74 |
75 | Wang, Yu, Qian Chen, and Baeomin Zhang.
76 |
77 | Image enhancement based on equal area dualistic sub-image histogram equalization method.
78 |
79 | IEEE Transactions on Consumer Electronics 45, no. 1 (1999): 68-75.
80 |
81 | ```python
82 | ie.DSIHE()
83 | ```
84 |
85 | #### MMBEBHE (Minimum Mean Brightness Error Histogram Equalization)
86 |
87 | Chen, Soong-Der, and Abd Rahman Ramli.
88 |
89 | Minimum mean brightness error bi-histogram equalization in contrast enhancement.
90 |
91 | IEEE transactions on Consumer Electronics 49, no. 4 (2003): 1310-1319.
92 |
93 | ```python
94 | ie.MMBEBHE()
95 | ```
96 |
97 | #### RMSHE (Recursively Mean-Separate Histogram Equalization)
98 |
99 | Chen, Soong-Der, and Abd Rahman Ramli.
100 |
101 | Contrast enhancement using recursive mean-separate histogram equalization for scalable brightness preservation.
102 |
103 | IEEE Transactions on consumer Electronics 49, no. 4 (2003): 1301-1309.
104 |
105 | ```python
106 | ie.RMSHE(recursive)
107 | ```
108 |
109 | #### BUBOHE (Bin Underflow and Bin Overflow Histogram Equalization)
110 |
111 | Yang, Seungjoon, Jae Hwan Oh, and Yungfun Park.
112 |
113 | Contrast enhancement using histogram equalization with bin underflow and bin overflow.
114 |
115 | In Proceedings 2003 International Conference on Image Processing (Cat. No. 03CH37429), vol. 1, pp. I-881. IEEE, 2003.
116 |
117 | ```python
118 | ie.BUBOHE(underflow, overflow)
119 | ```
120 |
121 | #### BPHEME (Brightness Preserving Histogram Equalization with Maximum Entropy)
122 |
123 | Wang, Chao, and Zhongfu Ye.
124 |
125 | Brightness preserving histogram equalization with maximum entropy: a variational perspective.
126 |
127 | IEEE Transactions on Consumer Electronics 51, no. 4 (2005): 1326-1334.
128 |
129 | ```python
130 | ie.BPHEME()
131 | ```
132 |
133 | #### RSIHE (Recursive Sub-Image Histogram Equalization)
134 |
135 | Sim, K. S., C. P. Tso, and Y. Y. Tan.
136 |
137 | Recursive sub-image histogram equalization applied to gray scale images.
138 |
139 | Pattern Recognition Letters 28, no. 10 (2007): 1209-1221.
140 |
141 | ```python
142 | ie.RSIHE(recursive)
143 | ```
144 |
145 | #### WTHE (Weighted Thresholded Histogram Equalization)
146 |
147 | Wang, Qing, and Rabab K. Ward.
148 |
149 | Fast image/video contrast enhancement based on weighted thresholded histogram equalization.
150 |
151 | IEEE transactions on Consumer Electronics 53, no. 2 (2007): 757-764.
152 |
153 | ```python
154 | ie.WTHE(root, value, lower)
155 | ```
156 |
157 | #### RSWHE (Recursive Separated and Weighted Histogram Equalization)
158 |
159 | Kim, Mary, and Min Gyo Chung.
160 |
161 | Recursively separated and weighted histogram equalization for brightness preservation and contrast enhancement.
162 |
163 | IEEE Transactions on Consumer Electronics 54, no. 3 (2008): 1389-1397.
164 |
165 | ```python
166 | ie.RSWHE(type, beta, recursive)
167 | ```
168 |
169 | #### FHSABP (Flattest Histogram Specification with Accurate Brightness Preservation)
170 |
171 | Wang, C., J. Peng, and Z. Ye.
172 |
173 | Flattest histogram specification with accurate brightness preservation.
174 |
175 | IET Image Processing 2, no. 5 (2008): 249-262.
176 |
177 | ```python
178 | ie.FHSABP()
179 | ```
180 |
181 | #### BHEPL (Bi-Histogram Equalization with a Plateau Limit)
182 |
183 | Ooi, Chen Hee, Nicholas Sia Pik Kong, and Haidi Ibrahim.
184 |
185 | Bi-histogram equalization with a plateau limit for digital image enhancement.
186 |
187 | IEEE transactions on consumer electronics 55, no. 4 (2009): 2072-2080.
188 |
189 | ```python
190 | ie.BHEPL()
191 | ```
192 |
193 | #### RLBHE (Range Limited Bi-Histogram Equalization)
194 |
195 | Zuo, Chao, Qian Chen, and Xiubao Sui.
196 |
197 | Range limited bi-histogram equalization for image contrast enhancement.
198 |
199 | Optik 124, no. 5 (2013): 425-431.
200 |
201 | ```python
202 | ie.RLBHE()
203 | ```
204 |
205 | ### Gamma Correction
206 |
207 | #### DCRGC (Dynamic Contrast Ratio Gamma Correction)
208 |
209 | Wang, Zhi-Guo, Zhi-Hu Liang, and Chun-Liang Liu.
210 |
211 | A real-time image processor with combining dynamic contrast ratio enhancement and inverse gamma correction for PDP.
212 |
213 | Displays 30, no. 3 (2009): 133-139.
214 |
215 | ```python
216 | ie.DCRGC(contrast_intensity, gamma)
217 | ```
218 |
219 | #### AGCWD (Adaptive Gamma Correction with Weighting Distribution)
220 |
221 | Huang, Shih-Chia, Fan-Chieh Cheng, and Yi-Sheng Chiu.
222 |
223 | Efficient contrast enhancement using adaptive gamma correction with weighting distribution.
224 |
225 | IEEE transactions on image processing 22, no. 3 (2012): 1032-1041.
226 |
227 | ```python
228 | ie.AGCWD(alpha)
229 | ```
230 |
231 | #### AGCCPF (Adaptive Gamma Correction Color Preserving Framework)
232 |
233 | Gupta, Bhupendra, and Mayank Tiwari.
234 |
235 | Minimum mean brightness error contrast enhancement of color images using adaptive gamma correction with color preserving framework.
236 |
237 | Optik 127, no. 4 (2016): 1671-1676.
238 |
239 | ```python
240 | ie.AGCCPF(alpha)
241 | ```
242 |
243 | ### Other
244 |
245 | #### FLH (Fuzzy-Logic and Histogram)
246 |
247 | Raju, G., and Madhu S. Nair.
248 |
249 | A fast and efficient color image enhancement method based on fuzzy-logic and histogram.
250 |
251 | AEU-International Journal of electronics and communications 68, no. 3 (2014): 237-243.
252 |
253 | ```python
254 | ie.FLH(enhancement)
255 | ```
256 |
257 | ## Quantitation
258 |
259 | Entry point to call quantitation functions.
260 |
261 | ```python
262 | from contrast_image import quantitation
263 |
264 | quantitation = Quantitation()
265 | ```
266 |
267 | #### AMBE (Absolute Mean Brightness Error)
268 |
269 | ```python
270 | quantitatin.AMBE(input_image, output_image)
271 | ```
272 |
273 | #### PSNR (Peak Signal to Noise Ratio)
274 |
275 | ```python
276 | quantitatin.PSNR(input_image, output_image)
277 | ```
278 |
279 | #### Entropy
280 |
281 | ```python
282 | quantitatin.Entropy(image)
283 | ```
284 |
285 | ## Contributing
286 |
287 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
288 |
289 | Please make sure to update tests as appropriate.
290 |
291 | ## License
292 |
293 | [MIT](https://choosealicense.com/licenses/mit/)
294 |
--------------------------------------------------------------------------------
/image_enhancement/image_enhancement.py:
--------------------------------------------------------------------------------
1 | import math
2 | import numpy as np
3 | import numpy.ma as ma
4 | import cv2 as cv
5 | from .utils import Utils
6 | from .histogram import Histogram
7 |
8 | class IE:
9 | def __init__(self, image, color_space = 'HSV'):
10 | self.image = image
11 | self.color_space = color_space
12 |
13 | ########################################
14 | #
15 | # Global histogram
16 | #
17 | ########################################
18 |
19 | # Global Histogram Equalization
20 | def GHE(self):
21 | utils = Utils(self.image, self.color_space)
22 | image_gray = utils.image_gray()
23 | image_1d = image_gray.flatten()
24 |
25 | histogram = Histogram()
26 | LUT = histogram.histogram_equalization(image_1d)
27 | return utils.LUT_image(LUT)
28 |
29 |
30 | # Kim, Yeong-Taeg.
31 | # Contrast enhancement using brightness preserving bi-histogram equalization.
32 | # IEEE transactions on Consumer Electronics 43, no. 1 (1997): 1-8.
33 | # Brightness-preserving Bi-Histogram Equalization (BBHE)
34 | def BBHE(self):
35 | utils = Utils(self.image, self.color_space)
36 | image_gray = utils.image_gray()
37 | image_1d = image_gray.flatten()
38 |
39 | mean = np.mean(image_1d)
40 | mean = math.floor(mean)
41 | histogram = Histogram()
42 | LUT = histogram.histogram_equalization_threshold(image_1d, mean)
43 | return utils.LUT_image(LUT)
44 |
45 |
46 | # Kim, Yeong-Taeg.
47 | # Quantized bi-histogram equalization."
48 | # In 1997 IEEE International Conference on Acoustics, Speech, and Signal Processing, vol. 4, pp. 2797-2800. IEEE, 1997.
49 | # Quantized Bi-Histogram Equalization (QBHE)
50 | def QBHE(self, number_gray):
51 | utils = Utils(self.image, self.color_space)
52 | image_gray = utils.image_gray()
53 | image_1d = image_gray.flatten()
54 |
55 | mean = np.mean(image_1d)
56 | mean = math.floor(mean)
57 |
58 | number_divide = 256 / number_gray
59 | image_1d = image_1d / number_divide
60 | image_1d = image_1d.astype('uint8')
61 | image_1d = image_1d * number_divide
62 | image_1d = image_1d.astype('uint8')
63 |
64 | mean = round(round(mean / number_divide) * number_divide)
65 |
66 | histogram = Histogram()
67 | LUT = histogram.histogram_equalization_threshold(image_1d, mean)
68 | return utils.LUT_image(LUT)
69 |
70 |
71 | # Wang, Yu, Qian Chen, and Baeomin Zhang.
72 | # Image enhancement based on equal area dualistic sub-image histogram equalization method.
73 | # IEEE Transactions on Consumer Electronics 45, no. 1 (1999): 68-75.
74 | # Dualistic Sub-Image Histogram Equalization (DSIHE)
75 | def DSIHE(self):
76 | utils = Utils(self.image, self.color_space)
77 | image_gray = utils.image_gray()
78 | image_1d = image_gray.flatten()
79 |
80 | median = np.median(image_1d)
81 | median = math.floor(median)
82 | histogram = Histogram()
83 | LUT = histogram.histogram_equalization_threshold(image_1d, median)
84 | return utils.LUT_image(LUT)
85 |
86 |
87 | # Chen, Soong-Der, and Abd Rahman Ramli.
88 | # Minimum mean brightness error bi-histogram equalization in contrast enhancement.
89 | # IEEE transactions on Consumer Electronics 49, no. 4 (2003): 1310-1319.
90 | # Minimum Mean Brightness Error Histogram Equalization (MMBEBHE)
91 | def MMBEBHE(self):
92 | utils = Utils(self.image, self.color_space)
93 | image_gray = utils.image_gray()
94 | image_1d = image_gray.flatten()
95 |
96 | mbe = utils.minimum_mean_brightness_error(image_1d)
97 | histogram = Histogram()
98 | LUT = histogram.histogram_equalization_threshold(image_1d, mbe)
99 | return utils.LUT_image(LUT)
100 |
101 |
102 | # Chen, Soong-Der, and Abd Rahman Ramli.
103 | # Contrast enhancement using recursive mean-separate histogram equalization for scalable brightness preservation.
104 | # IEEE Transactions on consumer Electronics 49, no. 4 (2003): 1301-1309.
105 | # Recursive Mean-Separate Histogram Equalization (RMSHE)
106 | def RMSHE(self, recursive = 2):
107 | utils = Utils(self.image, self.color_space)
108 | image_gray = utils.image_gray()
109 | image_1d = image_gray.flatten()
110 |
111 | histogram = Histogram()
112 | LUT = histogram.histogram_equalization_recursively(image_1d, np.mean, recursive)
113 | return utils.LUT_image(LUT)
114 |
115 |
116 | # Yang, Seungjoon, Jae Hwan Oh, and Yungfun Park.
117 | # Contrast enhancement using histogram equalization with bin underflow and bin overflow.
118 | # In Proceedings 2003 International Conference on Image Processing (Cat. No. 03CH37429), vol. 1, pp. I-881. IEEE, 2003.
119 | # Bin Underflow and Bin Overflow Histogram Equalization (BUBOHE)
120 | def BUBOHE(self, underflow, overflow):
121 | utils = Utils(self.image, self.color_space)
122 | image_gray = utils.image_gray()
123 | image_1d = image_gray.flatten()
124 |
125 | histogram, _ = np.histogram(image_1d, 256, [0, 255])
126 | histogram = histogram / len(image_1d)
127 |
128 | histogram[histogram > overflow] = overflow
129 | histogram[histogram < underflow] = underflow
130 |
131 | cdf = histogram.cumsum()
132 | LUT = np.array([0.0] * 256)
133 |
134 | for i in range(0, 256):
135 | LUT[i] = 255 * (cdf[i] - (cdf[i] / 255) * i) + i
136 |
137 | LUT = LUT.astype('uint8')
138 | return utils.LUT_image(LUT)
139 |
140 | # Wang, Chao, and Zhongfu Ye.
141 | # Brightness preserving histogram equalization with maximum entropy: a variational perspective.
142 | # IEEE Transactions on Consumer Electronics 51, no. 4 (2005): 1326-1334.
143 | # Brightness Preserving Histogram Equalization with Maximum Entropy (BPHEME)
144 | def BPHEME(self):
145 | utils = Utils(self.image, self.color_space)
146 | image_gray = utils.image_gray()
147 | image_1d = image_gray.flatten()
148 |
149 | mean = np.mean(image_1d)
150 | if mean == 127.5:
151 | cdf_output = np.array([mean] * 255)
152 | else:
153 | def maximum_histogram_entropy(x, mean):
154 | return (x * math.exp(x) - math.exp(x) + 1) / (x * (math.exp(x) - 1)) - mean
155 |
156 | def derivative_maximum_histogram_entropy(x):
157 | return (-math.exp(x) * (x * x + 2) + math.exp(2 * x) + 1) / ((math.exp(x) - 1) * (math.exp(x) - 1) * x * x)
158 |
159 | def maximum_cumulative_entropy(x):
160 | return np.array([(math.exp(x * (i / 255)) - 1) / (math.exp(x) - 1) for i in range(0, 256)])
161 |
162 | scale_mean = mean / 255
163 | lamda = 1
164 | output_newton_method = maximum_histogram_entropy(lamda, scale_mean)
165 |
166 | while abs(output_newton_method) > 0.01:
167 | lamda = lamda - (output_newton_method / derivative_maximum_histogram_entropy(lamda))
168 | output_newton_method = maximum_histogram_entropy(lamda, scale_mean)
169 |
170 | cdf_output = maximum_cumulative_entropy(lamda)
171 |
172 | pdf_input, _ = np.histogram(image_1d, 256, [0, 255])
173 | cdf_input = pdf_input.cumsum()
174 |
175 | histogram = Histogram()
176 | LUT = histogram.cdf_matching(cdf_input, cdf_output)
177 | return utils.LUT_image(LUT)
178 |
179 |
180 | # Sim, K. S., C. P. Tso, and Y. Y. Tan.
181 | # Recursive sub-image histogram equalization applied to gray scale images.
182 | # Pattern Recognition Letters 28, no. 10 (2007): 1209-1221.
183 | # Recursive Sub-Image Histogram Equalization (RSIHE)
184 | def RSIHE(self, recursive = 2):
185 | utils = Utils(self.image, self.color_space)
186 | image_gray = utils.image_gray()
187 | image_1d = image_gray.flatten()
188 |
189 | histogram = Histogram()
190 | LUT = histogram.histogram_equalization_recursively(image_1d, np.median, recursive)
191 | return utils.LUT_image(LUT)
192 |
193 |
194 | # Wang, Qing, and Rabab K. Ward.
195 | # Fast image/video contrast enhancement based on weighted thresholded histogram equalization.
196 | # IEEE transactions on Consumer Electronics 53, no. 2 (2007): 757-764.
197 | # Weighted Thresholded Histogram Equalization (WTHE)
198 | def WTHE(self, root = 0.5, value = 0.5, lower = 0):
199 | utils = Utils(self.image, self.color_space)
200 | image_gray = utils.image_gray()
201 | image_1d = image_gray.flatten()
202 | length = len(image_1d)
203 |
204 | pdf, _ = np.histogram(image_1d, 256, [0, 255])
205 | pdf = pdf / length
206 |
207 | if value < 1:
208 | upper = pdf.max() * value
209 | else:
210 | upper = pdf.max()
211 |
212 | weight_pdf = np.array([0.0] * 256)
213 | for i in range(0, 256):
214 | if pdf[i] < lower:
215 | weight_pdf[i] = 0
216 | elif pdf[i] < upper:
217 | weight_pdf[i] = upper * ((pdf[i] - lower) / (upper - lower)) ** root
218 | else:
219 | weight_pdf[i] = upper
220 |
221 | weight_pdf_sum = np.sum(weight_pdf)
222 | weight_pdf_scale = weight_pdf / weight_pdf_sum
223 |
224 | histogram = Histogram()
225 | LUT = histogram.sub_histogram_equalization(weight_pdf_scale)
226 | return utils.LUT_image(LUT)
227 |
228 |
229 | # Kim, Mary, and Min Gyo Chung.
230 | # Recursively separated and weighted histogram equalization for brightness preservation and contrast enhancement.
231 | # IEEE Transactions on Consumer Electronics 54, no. 3 (2008): 1389-1397.
232 | # Recursive Separated and Weighted Histogram Equalization (RSWHE)
233 | def RSWHE(self, type = 'mean', recursive = 2):
234 | utils = Utils(self.image, self.color_space)
235 | image_gray = utils.image_gray()
236 | image_1d = image_gray.flatten()
237 | length = len(image_1d)
238 |
239 | histogram = Histogram()
240 | if (type == 'mean'):
241 | histogram_segmentation = histogram.histogram_segmentation(image_1d, np.mean, recursive)
242 | elif (type == 'median'):
243 | histogram_segmentation = histogram.histogram_segmentation(image_1d, np.median, recursive)
244 |
245 | pdf, _ = np.histogram(image_1d, 256, [0, 255])
246 | highest_probabilitiy = pdf.max() / length
247 | lowest_probability = pdf.min() / length
248 |
249 | image_mean = np.mean(image_1d)
250 | image_min = image_1d.min()
251 | image_max = image_1d.max()
252 | image_middle = (int(image_min) + int(image_max)) / 2
253 | beta = highest_probabilitiy * abs(image_mean - image_middle) / (image_max - image_min)
254 |
255 | histogram_weight = []
256 | for sub_histogram in histogram_segmentation:
257 | sub_histogram_scale = sub_histogram / length
258 | alpha = np.sum(sub_histogram_scale)
259 | for i in range(0, len(sub_histogram_scale)):
260 | sub_histogram_scale[i] = highest_probabilitiy * ((sub_histogram_scale[i] - lowest_probability) / (highest_probabilitiy - lowest_probability)) ** alpha + beta
261 |
262 | histogram_weight += [sub_histogram_scale]
263 |
264 | histogram_weight_sum = 0
265 | for sub_histogram in histogram_weight:
266 | histogram_weight_sum += np.sum(sub_histogram)
267 |
268 | histogram_weight_scale = []
269 | for sub_histogram in histogram_weight:
270 | sub_histogram = sub_histogram / histogram_weight_sum
271 | histogram_weight_scale += [sub_histogram]
272 |
273 | start = 0
274 | end = -1
275 | LUT = np.array([])
276 | for sub_histogram in histogram_weight_scale:
277 | start = end + 1
278 | end = start + len(sub_histogram) - 1
279 | LUT = np.concatenate((LUT, histogram.sub_histogram_equalization(sub_histogram, start, end)))
280 |
281 | return utils.LUT_image(LUT)
282 |
283 |
284 | # Wang, C., J. Peng, and Z. Ye.
285 | # Flattest histogram specification with accurate brightness preservation.
286 | # IET Image Processing 2, no. 5 (2008): 249-262.
287 | # Flattest Histogram Specification with Accurate Brightness Preservation (FHSABP)
288 | def FHSABP(self):
289 | utils = Utils(self.image, self.color_space)
290 | image_gray = utils.image_gray()
291 | image_1d = image_gray.flatten()
292 |
293 | pdf_input, _ = np.histogram(image_1d, 256, [0, 255])
294 | pdf_input = pdf_input / 1.0
295 | pdf_output = np.array([0.0] * 256)
296 |
297 | mean = np.mean(image_1d)
298 | if mean < 84.67:
299 | x_0 = 3 * math.floor(mean) + 1
300 | a = (-6 * x_0 + 12 * mean) / (x_0 * (x_0 + 1) * (x_0 + 2))
301 | b = (4 * x_0 - 6 * mean + 2) / ((x_0 + 1) * (x_0 + 2))
302 |
303 | for i in range(0, 256):
304 | pdf_output[i] = max(0, a * i + b)
305 | elif mean <= 170.33:
306 | a = (mean - 127.5) / 1398080
307 | b = (511 - 3 * mean) / 32896
308 |
309 | for i in range(0, 256):
310 | pdf_output[i] = a * i + b
311 | else:
312 | invert_mean = 255 - mean
313 | x_0 = 3 * math.floor(invert_mean) + 1
314 | a = (-6 * x_0 + 12 * invert_mean) / (x_0 * (x_0 + 1) * (x_0 + 2))
315 | b = (4 * x_0 - 6 * invert_mean + 2) / ((x_0 + 1) * (x_0 + 2))
316 |
317 | for i in range(0, 256):
318 | pdf_output[i] = max(0, a * i + b)
319 |
320 | histogram = Histogram()
321 | LUT = histogram.histogram_specification(pdf_input, pdf_output)
322 | return utils.LUT_image(LUT)
323 |
324 |
325 | # Ooi, Chen Hee, Nicholas Sia Pik Kong, and Haidi Ibrahim.
326 | # Bi-histogram equalization with a plateau limit for digital image enhancement.
327 | # IEEE transactions on consumer electronics 55, no. 4 (2009): 2072-2080.
328 | # Bi-Histogram Equalization with a Plateau Limit (BHEPL)
329 | def BHEPL(self):
330 | utils = Utils(self.image, self.color_space)
331 | image_gray = utils.image_gray()
332 | image_1d = image_gray.flatten()
333 |
334 | mean = np.mean(image_1d)
335 | mean = math.floor(mean)
336 |
337 | lower_filter = image_1d <= mean
338 | lower_1d = image_1d[lower_filter]
339 |
340 | upper_filter = image_1d > mean
341 | upper_1d = image_1d[upper_filter]
342 |
343 | lower_histogram, _ = np.histogram(lower_1d, mean + 1, [0, mean])
344 | upper_histogram, _ = np.histogram(upper_1d, 255 - mean, [mean + 1, 255])
345 |
346 | lower_plateau_limit = np.sum(lower_histogram) / (mean + 1)
347 | upper_plateau_limit = np.sum(upper_histogram) / (255 - mean)
348 |
349 | lower_histogram[lower_histogram > lower_plateau_limit] = lower_plateau_limit
350 | upper_histogram[upper_histogram > upper_plateau_limit] = upper_plateau_limit
351 |
352 | lower_histogram_sum = np.sum(lower_histogram)
353 | upper_Histogram_sum = np.sum(upper_histogram)
354 |
355 | lower_cdf = lower_histogram.cumsum()
356 | lower_cdf_mask = np.ma.masked_equal(lower_cdf, 0)
357 |
358 | # Scale cdf to [range_min, range_max]
359 | lower_scale_cdf_mask = ((lower_cdf_mask - 0.5 * lower_histogram - lower_cdf_mask.min()) * (mean - 0) / (lower_cdf_mask.max() - lower_cdf_mask.min())) + 0
360 | lower_LUT = np.ma.filled(lower_scale_cdf_mask, 0).astype('uint8')
361 |
362 | upper_cdf = upper_histogram.cumsum()
363 | upper_cdf_mask = np.ma.masked_equal(upper_cdf, 0)
364 |
365 | # Scale cdf to [range_min, range_max]
366 | upper_scale_cdf_mask = ((upper_cdf_mask - 0.5 * upper_histogram - upper_cdf_mask.min()) * (255 - mean - 1) / (upper_cdf_mask.max() - upper_cdf_mask.min())) + mean + 1
367 | upper_LUT = np.ma.filled(upper_scale_cdf_mask, 0).astype('uint8')
368 |
369 | LUT = np.concatenate((lower_LUT, upper_LUT))
370 |
371 | return utils.LUT_image(LUT)
372 |
373 |
374 | # Zuo, Chao, Qian Chen, and Xiubao Sui.
375 | # Range limited bi-histogram equalization for image contrast enhancement.
376 | # Optik 124, no. 5 (2013): 425-431.
377 | # Range Limited Bi-Histogram Equalization (RLBHE)
378 | def RLBHE(self):
379 | utils = Utils(self.image, self.color_space)
380 | image_gray = utils.image_gray()
381 | image_1d = image_gray.flatten()
382 |
383 | otsu_threshold, _ = cv.threshold(image_gray, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
384 | otsu_threshold = math.floor(otsu_threshold)
385 |
386 | pdf, _ = np.histogram(image_1d, 256, [0, 255])
387 | image_mean = 0
388 | lower_cumulative = 0
389 | for i in range(0, 256):
390 | image_mean += i * pdf[i]
391 |
392 | if i <= otsu_threshold:
393 | lower_cumulative += pdf[i]
394 |
395 | length = len(image_1d)
396 | image_mean /= length
397 | lower_cumulative /= length
398 |
399 | a = lower_cumulative
400 | b = 2 * image_mean - otsu_threshold - (1 - a)
401 | x_0 = 0
402 | x_l = 255
403 | for i in range(0, 500):
404 | temp = 2 * (a * x_0 + (1 - a) * x_l - b)
405 | x_0 -= temp * a
406 | x_l -= temp * (1 - a)
407 |
408 | if x_0 < 0:
409 | x_0 = 0
410 | elif x_0 > otsu_threshold:
411 | x_0 = otsu_threshold
412 | else:
413 | x_0 = math.floor(x_0)
414 |
415 | if x_l > 255:
416 | x_l = 255
417 | elif x_l <= otsu_threshold:
418 | x_l = otsu_threshold + 1
419 | else:
420 | x_l = math.floor(x_l)
421 |
422 | histogram = Histogram()
423 | LUT = histogram.histogram_equalization_threshold(image_1d, otsu_threshold, x_0, x_l)
424 | return utils.LUT_image(LUT)
425 |
426 | # Automatic Weighting Mean-separated Histogram Equalization
427 | # def AWMHE(image, color_space = 'HSV'):
428 | # image_gray, image_color = utils.image_gray(image, color_space)
429 | # image_1d = image_gray.flatten()
430 |
431 | # pdf, _ = np.histogram(image_1d, 256, [0, 255])
432 | # cdf = pdf.cumsum()
433 |
434 | # print(histogram.histogram_weighting_mean(cdf))
435 |
436 | ########################################
437 | #
438 | # Adaptive histogram
439 | #
440 | ########################################
441 |
442 | # Adaptive Histogram Equalization
443 | def AHE(self):
444 | return self.image
445 |
446 | # Non-Overlapped Sub-block Histogram Equalization
447 | def NOSHE(self):
448 | return self.image
449 |
450 | # Partially Overlapped Sub-block Histogram Equalization
451 | def POSHE(self):
452 | return self.image
453 |
454 | # Cascadede Multistep Binominal Filtering Histogram Equalization
455 | def CMBFHE(self):
456 | return self.image
457 |
458 | # Contrast Limited Adaptive Histogram Equalization
459 | def CLAHE(self):
460 | return self.image
461 |
462 |
463 | ########################################
464 | #
465 | # Gamma Correction
466 | #
467 | ########################################
468 |
469 |
470 | # Wang, Zhi-Guo, Zhi-Hu Liang, and Chun-Liang Liu.
471 | # A real-time image processor with combining dynamic contrast ratio enhancement and inverse gamma correction for PDP.
472 | # Displays 30, no. 3 (2009): 133-139.
473 | # Dynamic Contrast Ratio Gamma Correction (DCRGC)
474 | def DCRGC(self, contrast_intensity, gamma):
475 | utils = Utils(self.image, self.color_space)
476 | image_gray = utils.image_gray()
477 | image_1d = image_gray.flatten()
478 |
479 | gamma_reverse = [0.0] * 256
480 | for i in range(1, 256):
481 | gamma_reverse[i] = (i / 255) ** gamma
482 |
483 | normalized_foundation_histogram = np.array([0.0] * 256)
484 | for i in range(1, 256):
485 | normalized_foundation_histogram[i] = gamma_reverse[i] - gamma_reverse[i - 1]
486 |
487 | histogram, _ = np.histogram(image_1d, 256, [0, 255])
488 | histogram = histogram / len(image_1d)
489 |
490 | normalized_combination_histogram = histogram * contrast_intensity + normalized_foundation_histogram * (1 - contrast_intensity)
491 | normalized_combination_cdf = normalized_combination_histogram.cumsum()
492 |
493 | LUT = normalized_combination_cdf * 255
494 | LUT = LUT.astype('uint8')
495 |
496 | return utils.LUT_image(LUT)
497 |
498 |
499 | # Huang, Shih-Chia, Fan-Chieh Cheng, and Yi-Sheng Chiu.
500 | # Efficient contrast enhancement using adaptive gamma correction with weighting distribution.
501 | # IEEE transactions on image processing 22, no. 3 (2012): 1032-1041.
502 | # Adaptive Gamma Correction with Weighting Distribution (AGCWD)
503 | def AGCWD(self, alpha = 0.5):
504 | utils = Utils(self.image, self.color_space)
505 | image_gray = utils.image_gray()
506 | image_1d = image_gray.flatten()
507 | length = len(image_1d)
508 |
509 | pdf, _ = np.histogram(image_1d, 256, [0, 255])
510 | pdf = pdf / length
511 | highest_probabilitiy = pdf.max()
512 | lowest_probability = pdf.min()
513 |
514 | weight_distribution = highest_probabilitiy * ((pdf - lowest_probability) / (highest_probabilitiy - lowest_probability)) ** alpha
515 | weight_distribution_sum = np.sum(weight_distribution)
516 |
517 | weight_distribution_scale = weight_distribution / weight_distribution_sum
518 |
519 | LUT = np.array([0.0] * 256)
520 | for i in range(0, 256):
521 | LUT[i] = 255 * (i / 255) ** (1 - weight_distribution_scale[i])
522 | LUT = LUT.astype('uint8')
523 |
524 | return utils.LUT_image(LUT)
525 |
526 | # Rahman, Shanto, Md Mostafijur Rahman, Mohammad Abdullah-Al-Wadud, Golam Dastegir Al-Quaderi, and Mohammad Shoyaib.
527 | # An adaptive gamma correction for image enhancement.
528 | # EURASIP Journal on Image and Video Processing 2016, no. 1 (2016): 1-13.
529 | # Adaptive Gamma Correction Image Enhancement (AGCIE)
530 | def AGCIE(self, contrast_threshold = 3):
531 | utils = Utils(self.image, self.color_space)
532 | image_gray = utils.image_gray()
533 | image_1d = image_gray.flatten() / 255
534 |
535 | mean = np.mean(image_1d)
536 | std = np.std(image_1d)
537 | LUT = np.arange(0, 256) / 255
538 |
539 | if std <= 1 / (4 * contrast_threshold):
540 | gamma = -math.log(std, 2)
541 | else:
542 | gamma = math.exp((1 - (mean + std))/2)
543 |
544 | if mean >= 0.5:
545 | LUT = 255 * (LUT ** gamma)
546 | else:
547 | for i in range(0, 256):
548 | LUT[i] = 255 * (LUT[i] ** gamma / (LUT[i] ** gamma + (1 - LUT[i] ** gamma) * mean ** gamma))
549 |
550 | LUT = LUT.astype('uint8')
551 |
552 | return utils.LUT_image(LUT)
553 |
554 | # Gupta, Bhupendra, and Mayank Tiwari.
555 | # Minimum mean brightness error contrast enhancement of color images using adaptive gamma correction with color preserving framework.
556 | # Optik 127, no. 4 (2016): 1671-1676.
557 | # Adaptive Gamma Correction Color Preserving Framework (AGCCPF)
558 | def AGCCPF(self, alpha = 0.5):
559 | utils = Utils(self.image, self.color_space)
560 | image_gray = utils.image_gray()
561 | image_1d = image_gray.flatten()
562 |
563 | pdf, _ = np.histogram(image_1d, 256, [0, 255])
564 |
565 | image_equalization = self.GHE()
566 | image_equalization_1d = image_equalization.flatten()
567 |
568 | pdf_equalization, _ = np.histogram(image_equalization_1d, 256, [0, 255])
569 |
570 | smooth_pdf = 0.5 * pdf + 0.5 * pdf_equalization
571 | smooth_pdf_scale = smooth_pdf / np.sum(smooth_pdf)
572 |
573 | cdf = smooth_pdf_scale.cumsum()
574 |
575 | LUT = np.array([0.0] * 256)
576 | for i in range(0, 256):
577 | LUT[i] = 255 * (i / 255) ** (1 - cdf[i])
578 | LUT = LUT.astype('uint8')
579 |
580 | return utils.LUT_image(LUT)
581 | ########################################
582 | #
583 | # Genetic Algorithm
584 | #
585 | ########################################
586 |
587 | # Saitoh, Fumihiko.
588 | # Image contrast enhancement using genetic algorithm.
589 | # In IEEE SMC'99 Conference Proceedings. 1999 IEEE International Conference on Systems, Man, and Cybernetics (Cat. No. 99CH37028), vol. 4, pp. 899-904. IEEE, 1999.
590 | # Saitoh Genetic Algorithm (SGA)
591 |
592 | # Hashemi, Sara, Soheila Kiani, Navid Noroozi, and Mohsen Ebrahimi Moghaddam.
593 | # An image contrast enhancement method based on genetic algorithm.
594 | # Pattern Recognition Letters 31, no. 13 (2010): 1816-1824.
595 | # Constrast Enhancement Based Genetic Algorithm (CEBGA)
596 |
597 | ########################################
598 | #
599 | # Other
600 | #
601 | ########################################
602 |
603 |
604 | # Raju, G., and Madhu S. Nair.
605 | # A fast and efficient color image enhancement method based on fuzzy-logic and histogram.
606 | # AEU-International Journal of electronics and communications 68, no. 3 (2014): 237-243.
607 | # Fuzzy-Logic and Histogram (FLH)
608 | def FLH(self, enhancement):
609 | utils = Utils(self.image, self.color_space)
610 | image_gray = utils.image_gray()
611 | image_1d = image_gray.flatten()
612 |
613 | histogram, _ = np.histogram(image_1d, 256, [0, 255])
614 | sum_weight_histogram = 0
615 | for i in range(0, 256):
616 | sum_weight_histogram += i * histogram[i]
617 |
618 | control = sum_weight_histogram / np.sum(histogram)
619 | control = math.floor(control)
620 |
621 | lower_fuzzy = np.array([0.0] * (control))
622 | upper_fuzzy = np.array([0.0] * (256 - control))
623 |
624 | for i in range(0, control):
625 | lower_fuzzy[i] = i + (1 - control + i) * enhancement / control
626 |
627 | for i in range(control, 256):
628 | upper_fuzzy[i - control] = (255 - i) / (255 - control) + 255 - (255 - i) * enhancement / (255 - control)
629 |
630 | LUT = np.concatenate((lower_fuzzy, upper_fuzzy))
631 | LUT[LUT < 0] = 0
632 | LUT = LUT.astype('uint8')
633 |
634 | return utils.LUT_image(LUT)
635 |
636 | # Celik, Turgay, and Tardi Tjahjadi.
637 | # Contextual and variational contrast enhancement.
638 | # IEEE Transactions on Image Processing 20, no. 12 (2011): 3431-3441.
639 | # Contextual and Variational Contrast (CVC)
640 |
--------------------------------------------------------------------------------