ElBeh commited on
Commit
2dd4abe
·
verified ·
1 Parent(s): 13abd12

Upload image_processing.py

Browse files
Files changed (1) hide show
  1. processing/image_processing.py +249 -0
processing/image_processing.py ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # image_processing.py
2
+ from PIL import Image
3
+ import numpy as np
4
+ import cv2
5
+ from io import BytesIO
6
+ try:
7
+ import pywt
8
+ PYWT_AVAILABLE = True
9
+ except ImportError:
10
+ PYWT_AVAILABLE = False
11
+
12
+ def laplacian_highpass(img):
13
+ """Applies Laplacian high-pass filter to emphasize high frequencies."""
14
+ arr = np.array(img)
15
+
16
+ # Convert to grayscale if needed
17
+ if len(arr.shape) == 3:
18
+ gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY)
19
+ else:
20
+ gray = arr
21
+
22
+ # Apply Laplacian
23
+ laplacian = cv2.Laplacian(gray, cv2.CV_64F, ksize=3)
24
+
25
+ # Normalize to 0-255
26
+ laplacian_norm = np.absolute(laplacian)
27
+ laplacian_norm = np.uint8(255 * laplacian_norm / np.max(laplacian_norm)) if np.max(laplacian_norm) > 0 else np.uint8(laplacian_norm)
28
+
29
+ return Image.fromarray(laplacian_norm)
30
+
31
+ def fft_spectrum(img):
32
+ """Computes 2D FFT and visualizes log-scaled magnitude spectrum."""
33
+ arr = np.array(img)
34
+
35
+ # Convert to grayscale
36
+ if len(arr.shape) == 3:
37
+ gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY)
38
+ else:
39
+ gray = arr
40
+
41
+ # Compute FFT
42
+ f_transform = np.fft.fft2(gray)
43
+ f_shift = np.fft.fftshift(f_transform)
44
+
45
+ # Magnitude spectrum (log scale)
46
+ magnitude_spectrum = np.abs(f_shift)
47
+ magnitude_spectrum = np.log1p(magnitude_spectrum)
48
+
49
+ # Normalize to 0-255
50
+ magnitude_spectrum = np.uint8(255 * magnitude_spectrum / np.max(magnitude_spectrum))
51
+
52
+ return Image.fromarray(magnitude_spectrum)
53
+
54
+ def error_level_analysis(img, quality=90):
55
+ """Performs Error Level Analysis via JPEG re-compression."""
56
+ arr = np.array(img)
57
+
58
+ # Save with specified quality
59
+ buffer = BytesIO()
60
+ Image.fromarray(arr).save(buffer, format='JPEG', quality=quality)
61
+ buffer.seek(0)
62
+
63
+ # Reload compressed image
64
+ compressed_img = Image.open(buffer)
65
+ compressed_arr = np.array(compressed_img)
66
+
67
+ # Compute difference
68
+ diff = cv2.absdiff(arr, compressed_arr)
69
+
70
+ # Enhance differences
71
+ diff = cv2.multiply(diff, 10)
72
+
73
+ # Convert to grayscale if color
74
+ if len(diff.shape) == 3:
75
+ diff = cv2.cvtColor(diff, cv2.COLOR_RGB2GRAY)
76
+
77
+ return Image.fromarray(diff)
78
+
79
+ def wavelet_decomposition(img):
80
+ """Decomposes image into wavelet subbands (LL, LH, HL, HH)."""
81
+ if not PYWT_AVAILABLE:
82
+ # Fallback: return grayscale
83
+ arr = np.array(img)
84
+ if len(arr.shape) == 3:
85
+ gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY)
86
+ else:
87
+ gray = arr
88
+ return Image.fromarray(gray)
89
+
90
+ arr = np.array(img)
91
+
92
+ # Convert to grayscale
93
+ if len(arr.shape) == 3:
94
+ gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY)
95
+ else:
96
+ gray = arr
97
+
98
+ # Perform 2D wavelet decomposition
99
+ coeffs = pywt.dwt2(gray, 'haar')
100
+ LL, (LH, HL, HH) = coeffs
101
+
102
+ # Normalize each subband
103
+ def normalize(band):
104
+ band = np.abs(band)
105
+ if np.max(band) > 0:
106
+ return np.uint8(255 * band / np.max(band))
107
+ return np.uint8(band)
108
+
109
+ LL_norm = normalize(LL)
110
+ LH_norm = normalize(LH)
111
+ HL_norm = normalize(HL)
112
+ HH_norm = normalize(HH)
113
+
114
+ # Combine into single image (2x2 grid)
115
+ top = np.hstack([LL_norm, LH_norm])
116
+ bottom = np.hstack([HL_norm, HH_norm])
117
+ combined = np.vstack([top, bottom])
118
+
119
+ return Image.fromarray(combined)
120
+
121
+ def noise_extraction(img):
122
+ """Extracts and amplifies noise via high-pass filter."""
123
+ arr = np.array(img)
124
+
125
+ # Convert to grayscale
126
+ if len(arr.shape) == 3:
127
+ gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY)
128
+ else:
129
+ gray = arr
130
+
131
+ # Apply strong Gaussian blur
132
+ blurred = cv2.GaussianBlur(gray, (15, 15), 0)
133
+
134
+ # Subtract to get high-frequency content (noise)
135
+ noise = cv2.subtract(gray, blurred)
136
+
137
+ # Amplify noise
138
+ noise = cv2.multiply(noise, 5)
139
+
140
+ return Image.fromarray(noise)
141
+
142
+ def ycbcr_channels(img):
143
+ """Converts to YCbCr and visualizes chrominance channels."""
144
+ arr = np.array(img)
145
+
146
+ # Convert RGB to YCbCr
147
+ if len(arr.shape) == 3:
148
+ ycbcr = cv2.cvtColor(arr, cv2.COLOR_RGB2YCrCb)
149
+
150
+ # Extract channels
151
+ Y, Cr, Cb = cv2.split(ycbcr)
152
+
153
+ # Create combined visualization (Y on top, Cr and Cb side by side below)
154
+ h, w = Y.shape
155
+
156
+ # Resize Cr and Cb to half width
157
+ Cr_resized = cv2.resize(Cr, (w//2, h//2))
158
+ Cb_resized = cv2.resize(Cb, (w//2, h//2))
159
+
160
+ # Combine
161
+ bottom = np.hstack([Cr_resized, Cb_resized])
162
+ Y_resized = cv2.resize(Y, (w, h//2))
163
+ combined = np.vstack([Y_resized, bottom])
164
+
165
+ return Image.fromarray(combined)
166
+ else:
167
+ return Image.fromarray(arr)
168
+
169
+ def gradient_magnitude(img):
170
+ """Computes gradient magnitude using Sobel operator."""
171
+ arr = np.array(img)
172
+
173
+ # Convert to grayscale
174
+ if len(arr.shape) == 3:
175
+ gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY)
176
+ else:
177
+ gray = arr
178
+
179
+ # Compute gradients
180
+ grad_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
181
+ grad_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
182
+
183
+ # Compute magnitude
184
+ magnitude = np.sqrt(grad_x**2 + grad_y**2)
185
+
186
+ # Normalize
187
+ magnitude = np.uint8(255 * magnitude / np.max(magnitude)) if np.max(magnitude) > 0 else np.uint8(magnitude)
188
+
189
+ return Image.fromarray(magnitude)
190
+
191
+ def histogram_stretching(img):
192
+ """Applies extreme contrast stretching."""
193
+ arr = np.array(img)
194
+
195
+ # Process each channel separately
196
+ if len(arr.shape) == 3:
197
+ result = np.zeros_like(arr)
198
+ for i in range(arr.shape[2]):
199
+ channel = arr[:, :, i]
200
+ # Stretch to full range
201
+ min_val = np.min(channel)
202
+ max_val = np.max(channel)
203
+ if max_val > min_val:
204
+ stretched = 255 * (channel - min_val) / (max_val - min_val)
205
+ result[:, :, i] = np.uint8(stretched)
206
+ else:
207
+ result[:, :, i] = channel
208
+ return Image.fromarray(result)
209
+ else:
210
+ # Grayscale
211
+ min_val = np.min(arr)
212
+ max_val = np.max(arr)
213
+ if max_val > min_val:
214
+ stretched = 255 * (arr - min_val) / (max_val - min_val)
215
+ return Image.fromarray(np.uint8(stretched))
216
+ return Image.fromarray(arr)
217
+
218
+ def process_image(slider_input, transformation):
219
+ """Applies the selected transformation."""
220
+ # Extract image from slider input
221
+ if slider_input is None:
222
+ return None
223
+
224
+ # If it's a tuple, take the first image
225
+ if isinstance(slider_input, tuple):
226
+ img = slider_input[0]
227
+ else:
228
+ img = slider_input
229
+
230
+ if img is None:
231
+ return None
232
+
233
+ # Select the corresponding function
234
+ transform_functions = {
235
+ "Laplacian High-Pass": laplacian_highpass,
236
+ "FFT Spectrum": fft_spectrum,
237
+ "Error Level Analysis": error_level_analysis,
238
+ "Wavelet Decomposition": wavelet_decomposition,
239
+ "Noise Extraction": noise_extraction,
240
+ "YCbCr Channels": ycbcr_channels,
241
+ "Gradient Magnitude": gradient_magnitude,
242
+ "Histogram Stretching": histogram_stretching
243
+ }
244
+
245
+ transform_func = transform_functions.get(transformation, laplacian_highpass)
246
+ transformed = transform_func(img)
247
+
248
+ # Return as tuple for ImageSlider
249
+ return (img, transformed)