random2222 commited on
Commit
ea3cae7
·
verified ·
1 Parent(s): 11e6f59

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +323 -132
app.py CHANGED
@@ -1,166 +1,357 @@
1
- import gradio as gr
2
  import cv2
3
  import numpy as np
4
  import os
5
- import tempfile
6
  from PIL import Image
 
 
 
 
 
 
 
7
 
8
  # ------------------- Black & White Converter Functions ------------------- #
9
  def convert_to_black_white(image, threshold_value=127, method="otsu"):
10
- """Convert image to black and white using various thresholding methods"""
11
- # Convert from PIL to OpenCV format if needed
12
- if isinstance(image, np.ndarray) and len(image.shape) == 3:
13
- # Handle RGB or RGBA to BGR conversion
14
- if image.shape[2] == 4: # RGBA
15
- image = cv2.cvtColor(image, cv2.COLOR_RGBA2BGR)
16
- elif image.shape[2] == 3: # RGB
17
- image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
18
 
19
- # Convert to grayscale
20
- gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
 
 
21
 
22
- # Apply thresholding based on method
23
  if method == "adaptive":
24
  binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
25
- cv2.THRESH_BINARY, 11, 2)
26
  elif method == "otsu":
27
  _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
28
- else: # manual
29
  _, binary = cv2.threshold(gray, threshold_value, 255, cv2.THRESH_BINARY)
30
 
31
  return binary
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  # ------------------- Pencil Sketch Converter Functions ------------------- #
34
- def convert_to_sketch(image, intensity=255, blur_ksize=21, sigma=0):
35
- """Convert image to pencil sketch effect"""
36
- # Convert from PIL to OpenCV format if needed
37
- if isinstance(image, np.ndarray) and len(image.shape) == 3:
38
- # Handle RGB or RGBA to BGR conversion
39
- if image.shape[2] == 4: # RGBA
40
- image = cv2.cvtColor(image, cv2.COLOR_RGBA2BGR)
41
- elif image.shape[2] == 3: # RGB
42
- image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
 
 
 
 
43
 
44
  # Convert to grayscale
45
- gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
46
 
47
- # Invert grayscale image
48
  inverted = cv2.bitwise_not(gray)
49
-
50
- # Ensure kernel size is odd
51
- blur_ksize = blur_ksize if blur_ksize % 2 == 1 else blur_ksize + 1
52
-
53
- # Apply Gaussian blur to the inverted image
54
  blurred = cv2.GaussianBlur(inverted, (blur_ksize, blur_ksize), sigma)
55
-
56
- # Blend the grayscale image with the blurred inverse
57
  sketch = cv2.divide(gray, cv2.bitwise_not(blurred), scale=intensity)
58
 
59
- return sketch
60
 
61
- # ------------------- Image Processing Functions ------------------- #
62
- def process_black_white(image, threshold, method):
63
- """Main function for black and white processing"""
64
- if image is None:
65
- return None
66
- result = convert_to_black_white(image, threshold, method)
67
- return result
68
-
69
- def process_sketch(image, intensity, blur_ksize, sigma):
70
- """Main function for sketch processing"""
71
- if image is None:
72
- return None
73
- result = convert_to_sketch(image, intensity, blur_ksize, sigma)
74
- return result
75
 
76
- # ------------------- Gradio App Construction ------------------- #
77
- with gr.Blocks(title="Image Processing Tool") as demo:
78
- gr.Markdown("# Image Processing Tool")
79
-
80
- with gr.Tab("Black & White Converter"):
81
- with gr.Row():
82
- with gr.Column():
83
- bw_input = gr.Image(label="Input Image")
84
- bw_method = gr.Radio(
85
- choices=["otsu", "adaptive", "manual"],
86
- value="otsu",
87
- label="Thresholding Method"
88
- )
89
- bw_threshold = gr.Slider(
90
- minimum=0,
91
- maximum=255,
92
- value=127,
93
- step=1,
94
- label="Threshold Value (for Manual method)"
95
- )
96
- bw_button = gr.Button("Convert to Black & White")
 
 
 
 
 
 
97
 
