image-enhancer-ai 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- image_enhancer_ai-1.0.1/LICENSE +5 -0
- image_enhancer_ai-1.0.1/MANIFEST.in +11 -0
- image_enhancer_ai-1.0.1/PKG-INFO +59 -0
- image_enhancer_ai-1.0.1/README.md +39 -0
- image_enhancer_ai-1.0.1/image_enhancer/__init__.py +1 -0
- image_enhancer_ai-1.0.1/image_enhancer/config.py +0 -0
- image_enhancer_ai-1.0.1/image_enhancer/enhance_engine.py +390 -0
- image_enhancer_ai-1.0.1/image_enhancer/enhancer.py +109 -0
- image_enhancer_ai-1.0.1/image_enhancer_ai.egg-info/PKG-INFO +59 -0
- image_enhancer_ai-1.0.1/image_enhancer_ai.egg-info/SOURCES.txt +18 -0
- image_enhancer_ai-1.0.1/image_enhancer_ai.egg-info/dependency_links.txt +1 -0
- image_enhancer_ai-1.0.1/image_enhancer_ai.egg-info/requires.txt +5 -0
- image_enhancer_ai-1.0.1/image_enhancer_ai.egg-info/top_level.txt +1 -0
- image_enhancer_ai-1.0.1/pyproject.toml +48 -0
- image_enhancer_ai-1.0.1/setup.cfg +4 -0
- image_enhancer_ai-1.0.1/tests/test_blur.py +19 -0
- image_enhancer_ai-1.0.1/tests/test_noise.py +0 -0
- image_enhancer_ai-1.0.1/tests/test_quality.py +0 -0
- image_enhancer_ai-1.0.1/tests/test_quality_metrics.py +27 -0
- image_enhancer_ai-1.0.1/tests/test_rotation.py +13 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
recursive-include image_enhancer *.json
|
|
4
|
+
recursive-include image_enhancer *.yaml
|
|
5
|
+
recursive-include image_enhancer *.yml
|
|
6
|
+
recursive-include image_enhancer *.txt
|
|
7
|
+
recursive-include image_enhancer *.h5
|
|
8
|
+
recursive-include image_enhancer *.keras
|
|
9
|
+
recursive-include image_enhancer *.pkl
|
|
10
|
+
recursive-include image_enhancer *.jpg
|
|
11
|
+
recursive-include image_enhancer *.png
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: image-enhancer-ai
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Reusable AI Image Enhancement Package
|
|
5
|
+
Author-email: Punsara Wikramarathna <punsarawikramarathna@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: image enhancement,opencv,computer vision,image processing,tensorflow,ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: opencv-python
|
|
15
|
+
Requires-Dist: numpy
|
|
16
|
+
Requires-Dist: tensorflow
|
|
17
|
+
Requires-Dist: scikit-image
|
|
18
|
+
Requires-Dist: PyYAML
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# Image Enhancer
|
|
22
|
+
|
|
23
|
+
A reusable AI-powered image enhancement package.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- Major Rotation Correction (CNN)
|
|
28
|
+
- Minor Rotation Correction
|
|
29
|
+
- Blur Detection and Correction
|
|
30
|
+
- Noise Reduction
|
|
31
|
+
- Brightness Enhancement
|
|
32
|
+
- Contrast Enhancement
|
|
33
|
+
- Quality Evaluation
|
|
34
|
+
- Iterative Enhancement
|
|
35
|
+
- Configuration Support
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install image-enhancer-punsara99
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from image_enhancer import ImageEnhancer
|
|
47
|
+
|
|
48
|
+
engine = ImageEnhancer()
|
|
49
|
+
|
|
50
|
+
output, report = engine.process("input.jpg")
|
|
51
|
+
|
|
52
|
+
engine.save(output, "output.jpg")
|
|
53
|
+
|
|
54
|
+
engine.print_report(report)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
MIT
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Image Enhancer
|
|
2
|
+
|
|
3
|
+
A reusable AI-powered image enhancement package.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Major Rotation Correction (CNN)
|
|
8
|
+
- Minor Rotation Correction
|
|
9
|
+
- Blur Detection and Correction
|
|
10
|
+
- Noise Reduction
|
|
11
|
+
- Brightness Enhancement
|
|
12
|
+
- Contrast Enhancement
|
|
13
|
+
- Quality Evaluation
|
|
14
|
+
- Iterative Enhancement
|
|
15
|
+
- Configuration Support
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install image-enhancer-punsara99
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from image_enhancer import ImageEnhancer
|
|
27
|
+
|
|
28
|
+
engine = ImageEnhancer()
|
|
29
|
+
|
|
30
|
+
output, report = engine.process("input.jpg")
|
|
31
|
+
|
|
32
|
+
engine.save(output, "output.jpg")
|
|
33
|
+
|
|
34
|
+
engine.print_report(report)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .enhancer import ImageEnhancer
|
|
File without changes
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from config.config_loader import load_config
|
|
5
|
+
|
|
6
|
+
from utils.blur_module import (
|
|
7
|
+
detect_blur,
|
|
8
|
+
fix_blur
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from utils.noise_module import (
|
|
12
|
+
remove_noise
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from utils.brightness_module import (
|
|
16
|
+
enhance_brightness_contrast
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from utils.quality_module import (
|
|
20
|
+
quality_score
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from utils.rotation_module import (
|
|
24
|
+
detect_minor_rotation,
|
|
25
|
+
correct_minor_rotation,
|
|
26
|
+
rotation_direction,
|
|
27
|
+
rotation_level
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from training.predict_rotation import predict_rotation
|
|
31
|
+
|
|
32
|
+
from utils.quality_metrics import (
|
|
33
|
+
improvement,
|
|
34
|
+
quality_report
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ==========================================================
|
|
39
|
+
# Major Rotation Correction
|
|
40
|
+
# ==========================================================
|
|
41
|
+
|
|
42
|
+
def fix_rotation(image, angle):
|
|
43
|
+
|
|
44
|
+
angle = int(float(angle))
|
|
45
|
+
|
|
46
|
+
if angle == 90:
|
|
47
|
+
return cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE)
|
|
48
|
+
|
|
49
|
+
elif angle == 180:
|
|
50
|
+
return cv2.rotate(image, cv2.ROTATE_180)
|
|
51
|
+
|
|
52
|
+
elif angle == 270:
|
|
53
|
+
return cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
|
|
54
|
+
|
|
55
|
+
return image
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# ==========================================================
|
|
59
|
+
# Configuration Helper
|
|
60
|
+
# ==========================================================
|
|
61
|
+
|
|
62
|
+
def _enabled(config, section):
|
|
63
|
+
|
|
64
|
+
value = config.get(section, {})
|
|
65
|
+
|
|
66
|
+
if isinstance(value, dict):
|
|
67
|
+
return value.get("enabled", False)
|
|
68
|
+
|
|
69
|
+
return bool(value)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ==========================================================
|
|
73
|
+
# Run One Enhancement Cycle
|
|
74
|
+
# ==========================================================
|
|
75
|
+
|
|
76
|
+
def run_pipeline(image, config):
|
|
77
|
+
|
|
78
|
+
report = []
|
|
79
|
+
|
|
80
|
+
output = image.copy()
|
|
81
|
+
|
|
82
|
+
# ---------------------------------------
|
|
83
|
+
# Blur
|
|
84
|
+
# ---------------------------------------
|
|
85
|
+
|
|
86
|
+
if _enabled(config, "blur"):
|
|
87
|
+
|
|
88
|
+
blur_score = detect_blur(output)
|
|
89
|
+
|
|
90
|
+
output, _, blur_level, motion, _ = fix_blur(output)
|
|
91
|
+
|
|
92
|
+
report.append(f"Blur Score : {blur_score:.2f}")
|
|
93
|
+
report.append(f"Blur Level : {blur_level}")
|
|
94
|
+
report.append(f"Motion Blur : {motion}")
|
|
95
|
+
|
|
96
|
+
# ---------------------------------------
|
|
97
|
+
# Noise
|
|
98
|
+
# ---------------------------------------
|
|
99
|
+
|
|
100
|
+
if _enabled(config, "noise"):
|
|
101
|
+
|
|
102
|
+
output, noise_score, noise_level, noise_type = remove_noise(output)
|
|
103
|
+
|
|
104
|
+
report.append(f"Noise Score : {noise_score:.2f}")
|
|
105
|
+
report.append(f"Noise Level : {noise_level}")
|
|
106
|
+
report.append(f"Noise Type : {noise_type}")
|
|
107
|
+
|
|
108
|
+
# ---------------------------------------
|
|
109
|
+
# Brightness
|
|
110
|
+
# ---------------------------------------
|
|
111
|
+
|
|
112
|
+
if _enabled(config, "brightness"):
|
|
113
|
+
|
|
114
|
+
output, brightness, b_level, contrast, c_level = \
|
|
115
|
+
enhance_brightness_contrast(output)
|
|
116
|
+
|
|
117
|
+
report.append(f"Brightness : {brightness:.2f}")
|
|
118
|
+
report.append(f"Brightness Level : {b_level}")
|
|
119
|
+
|
|
120
|
+
report.append(f"Contrast : {contrast:.2f}")
|
|
121
|
+
report.append(f"Contrast Level : {c_level}")
|
|
122
|
+
|
|
123
|
+
return output, report
|
|
124
|
+
|
|
125
|
+
# ==========================================================
|
|
126
|
+
# Image Enhancement Engine
|
|
127
|
+
# ==========================================================
|
|
128
|
+
|
|
129
|
+
def enhance_image(image):
|
|
130
|
+
|
|
131
|
+
if image is None:
|
|
132
|
+
raise ValueError("Invalid image.")
|
|
133
|
+
|
|
134
|
+
config = load_config()
|
|
135
|
+
|
|
136
|
+
os.makedirs("output", exist_ok=True)
|
|
137
|
+
|
|
138
|
+
original = image.copy()
|
|
139
|
+
output = image.copy()
|
|
140
|
+
|
|
141
|
+
report = []
|
|
142
|
+
|
|
143
|
+
# ---------------------------------------------
|
|
144
|
+
# Track whether image orientation changed
|
|
145
|
+
# ---------------------------------------------
|
|
146
|
+
|
|
147
|
+
rotation_changed = False
|
|
148
|
+
|
|
149
|
+
# =====================================================
|
|
150
|
+
# Major Rotation
|
|
151
|
+
# =====================================================
|
|
152
|
+
|
|
153
|
+
if _enabled(config, "rotation"):
|
|
154
|
+
|
|
155
|
+
angle, confidence = predict_rotation(output)
|
|
156
|
+
|
|
157
|
+
report.append(f"Major Rotation : {angle}")
|
|
158
|
+
report.append(f"Confidence : {confidence:.3f}")
|
|
159
|
+
|
|
160
|
+
threshold = config["rotation"]["confidence_threshold"]
|
|
161
|
+
|
|
162
|
+
if confidence >= threshold and angle != 0:
|
|
163
|
+
|
|
164
|
+
output = fix_rotation(output, angle)
|
|
165
|
+
|
|
166
|
+
rotation_changed = True
|
|
167
|
+
|
|
168
|
+
report.append("Major Rotation Fixed")
|
|
169
|
+
|
|
170
|
+
elif angle == 0:
|
|
171
|
+
|
|
172
|
+
report.append("No Rotation Needed")
|
|
173
|
+
|
|
174
|
+
else:
|
|
175
|
+
|
|
176
|
+
report.append("Rotation Ignored (Low Confidence)")
|
|
177
|
+
|
|
178
|
+
# =====================================================
|
|
179
|
+
# Minor Rotation
|
|
180
|
+
# =====================================================
|
|
181
|
+
|
|
182
|
+
if _enabled(config, "minor_rotation"):
|
|
183
|
+
|
|
184
|
+
minor_angle = detect_minor_rotation(output)
|
|
185
|
+
|
|
186
|
+
direction = rotation_direction(minor_angle)
|
|
187
|
+
|
|
188
|
+
level = rotation_level(minor_angle)
|
|
189
|
+
|
|
190
|
+
report.append(f"Minor Rotation : {minor_angle:.2f}")
|
|
191
|
+
report.append(f"Direction : {direction}")
|
|
192
|
+
report.append(f"Rotation Level : {level}")
|
|
193
|
+
|
|
194
|
+
if abs(minor_angle) > 2:
|
|
195
|
+
|
|
196
|
+
output = correct_minor_rotation(output, minor_angle)
|
|
197
|
+
|
|
198
|
+
rotation_changed = True
|
|
199
|
+
|
|
200
|
+
report.append("Minor Rotation Fixed")
|
|
201
|
+
|
|
202
|
+
# Save rotation result
|
|
203
|
+
|
|
204
|
+
if _enabled(config, "save_steps"):
|
|
205
|
+
|
|
206
|
+
cv2.imwrite("output/1_rotation.jpg", output)
|
|
207
|
+
|
|
208
|
+
# =====================================================
|
|
209
|
+
# Iterative Enhancement
|
|
210
|
+
# =====================================================
|
|
211
|
+
|
|
212
|
+
iteration_cfg = config["iteration"]
|
|
213
|
+
|
|
214
|
+
max_iterations = iteration_cfg["max_iterations"]
|
|
215
|
+
|
|
216
|
+
target_quality = iteration_cfg["quality_threshold"]
|
|
217
|
+
|
|
218
|
+
best_quality = -1
|
|
219
|
+
|
|
220
|
+
best_output = output.copy()
|
|
221
|
+
|
|
222
|
+
best_iteration = 0
|
|
223
|
+
|
|
224
|
+
# =====================================================
|
|
225
|
+
# Enhancement Loop
|
|
226
|
+
# =====================================================
|
|
227
|
+
|
|
228
|
+
if iteration_cfg["enabled"]:
|
|
229
|
+
|
|
230
|
+
for i in range(max_iterations):
|
|
231
|
+
|
|
232
|
+
report.append("")
|
|
233
|
+
report.append(f"========== Iteration {i+1} ==========")
|
|
234
|
+
|
|
235
|
+
output, temp_report = run_pipeline(output, config)
|
|
236
|
+
|
|
237
|
+
report.extend(temp_report)
|
|
238
|
+
|
|
239
|
+
current_quality, grade = quality_score(output)
|
|
240
|
+
|
|
241
|
+
report.append(f"Current Quality : {current_quality:.2f}")
|
|
242
|
+
|
|
243
|
+
# Save intermediate image
|
|
244
|
+
|
|
245
|
+
if _enabled(config, "save_steps"):
|
|
246
|
+
|
|
247
|
+
cv2.imwrite(
|
|
248
|
+
f"output/iteration_{i+1}.jpg",
|
|
249
|
+
output
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# Keep the best result
|
|
253
|
+
|
|
254
|
+
# -----------------------------------------
|
|
255
|
+
# Keep the Best Result
|
|
256
|
+
# -----------------------------------------
|
|
257
|
+
|
|
258
|
+
if current_quality > best_quality:
|
|
259
|
+
|
|
260
|
+
best_quality = current_quality
|
|
261
|
+
best_output = output.copy()
|
|
262
|
+
best_iteration = i + 1
|
|
263
|
+
|
|
264
|
+
else:
|
|
265
|
+
|
|
266
|
+
report.append("Quality decreased.")
|
|
267
|
+
report.append("Stopping iterations.")
|
|
268
|
+
|
|
269
|
+
break
|
|
270
|
+
|
|
271
|
+
# Stop if target reached
|
|
272
|
+
|
|
273
|
+
if current_quality >= target_quality:
|
|
274
|
+
|
|
275
|
+
report.append("Target Quality Reached")
|
|
276
|
+
|
|
277
|
+
break
|
|
278
|
+
|
|
279
|
+
# Use the best enhanced image
|
|
280
|
+
|
|
281
|
+
output = best_output.copy()
|
|
282
|
+
|
|
283
|
+
final_quality = best_quality
|
|
284
|
+
|
|
285
|
+
# =====================================================
|
|
286
|
+
# Final Quality
|
|
287
|
+
# =====================================================
|
|
288
|
+
|
|
289
|
+
report.append("")
|
|
290
|
+
report.append("==============================")
|
|
291
|
+
report.append(" FINAL IMAGE QUALITY ")
|
|
292
|
+
report.append("==============================")
|
|
293
|
+
|
|
294
|
+
report.append(f"Quality Score : {final_quality:.2f}")
|
|
295
|
+
|
|
296
|
+
_, grade = quality_score(output)
|
|
297
|
+
|
|
298
|
+
report.append(f"Quality Grade : {grade}")
|
|
299
|
+
|
|
300
|
+
report.append(f"Iterations Used : {best_iteration}")
|
|
301
|
+
|
|
302
|
+
report.append(f"Target Quality : {target_quality}")
|
|
303
|
+
|
|
304
|
+
# =====================================================
|
|
305
|
+
# Quality Metrics
|
|
306
|
+
# =====================================================
|
|
307
|
+
|
|
308
|
+
report.append("")
|
|
309
|
+
report.append("==============================")
|
|
310
|
+
report.append(" QUALITY METRICS ")
|
|
311
|
+
report.append("==============================")
|
|
312
|
+
|
|
313
|
+
if rotation_changed:
|
|
314
|
+
|
|
315
|
+
report.append("Skipped")
|
|
316
|
+
report.append(
|
|
317
|
+
"Reason : Image orientation changed after rotation correction."
|
|
318
|
+
)
|
|
319
|
+
report.append(
|
|
320
|
+
"PSNR/SSIM require identical image orientation."
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
else:
|
|
324
|
+
|
|
325
|
+
metrics = quality_report(original, output)
|
|
326
|
+
|
|
327
|
+
report.append(f"MSE : {metrics['mse']:.2f}")
|
|
328
|
+
report.append(f"PSNR : {metrics['psnr']:.2f} dB")
|
|
329
|
+
report.append(f"SSIM : {metrics['ssim']:.4f}")
|
|
330
|
+
report.append(f"Image Quality : {metrics['grade']}")
|
|
331
|
+
|
|
332
|
+
# =====================================================
|
|
333
|
+
# Improvement Report
|
|
334
|
+
# =====================================================
|
|
335
|
+
|
|
336
|
+
report.append("")
|
|
337
|
+
report.append("==============================")
|
|
338
|
+
report.append(" IMPROVEMENT REPORT ")
|
|
339
|
+
report.append("==============================")
|
|
340
|
+
|
|
341
|
+
before, after, gain = improvement(original, output)
|
|
342
|
+
|
|
343
|
+
report.append(f"Before Quality : {before:.2f}")
|
|
344
|
+
report.append(f"After Quality : {after:.2f}")
|
|
345
|
+
|
|
346
|
+
if gain >= 0:
|
|
347
|
+
|
|
348
|
+
report.append(f"Improvement : +{gain:.2f}")
|
|
349
|
+
|
|
350
|
+
else:
|
|
351
|
+
|
|
352
|
+
report.append(f"Improvement : {gain:.2f}")
|
|
353
|
+
|
|
354
|
+
# =====================================================
|
|
355
|
+
# Save Final Image
|
|
356
|
+
# =====================================================
|
|
357
|
+
|
|
358
|
+
if _enabled(config, "save_steps"):
|
|
359
|
+
|
|
360
|
+
cv2.imwrite("output/6_final.jpg", output)
|
|
361
|
+
|
|
362
|
+
# =====================================================
|
|
363
|
+
# Completion Summary
|
|
364
|
+
# =====================================================
|
|
365
|
+
|
|
366
|
+
report.append("")
|
|
367
|
+
report.append("========================================")
|
|
368
|
+
report.append(" Image Enhancement Completed ")
|
|
369
|
+
report.append("========================================")
|
|
370
|
+
|
|
371
|
+
report.append(f"Quality Score : {final_quality:.2f}")
|
|
372
|
+
report.append(f"Iterations Used : {best_iteration}")
|
|
373
|
+
report.append("")
|
|
374
|
+
report.append("Module Status")
|
|
375
|
+
report.append("---------------------------")
|
|
376
|
+
|
|
377
|
+
report.append("[OK] Rotation")
|
|
378
|
+
report.append("[OK] Blur")
|
|
379
|
+
report.append("[OK] Noise")
|
|
380
|
+
report.append("[OK] Brightness")
|
|
381
|
+
report.append("[OK] Quality")
|
|
382
|
+
|
|
383
|
+
report.append("")
|
|
384
|
+
report.append("Output Saved Successfully")
|
|
385
|
+
|
|
386
|
+
# =====================================================
|
|
387
|
+
# Return
|
|
388
|
+
# =====================================================
|
|
389
|
+
|
|
390
|
+
return output, report
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import os
|
|
3
|
+
from config.config_loader import load_config
|
|
4
|
+
from .enhance_engine import enhance_image
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ImageEnhancer:
|
|
8
|
+
|
|
9
|
+
def __init__(self):
|
|
10
|
+
|
|
11
|
+
self.config = load_config()
|
|
12
|
+
|
|
13
|
+
print("Image Enhancer Initialized")
|
|
14
|
+
|
|
15
|
+
# -----------------------------------------
|
|
16
|
+
# Show Current Configuration
|
|
17
|
+
# -----------------------------------------
|
|
18
|
+
|
|
19
|
+
def show_configuration(self):
|
|
20
|
+
|
|
21
|
+
print("\n========== CURRENT CONFIGURATION ==========\n")
|
|
22
|
+
|
|
23
|
+
for key, value in self.config.items():
|
|
24
|
+
|
|
25
|
+
print(f"{key} : {value}")
|
|
26
|
+
|
|
27
|
+
print()
|
|
28
|
+
|
|
29
|
+
# -----------------------------------------
|
|
30
|
+
# Process Image
|
|
31
|
+
# -----------------------------------------
|
|
32
|
+
|
|
33
|
+
def process(self, image_path):
|
|
34
|
+
|
|
35
|
+
image = cv2.imread(image_path)
|
|
36
|
+
|
|
37
|
+
if image is None:
|
|
38
|
+
raise FileNotFoundError(image_path)
|
|
39
|
+
|
|
40
|
+
output, report = enhance_image(image)
|
|
41
|
+
|
|
42
|
+
return output, report
|
|
43
|
+
|
|
44
|
+
# -----------------------------------------
|
|
45
|
+
# Save Image
|
|
46
|
+
# -----------------------------------------
|
|
47
|
+
|
|
48
|
+
def process_and_save(self, image_path, output_path="output/final.jpg"):
|
|
49
|
+
|
|
50
|
+
output, report = self.process(image_path)
|
|
51
|
+
|
|
52
|
+
cv2.imwrite(output_path, output)
|
|
53
|
+
|
|
54
|
+
return report
|
|
55
|
+
|
|
56
|
+
# -----------------------------------------
|
|
57
|
+
# Save Image
|
|
58
|
+
# -----------------------------------------
|
|
59
|
+
|
|
60
|
+
def save(self, image, output_path):
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
folder = os.path.dirname(output_path)
|
|
65
|
+
|
|
66
|
+
if folder != "":
|
|
67
|
+
os.makedirs(folder, exist_ok=True)
|
|
68
|
+
|
|
69
|
+
cv2.imwrite(output_path, image)
|
|
70
|
+
|
|
71
|
+
print(f"Image saved to {output_path}")
|
|
72
|
+
# -----------------------------------------
|
|
73
|
+
# Print Report
|
|
74
|
+
# -----------------------------------------
|
|
75
|
+
|
|
76
|
+
def print_report(self, report):
|
|
77
|
+
|
|
78
|
+
print("\n========== REPORT ==========\n")
|
|
79
|
+
|
|
80
|
+
for line in report:
|
|
81
|
+
print(line)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# -----------------------------------------
|
|
85
|
+
# Batch Processing
|
|
86
|
+
# -----------------------------------------
|
|
87
|
+
|
|
88
|
+
def process_folder(self, input_folder, output_folder="output/results"):
|
|
89
|
+
|
|
90
|
+
import os
|
|
91
|
+
|
|
92
|
+
os.makedirs(output_folder, exist_ok=True)
|
|
93
|
+
|
|
94
|
+
for file in os.listdir(input_folder):
|
|
95
|
+
|
|
96
|
+
path = os.path.join(input_folder, file)
|
|
97
|
+
|
|
98
|
+
if not os.path.isfile(path):
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
output, report = self.process(path)
|
|
102
|
+
|
|
103
|
+
save_path = os.path.join(output_folder, file)
|
|
104
|
+
|
|
105
|
+
cv2.imwrite(save_path, output)
|
|
106
|
+
|
|
107
|
+
print(file, "Completed")
|
|
108
|
+
|
|
109
|
+
print("\nBatch Processing Finished")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: image-enhancer-ai
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Reusable AI Image Enhancement Package
|
|
5
|
+
Author-email: Punsara Wikramarathna <punsarawikramarathna@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: image enhancement,opencv,computer vision,image processing,tensorflow,ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: opencv-python
|
|
15
|
+
Requires-Dist: numpy
|
|
16
|
+
Requires-Dist: tensorflow
|
|
17
|
+
Requires-Dist: scikit-image
|
|
18
|
+
Requires-Dist: PyYAML
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# Image Enhancer
|
|
22
|
+
|
|
23
|
+
A reusable AI-powered image enhancement package.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- Major Rotation Correction (CNN)
|
|
28
|
+
- Minor Rotation Correction
|
|
29
|
+
- Blur Detection and Correction
|
|
30
|
+
- Noise Reduction
|
|
31
|
+
- Brightness Enhancement
|
|
32
|
+
- Contrast Enhancement
|
|
33
|
+
- Quality Evaluation
|
|
34
|
+
- Iterative Enhancement
|
|
35
|
+
- Configuration Support
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install image-enhancer-punsara99
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from image_enhancer import ImageEnhancer
|
|
47
|
+
|
|
48
|
+
engine = ImageEnhancer()
|
|
49
|
+
|
|
50
|
+
output, report = engine.process("input.jpg")
|
|
51
|
+
|
|
52
|
+
engine.save(output, "output.jpg")
|
|
53
|
+
|
|
54
|
+
engine.print_report(report)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
image_enhancer/__init__.py
|
|
6
|
+
image_enhancer/config.py
|
|
7
|
+
image_enhancer/enhance_engine.py
|
|
8
|
+
image_enhancer/enhancer.py
|
|
9
|
+
image_enhancer_ai.egg-info/PKG-INFO
|
|
10
|
+
image_enhancer_ai.egg-info/SOURCES.txt
|
|
11
|
+
image_enhancer_ai.egg-info/dependency_links.txt
|
|
12
|
+
image_enhancer_ai.egg-info/requires.txt
|
|
13
|
+
image_enhancer_ai.egg-info/top_level.txt
|
|
14
|
+
tests/test_blur.py
|
|
15
|
+
tests/test_noise.py
|
|
16
|
+
tests/test_quality.py
|
|
17
|
+
tests/test_quality_metrics.py
|
|
18
|
+
tests/test_rotation.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
image_enhancer
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=65", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "image-enhancer-ai"
|
|
7
|
+
version = "1.0.1"
|
|
8
|
+
|
|
9
|
+
description = "Reusable AI Image Enhancement Package"
|
|
10
|
+
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
|
+
|
|
15
|
+
license = { text = "MIT" }
|
|
16
|
+
|
|
17
|
+
authors = [
|
|
18
|
+
{ name = "Punsara Wikramarathna", email = "punsarawikramarathna@gmail.com" }
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
keywords = [
|
|
22
|
+
"image enhancement",
|
|
23
|
+
"opencv",
|
|
24
|
+
"computer vision",
|
|
25
|
+
"image processing",
|
|
26
|
+
"tensorflow",
|
|
27
|
+
"ai"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
classifiers = [
|
|
31
|
+
"Programming Language :: Python :: 3",
|
|
32
|
+
"License :: OSI Approved :: MIT License",
|
|
33
|
+
"Operating System :: OS Independent"
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
dependencies = [
|
|
37
|
+
"opencv-python",
|
|
38
|
+
"numpy",
|
|
39
|
+
"tensorflow",
|
|
40
|
+
"scikit-image",
|
|
41
|
+
"PyYAML"
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.setuptools]
|
|
45
|
+
include-package-data = true
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
include = ["image_enhancer*"]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
|
|
3
|
+
from utils.blur_module import *
|
|
4
|
+
|
|
5
|
+
img = cv2.imread("input/test.png")
|
|
6
|
+
|
|
7
|
+
output,score,level,motion,confidence=fix_blur(img)
|
|
8
|
+
|
|
9
|
+
print("\n========== BLUR REPORT ==========\n")
|
|
10
|
+
|
|
11
|
+
print("Blur Score :",round(score,2))
|
|
12
|
+
|
|
13
|
+
print("Blur Level :",level)
|
|
14
|
+
|
|
15
|
+
print("Motion Blur :",motion)
|
|
16
|
+
|
|
17
|
+
print("Confidence :",confidence)
|
|
18
|
+
|
|
19
|
+
cv2.imwrite("../output/test_blur.jpg",output)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
|
|
3
|
+
from utils.quality_metrics import *
|
|
4
|
+
|
|
5
|
+
original = cv2.imread("input/test.png")
|
|
6
|
+
|
|
7
|
+
enhanced = cv2.imread("output/6_final.jpg")
|
|
8
|
+
|
|
9
|
+
report = quality_report(original, enhanced)
|
|
10
|
+
|
|
11
|
+
print()
|
|
12
|
+
|
|
13
|
+
print("==============================")
|
|
14
|
+
|
|
15
|
+
print(" IMAGE QUALITY REPORT ")
|
|
16
|
+
|
|
17
|
+
print("==============================")
|
|
18
|
+
|
|
19
|
+
print("MSE :", round(report["mse"],2))
|
|
20
|
+
|
|
21
|
+
print("PSNR :", round(report["psnr"],2),"dB")
|
|
22
|
+
|
|
23
|
+
print("SSIM :", round(report["ssim"],4))
|
|
24
|
+
|
|
25
|
+
print("Grade :", report["grade"])
|
|
26
|
+
|
|
27
|
+
print("==============================")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
|
|
3
|
+
from utils.rotation_module import detect_minor_rotation, rotate_image
|
|
4
|
+
|
|
5
|
+
img=cv2.imread("input/test.png")
|
|
6
|
+
|
|
7
|
+
angle=detect_minor_rotation(img)
|
|
8
|
+
|
|
9
|
+
print("Detected Angle :",round(angle,2))
|
|
10
|
+
|
|
11
|
+
corrected=rotate_image(img,angle)
|
|
12
|
+
|
|
13
|
+
cv2.imwrite("output/minor_rotation.jpg",corrected)
|