98
- with gr.Column():
99
- bw_output = gr.Image(label="Output Image")
100
-
101
- def update_threshold_visibility(method):
102
- """Show/hide threshold slider based on method selection"""
103
- return gr.update(visible=(method == "manual"))
104
-
105
- # Connect components
106
- bw_method.change(
107
- fn=update_threshold_visibility,
108
- inputs=bw_method,
109
- outputs=bw_threshold
110
- )
111
 
112
- bw_button.click(
113
- fn=process_black_white,
114
- inputs=[bw_input, bw_threshold, bw_method],
115
- outputs=bw_output
116
- )
 
 
 
 
 
 
 
 
 
117
 
118
- with gr.Tab("Pencil Sketch Converter"):
119
- with gr.Row():
120
- with gr.Column():
121
- sketch_input = gr.Image(label="Input Image")
122
- sketch_intensity = gr.Slider(
123
- minimum=1,
124
- maximum=255,
125
- value=255,
126
- step=1,
127
- label="Intensity (1-255)"
128
- )
129
- sketch_blur = gr.Slider(
130
- minimum=1,
131
- maximum=99,
132
- value=21,
133
- step=2,
134
- label="Blur Kernel Size (odd values from 1-99)"
135
- )
136
- sketch_sigma = gr.Slider(
137
- minimum=0,
138
- maximum=50,
139
- value=0,
140
- step=0.1,
141
- label="Standard Deviation (0-50)"
142
- )
143
- sketch_button = gr.Button("Convert to Pencil Sketch")
144
-
145
- with gr.Column():
146
- sketch_output = gr.Image(label="Output Image")
147
-
148
- # Connect components
149
- sketch_button.click(
150
- fn=process_sketch,
151
- inputs=[sketch_input, sketch_intensity, sketch_blur, sketch_sigma],
152
- outputs=sketch_output
153
- )
154
 
155
- gr.Markdown("""
156
- ## About this app
157
- This tool provides two image processing capabilities:
 
158
 
159
- 1. **Black & White Converter**: Convert images to binary (black and white) using different thresholding methods
160
- 2. **Pencil Sketch Converter**: Create artistic pencil sketch effects with customizable parameters
161
 
162
- Upload an image, adjust the parameters, and click the conversion button to see the results.
163
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
- # Launch the Gradio app
166
- demo.launch()
 
 
 
1
  import cv2
2
  import numpy as np
3
  import os
4
+ import gradio as gr
5
  from PIL import Image
6
+ import tempfile
7
+
8
+ # Enable OpenCL for better performance if available
9
+ try:
10
+ cv2.ocl.setUseOpenCL(True)
11
+ except:
12
+ pass # OpenCL might not be available in all environments
13
 
14
  # ------------------- Black & White Converter Functions ------------------- #
15
  def convert_to_black_white(image, threshold_value=127, method="otsu"):
16
+ """Convert image to black and white using specified thresholding method"""
17
+ if isinstance(image, str):
18
+ image = cv2.imread(image)
 
 
 
 
 
19
 
20
+ # Convert to grayscale if not already
21
+ if len(image.shape) == 3:
22
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
23
+ else:
24
+ gray = image
25
 
 
26
  if method == "adaptive":
27
  binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
28
+ cv2.THRESH_BINARY, 11, 2)
29
  elif method == "otsu":
30
  _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
31
+ else:
32
  _, binary = cv2.threshold(gray, threshold_value, 255, cv2.THRESH_BINARY)
33
 
34
  return binary
35
 
36
+ def process_image_bw(image, threshold_method, threshold_value):
37
+ """Process image with black and white thresholding for Gradio"""
38
+ if image is None:
39
+ raise gr.Error("No image provided")
40
+
41
+ if threshold_method != "manual":
42
+ threshold_value = 0 # Not used for adaptive or Otsu
43
+
44
+ # Convert to numpy array if PIL Image
45
+ if isinstance(image, Image.Image):
46
+ image_np = np.array(image)
47
+ # Convert RGB to BGR for OpenCV
48
+ if len(image_np.shape) == 3:
49
+ image_np = cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)
50
+ else:
51
+ image_np = image
52
+
53
+ result = convert_to_black_white(image_np, threshold_value, threshold_method)
54
+ return Image.fromarray(result)
55
+
56
+ def process_video_bw(video_path, threshold_method, threshold_value):
57
+ """Process video with black and white filter for Gradio"""
58
+ if video_path is None:
59
+ raise gr.Error("No video provided")
60
+
61
+ if threshold_method != "manual":
62
+ threshold_value = 0 # Not used for adaptive or Otsu
63
+
64
+ try:
65
+ cap = cv2.VideoCapture(video_path)
66
+ if not cap.isOpened():
67
+ raise gr.Error("Could not open video file")
68
+
69
+ # Get video properties
70
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
71
+ frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
72
+ frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
73
+ fps = int(cap.get(cv2.CAP_PROP_FPS))
74
+
75
+ # Create temporary output file
76
+ temp_output = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False)
77
+ output_path = temp_output.name
78
+ temp_output.close()
79
+
80
+ # Create video writer
81
+ out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height), isColor=False)
82
+
83
+ # Process each frame
84
+ while cap.isOpened():
85
+ ret, frame = cap.read()
86
+ if not ret:
87
+ break
88
+
89
+ bw_frame = convert_to_black_white(frame, threshold_value, threshold_method)
90
+ out.write(bw_frame)
91
+
92
+ cap.release()
93
+ out.release()
94
+
95
+ return output_path
96
+ except Exception as e:
97
+ raise gr.Error(f"Error processing video: {str(e)}")
98
+
99
  # ------------------- Pencil Sketch Converter Functions ------------------- #
100
+ def process_image_sketch(image, intensity, blur_ksize, sigma):
101
+ """Process image with pencil sketch effect for Gradio"""
102
+ if image is None:
103
+ raise gr.Error("No image provided")
104
+
105
+ # Convert to numpy array if PIL Image
106
+ if isinstance(image, Image.Image):
107
+ image_np = np.array(image)
108
+ # Convert RGB to BGR for OpenCV
109
+ if len(image_np.shape) == 3:
110
+ image_np = cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)
111
+ else:
112
+ image_np = image
113
 
114
  # Convert to grayscale
115
+ gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY) if len(image_np.shape) == 3 else image_np
116
 
117
+ # Create sketch effect
118
  inverted = cv2.bitwise_not(gray)
119
+ blur_ksize = blur_ksize if blur_ksize % 2 == 1 else blur_ksize + 1 # Ensure kernel size is odd
 
 
 
 
120
  blurred = cv2.GaussianBlur(inverted, (blur_ksize, blur_ksize), sigma)
 
 
121
  sketch = cv2.divide(gray, cv2.bitwise_not(blurred), scale=intensity)
122
 
123
+ return Image.fromarray(sketch)
124
 
125
+ def process_video_sketch(video_path, intensity, blur_ksize, sigma):
126
+ """Process video with pencil sketch effect for Gradio"""
127
+ if video_path is None:
128
+ raise gr.Error("No video provided")
129
+
130
+ try:
131
+ cap = cv2.VideoCapture(video_path)
132
+ if not cap.isOpened():
133
+ raise gr.Error("Could not open video file")
 
 
 
 
 
134
 
135
+ # Get video properties
136
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
137
+ frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
138
+ frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
139
+ fps = int(cap.get(cv2.CAP_PROP_FPS))
140
+
141
+ # Create temporary output file
142
+ temp_output = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False)
143
+ output_path = temp_output.name
144
+ temp_output.close()
145
+
146
+ # Create video writer
147
+ out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height), isColor=True)
148
+
149
+ # Process each frame
150
+ while cap.isOpened():
151
+ ret, frame = cap.read()
152
+ if not ret:
153
+ break
154
+
155
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
156
+ inverted = cv2.bitwise_not(gray)
157
+ blur_ksize_adj = blur_ksize if blur_ksize % 2 == 1 else blur_ksize + 1
158
+ blurred = cv2.GaussianBlur(inverted, (blur_ksize_adj, blur_ksize_adj), sigma)
159
+ sketch = cv2.divide(gray, cv2.bitwise_not(blurred), scale=intensity)
160
+ sketch_bgr = cv2.cvtColor(sketch, cv2.COLOR_GRAY2BGR)
161
+ out.write(sketch_bgr)
162
 
163
+ cap.release()
164
+ out.release()
 
 
 
 
 
 
 
 
 
 
 
165
 
166
+ return output_path
167
+ except Exception as e:
168
+ raise gr.Error(f"Error processing video: {str(e)}")
169
+
170
+ # ------------------- Create Gradio Interface ------------------- #
171
+ def update_blur(value):
172
+ """Ensure blur kernel size is always odd"""
173
+ return value if value % 2 == 1 else value + 1
174
+
175
+ def create_interface():
176
+ # App title and description
177
+ title = "Image & Video Processor"
178
+ description = """
179
+ # Image and Video Processing App
180
 
181
+ This app provides tools to convert images and videos to black & white or pencil sketch styles.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
+ ## Features:
184
+ - **Black & White Conversion**: Apply different thresholding methods
185
+ - **Pencil Sketch Effect**: Create artistic pencil drawings with customizable parameters
186
+ - **Support for both images and videos**
187
 
188
+ Made with ❤️ using Gradio and OpenCV
189
+ """
190
 
191
+ # Black and White Image Interface
192
+ with gr.Blocks(title=title) as app:
193
+ gr.Markdown(description)
194
+
195
+ with gr.Tab("Black & White Converter"):
196
+ with gr.Tab("Image"):
197
+ with gr.Row():
198
+ with gr.Column():
199
+ bw_image_input = gr.Image(label="Input Image", type="numpy")
200
+ bw_method = gr.Radio(
201
+ choices=["otsu", "adaptive", "manual"],
202
+ value="otsu",
203
+ label="Thresholding Method"
204
+ )
205
+ bw_threshold = gr.Slider(
206
+ minimum=0,
207
+ maximum=255,
208
+ value=127,
209
+ step=1,
210
+ label="Manual Threshold (0-255)",
211
+ interactive=True
212
+ )
213
+ bw_image_btn = gr.Button("Convert to Black & White")
214
+
215
+ with gr.Column():
216
+ bw_image_output = gr.Image(label="Processed Image")
217
+
218
+ # Show/hide threshold slider based on method
219
+ def update_threshold_visibility(method):
220
+ return gr.update(visible=(method == "manual"))
221
+
222
+ bw_method.change(fn=update_threshold_visibility, inputs=bw_method, outputs=bw_threshold)
223
+
224
+ with gr.Tab("Video"):
225
+ with gr.Row():
226
+ with gr.Column():
227
+ bw_video_input = gr.Video(label="Input Video")
228
+ bw_video_method = gr.Radio(
229
+ choices=["otsu", "adaptive", "manual"],
230
+ value="otsu",
231
+ label="Thresholding Method"
232
+ )
233
+ bw_video_threshold = gr.Slider(
234
+ minimum=0,
235
+ maximum=255,
236
+ value=127,
237
+ step=1,
238
+ label="Manual Threshold (0-255)",
239
+ interactive=True
240
+ )
241
+ bw_video_btn = gr.Button("Convert to Black & White")
242
+
243
+ with gr.Column():
244
+ bw_video_output = gr.Video(label="Processed Video")
245
+
246
+ # Show/hide threshold slider based on method
247
+ bw_video_method.change(fn=update_threshold_visibility, inputs=bw_video_method, outputs=bw_video_threshold)
248
+
249
+ with gr.Tab("Pencil Sketch Converter"):
250
+ with gr.Tab("Image"):
251
+ with gr.Row():
252
+ with gr.Column():
253
+ sketch_image_input = gr.Image(label="Input Image", type="numpy")
254
+ sketch_intensity = gr.Slider(
255
+ minimum=1,
256
+ maximum=255,
257
+ value=255,
258
+ step=1,
259
+ label="Intensity (1-255)"
260
+ )
261
+ sketch_blur = gr.Slider(
262
+ minimum=1,
263
+ maximum=99,
264
+ value=21,
265
+ step=2,
266
+ label="Blur Kernel Size (odd, 1-99)"
267
+ )
268
+ sketch_sigma = gr.Slider(
269
+ minimum=0,
270
+ maximum=50,
271
+ value=0,
272
+ step=0.1,
273
+ label="Standard Deviation (0-50)"
274
+ )
275
+ sketch_image_btn = gr.Button("Convert to Pencil Sketch")
276
+
277
+ with gr.Column():
278
+ sketch_image_output = gr.Image(label="Processed Image")
279
+
280
+ with gr.Tab("Video"):
281
+ with gr.Row():
282
+ with gr.Column():
283
+ sketch_video_input = gr.Video(label="Input Video")
284
+ sketch_video_intensity = gr.Slider(
285
+ minimum=1,
286
+ maximum=255,
287
+ value=255,
288
+ step=1,
289
+ label="Intensity (1-255)"
290
+ )
291
+ sketch_video_blur = gr.Slider(
292
+ minimum=1,
293
+ maximum=99,
294
+ value=21,
295
+ step=2,
296
+ label="Blur Kernel Size (odd, 1-99)"
297
+ )
298
+ sketch_video_sigma = gr.Slider(
299
+ minimum=0,
300
+ maximum=50,
301
+ value=0,
302
+ step=0.1,
303
+ label="Standard Deviation (0-50)"
304
+ )
305
+ sketch_video_btn = gr.Button("Convert to Pencil Sketch")
306
+
307
+ with gr.Column():
308
+ sketch_video_output = gr.Video(label="Processed Video")
309
+
310
+ # Examples section
311
+ with gr.Accordion("Examples", open=False):
312
+ gr.Markdown("""
313
+ ## Example Usage:
314
+
315
+ 1. **Black & White Conversion**: Great for document scanning, text enhancement, or artistic effects
316
+ 2. **Pencil Sketch**: Perfect for creating artistic renderings from photos
317
+
318
+ Try uploading your own images or videos!
319
+ """)
320
+
321
+ # Set up event listeners
322
+ bw_image_btn.click(
323
+ fn=process_image_bw,
324
+ inputs=[bw_image_input, bw_method, bw_threshold],
325
+ outputs=bw_image_output
326
+ )
327
+
328
+ bw_video_btn.click(
329
+ fn=process_video_bw,
330
+ inputs=[bw_video_input, bw_video_method, bw_video_threshold],
331
+ outputs=bw_video_output
332
+ )
333
+
334
+ sketch_image_btn.click(
335
+ fn=process_image_sketch,
336
+ inputs=[sketch_image_input, sketch_intensity, sketch_blur, sketch_sigma],
337
+ outputs=sketch_image_output
338
+ )
339
+
340
+ sketch_video_btn.click(
341
+ fn=process_video_sketch,
342
+ inputs=[sketch_video_input, sketch_video_intensity, sketch_video_blur, sketch_video_sigma],
343
+ outputs=sketch_video_output
344
+ )
345
+
346
+ # Make blur slider always odd
347
+ sketch_blur.change(update_blur, sketch_blur, sketch_blur)
348
+ sketch_video_blur.change(update_blur, sketch_video_blur, sketch_video_blur)
349
+
350
+ return app
351
+
352
+ # Create and launch the app
353
+ app = create_interface()
354
 
355
+ # This is needed for Hugging Face Spaces
356
+ if __name__ == "__main__":
357
+ app.launch()