random2222 commited on
Commit
518eb83
·
verified ·
1 Parent(s): b824a46

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +273 -376
app.py CHANGED
@@ -4,10 +4,160 @@ import os
4
  import gradio as gr
5
  from PIL import Image
6
  import tempfile
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  # Enable OpenCL for better performance
9
  cv2.ocl.setUseOpenCL(True)
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  # ------------------- Black & White Converter Functions ------------------- #
12
  def convert_to_black_white(image, threshold_value=127, method="otsu"):
13
  """Convert image to black and white using specified thresholding method"""
@@ -188,412 +338,178 @@ def sketch_video(video, intensity, blur_ksize, sigma):
188
  else:
189
  raise gr.Error(message)
190
 
191
- # Tooltips and Help Text
192
- TOOLTIPS = {
193
- "otsu": "Otsu's method automatically determines the optimal threshold value by minimizing variance between black and white pixels.",
194
- "adaptive": "Adaptive thresholding calculates different thresholds for different regions of the image, useful for images with varying lighting.",
195
- "manual": "Manually set a threshold value between 0-255. Lower values create more white pixels, higher values create more black pixels.",
196
- "intensity": "Controls the contrast of the sketch. Higher values create darker lines.",
197
- "blur": "Controls the smoothness of the sketch. Higher values create softer, more blended lines.",
198
- "sigma": "Controls the edge detection sensitivity. Higher values detect finer details."
199
- }
200
-
201
  # ------------------- Create Gradio Interface ------------------- #
202
  def create_interface():
203
- # Custom CSS for better UI
204
- css = """
205
- /* Global styles */
206
- body {
207
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
208
- }
209
-
210
- /* Improved container styling */
211
- .container {
212
- max-width: 1200px;
213
- margin: 0 auto;
214
- padding: 20px;
215
- }
216
-
217
- /* Card styling */
218
- .gr-box, .gr-card {
219
- border-radius: 12px !important;
220
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
221
- padding: 18px !important;
222
- margin: 12px 0 !important;
223
- background-color: #ffffff;
224
- border: 1px solid #eaeaea;
225
- }
226
-
227
- /* Tab styling */
228
- .tabs {
229
- margin-bottom: 16px !important;
230
- }
231
-
232
- .tab-nav {
233
- padding: 8px 16px !important;
234
- font-size: 16px !important;
235
- font-weight: 500 !important;
236
- }
237
-
238
- /* Button styling */
239
- button.primary {
240
- background: linear-gradient(135deg, #4f46e5, #6366f1) !important;
241
- border-radius: 8px !important;
242
- font-weight: 600 !important;
243
- padding: 10px 20px !important;
244
- border: none !important;
245
- color: white !important;
246
- box-shadow: 0 4px 6px rgba(99, 102, 241, 0.25) !important;
247
- transition: all 0.3s ease !important;
248
- }
249
-
250
- button.primary:hover {
251
- box-shadow: 0 6px 10px rgba(99, 102, 241, 0.35) !important;
252
- transform: translateY(-1px) !important;
253
- }
254
-
255
- /* Slider styling */
256
- .gr-slider {
257
- height: 8px !important;
258
- }
259
-
260
- /* Radio button styling */
261
- .gr-radio {
262
- padding: 12px 0 !important;
263
- }
264
-
265
- /* Label styling */
266
- label {
267
- font-size: 15px !important;
268
- font-weight: 500 !important;
269
- margin-bottom: 6px !important;
270
- color: #333 !important;
271
- }
272
-
273
- /* Tooltip styling */
274
- .tooltip {
275
- position: relative;
276
- display: inline-block;
277
- margin-left: 6px;
278
- }
279
-
280
- .tooltip-icon {
281
- color: #6b7280;
282
- font-size: 16px;
283
- cursor: pointer;
284
- }
285
-
286
- .tooltip-text {
287
- visibility: hidden;
288
- width: 220px;
289
- background-color: #374151;
290
- color: #fff;
291
- text-align: center;
292
- border-radius: 6px;
293
- padding: 8px;
294
- position: absolute;
295
- z-index: 1;
296
- bottom: 125%;
297
- left: 50%;
298
- margin-left: -110px;
299
- opacity: 0;
300
- transition: opacity 0.3s;
301
- font-size: 13px;
302
- pointer-events: none;
303
- }
304
-
305
- .tooltip:hover .tooltip-text {
306
- visibility: visible;
307
- opacity: 1;
308
- }
309
-
310
- /* Responsive adjustments */
311
- @media (max-width: 768px) {
312
- .container {
313
- padding: 10px;
314
- }
315
-
316
- .gr-box, .gr-card {
317
- padding: 14px !important;
318
- }
319
-
320
- label {
321
- font-size: 14px !important;
322
- }
323
- }
324
- """
325
-
326
- # Helper function for tooltips
327
- def create_tooltip(label, tooltip_text):
328
- return f"""
329
- <div style="display: flex; align-items: center;">
330
- <span>{label}</span>
331
- <div class="tooltip">
332
- <span class="tooltip-icon">ⓘ</span>
333
- <span class="tooltip-text">{tooltip_text}</span>
334
- </div>
335
- </div>
336
- """
337
 
338
  # Black and White Image Interface
339
- with gr.Blocks(title="Image Processor", css=css) as app:
340
- gr.Markdown(
341
- """
342
  # Image and Video Processor
343
- ### Transform your media with Black & White and Pencil Sketch effects
344
- """,
345
- elem_classes=["container"]
346
- )
347
 
348
  with gr.Tabs() as tabs:
349
- with gr.TabItem("Black & White Converter", id="bw-tab"):
350
  with gr.Tabs() as bw_tabs:
351
- with gr.TabItem("Image Processing", id="bw-image-tab"):
352
  with gr.Row(equal_height=True):
353
  with gr.Column(scale=1):
354
- bw_image_input = gr.Image(
355
- label="Upload Image",
356
- elem_id="bw-input",
357
- height=300
358
- )
359
 
360
  with gr.Group():
 
361
  bw_method = gr.Radio(
362
  choices=["otsu", "adaptive", "manual"],
363
  value="otsu",
364
  label="",
365
- elem_id="bw-method"
366
  )
367
 
368
- gr.HTML(create_tooltip("Thresholding Method", "Choose how the image will be converted to black and white"))
 
 
 
 
 
 
 
 
 
369
 
370
- with gr.Row(visible=False) as threshold_row:
371
- bw_threshold = gr.Slider(
372
- minimum=0,
373
- maximum=255,
374
- value=127,
375
- step=1,
376
- label="Manual Threshold",
377
- elem_id="bw-threshold",
378
- interactive=True
379
- )
380
-
381
- gr.HTML(create_tooltip("", TOOLTIPS["manual"]))
382
-
383
- bw_image_btn = gr.Button(
384
- "Convert to Black & White",
385
- variant="primary",
386
- elem_id="bw-convert-btn"
387
- )
388
 
389
  with gr.Column(scale=1):
390
- bw_image_output = gr.Image(
391
- label="Processed Image",
392
- elem_id="bw-output",
393
- height=300
394
- )
395
-
396
- with gr.Accordion("About Black & White Conversion", open=False):
397
- gr.Markdown("""
398
- ### How it works
399
-
400
- Black & white conversion transforms your image into pure black and white pixels using thresholding.
401
-
402
- - **Otsu Method**: Automatically finds the optimal threshold value
403
- - **Adaptive Method**: Uses different thresholds for different areas of the image
404
- - **Manual Threshold**: You control the threshold value between black and white
405
- """)
406
 
407
- with gr.TabItem("Video Processing", id="bw-video-tab"):
408
  with gr.Row(equal_height=True):
409
  with gr.Column(scale=1):
410
- bw_video_input = gr.Video(
411
- label="Upload Video",
412
- elem_id="bw-video-input",
413
- height=300
414
- )
415
 
416
  with gr.Group():
 
417
  bw_video_method = gr.Radio(
418
  choices=["otsu", "adaptive", "manual"],
419
  value="otsu",
420
  label="",
421
- elem_id="bw-video-method"
422
  )
423
 
424
- gr.HTML(create_tooltip("Thresholding Method", "Choose how the video will be converted to black and white"))
 
 
 
 
 
 
 
 
 
425
 
426
- with gr.Row(visible=False) as video_threshold_row:
427
- bw_video_threshold = gr.Slider(
428
- minimum=0,
429
- maximum=255,
430
- value=127,
431
- step=1,
432
- label="Manual Threshold",
433
- elem_id="bw-video-threshold",
434
- interactive=True
435
- )
436
-
437
- gr.HTML(create_tooltip("", TOOLTIPS["manual"]))
438
-
439
- bw_video_btn = gr.Button(
440
- "Convert to Black & White",
441
- variant="primary",
442
- elem_id="bw-video-convert-btn"
443
- )
444
 
445
  with gr.Column(scale=1):
446
- bw_video_output = gr.Video(
447
- label="Processed Video",
448
- elem_id="bw-video-output",
449
- height=300
450
- )
451
 
452
- with gr.TabItem("Pencil Sketch Converter", id="sketch-tab"):
453
  with gr.Tabs() as sketch_tabs:
454
- with gr.TabItem("Image Processing", id="sketch-image-tab"):
455
  with gr.Row(equal_height=True):
456
  with gr.Column(scale=1):
457
- sketch_image_input = gr.Image(
458
- label="Upload Image",
459
- elem_id="sketch-input",
460
- height=300
461
- )
462
 
463
  with gr.Group():
464
- with gr.Row():
465
- with gr.Column(scale=4):
466
- sketch_intensity = gr.Slider(
467
- minimum=1,
468
- maximum=255,
469
- value=255,
470
- step=1,
471
- label="Intensity",
472
- elem_id="sketch-intensity"
473
- )
474
-
475
- with gr.Column(scale=1):
476
- gr.HTML(create_tooltip("", TOOLTIPS["intensity"]))
477
 
478
- with gr.Row():
479
- with gr.Column(scale=4):
480
- sketch_blur = gr.Slider(
481
- minimum=1,
482
- maximum=99,
483
- value=21,
484
- step=2,
485
- label="Blur Amount",
486
- elem_id="sketch-blur"
487
- )
488
-
489
- with gr.Column(scale=1):
490
- gr.HTML(create_tooltip("", TOOLTIPS["blur"]))
491
 
492
- with gr.Row():
493
- with gr.Column(scale=4):
494
- sketch_sigma = gr.Slider(
495
- minimum=0,
496
- maximum=50,
497
- value=0,
498
- step=0.1,
499
- label="Detail Level",
500
- elem_id="sketch-sigma"
501
- )
502
-
503
- with gr.Column(scale=1):
504
- gr.HTML(create_tooltip("", TOOLTIPS["sigma"]))
505
-
506
- sketch_image_btn = gr.Button(
507
- "Convert to Pencil Sketch",
508
- variant="primary",
509
- elem_id="sketch-convert-btn"
510
- )
511
 
512
  with gr.Column(scale=1):
513
- sketch_image_output = gr.Image(
514
- label="Processed Image",
515
- elem_id="sketch-output",
516
- height=300
517
- )
518
-
519
- with gr.Accordion("About Pencil Sketch", open=False):
520
- gr.Markdown("""
521
- ### How Pencil Sketch Works
522
-
523
- The pencil sketch effect creates a hand-drawn look by:
524
-
525
- 1. Converting the image to grayscale
526
- 2. Inverting the colors
527
- 3. Applying Gaussian blur
528
- 4. Combining the original grayscale with the blurred inverted image
529
-
530
- Adjust the sliders to get different artistic effects!
531
- """)
532
 
533
- with gr.TabItem("Video Processing", id="sketch-video-tab"):
534
  with gr.Row(equal_height=True):
535
  with gr.Column(scale=1):
536
- sketch_video_input = gr.Video(
537
- label="Upload Video",
538
- elem_id="sketch-video-input",
539
- height=300
540
- )
541
 
542
  with gr.Group():
543
- with gr.Row():
544
- with gr.Column(scale=4):
545
- sketch_video_intensity = gr.Slider(
546
- minimum=1,
547
- maximum=255,
548
- value=255,
549
- step=1,
550
- label="Intensity",
551
- elem_id="sketch-video-intensity"
552
- )
553
-
554
- with gr.Column(scale=1):
555
- gr.HTML(create_tooltip("", TOOLTIPS["intensity"]))
556
 
557
- with gr.Row():
558
- with gr.Column(scale=4):
559
- sketch_video_blur = gr.Slider(
560
- minimum=1,
561
- maximum=99,
562
- value=21,
563
- step=2,
564
- label="Blur Amount",
565
- elem_id="sketch-video-blur"
566
- )
567
-
568
- with gr.Column(scale=1):
569
- gr.HTML(create_tooltip("", TOOLTIPS["blur"]))
570
 
571
- with gr.Row():
572
- with gr.Column(scale=4):
573
- sketch_video_sigma = gr.Slider(
574
- minimum=0,
575
- maximum=50,
576
- value=0,
577
- step=0.1,
578
- label="Detail Level",
579
- elem_id="sketch-video-sigma"
580
- )
581
-
582
- with gr.Column(scale=1):
583
- gr.HTML(create_tooltip("", TOOLTIPS["sigma"]))
584
-
585
- sketch_video_btn = gr.Button(
586
- "Convert to Pencil Sketch",
587
- variant="primary",
588
- elem_id="sketch-video-convert-btn"
589
- )
590
 
591
  with gr.Column(scale=1):
592
- sketch_video_output = gr.Video(
593
- label="Processed Video",
594
- elem_id="sketch-video-output",
595
- height=300
596
- )
 
 
 
 
597
 
598
  # Set up event listeners
599
  bw_image_btn.click(
@@ -620,22 +536,6 @@ def create_interface():
620
  outputs=sketch_video_output
621
  )
622
 
623
- # Show/hide threshold slider based on method selection
624
- def update_threshold_visibility(method):
625
- return gr.update(visible=(method == "manual"))
626
-
627
- bw_method.change(
628
- fn=update_threshold_visibility,
629
- inputs=bw_method,
630
- outputs=threshold_row
631
- )
632
-
633
- bw_video_method.change(
634
- fn=update_threshold_visibility,
635
- inputs=bw_video_method,
636
- outputs=video_threshold_row
637
- )
638
-
639
  # Make blur slider always odd
640
  def update_blur(value):
641
  return value if value % 2 == 1 else value + 1
@@ -643,15 +543,12 @@ def create_interface():
643
  sketch_blur.change(update_blur, sketch_blur, sketch_blur)
644
  sketch_video_blur.change(update_blur, sketch_video_blur, sketch_video_blur)
645
 
646
- # Add tooltips for thresholding methods
647
- def update_method_info(method):
648
- return gr.update(value=create_tooltip("Thresholding Method", TOOLTIPS[method]))
649
 
650
- bw_method.change(
651
- fn=lambda x: TOOLTIPS[x],
652
- inputs=bw_method,
653
- outputs=[] # This is just for showing in the JS console for debugging
654
- )
655
 
656
  return app
657
 
 
4
  import gradio as gr
5
  from PIL import Image
6
  import tempfile
7
+ from typing import Union, Tuple
8
+
9
+ # Custom CSS for styling the interface
10
+ custom_css = """
11
+ .container {
12
+ max-width: 1200px;
13
+ margin: 0 auto;
14
+ }
15
+
16
+ /* Main styling */
17
+ .gradio-container {
18
+ font-family: 'Roboto', 'Segoe UI', sans-serif;
19
+ color: white;
20
+ }
21
+
22
+ /* Card styling */
23
+ .app-card {
24
+ border-radius: 12px;
25
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
26
+ padding: 20px;
27
+ background: linear-gradient(135deg, #2a3a4a 0%, #1e2a3a 100%);
28
+ margin-bottom: 20px;
29
+ }
30
+
31
+ /* Header styling */
32
+ h1, h2, h3 {
33
+ font-weight: 700 !important;
34
+ color: white !important;
35
+ }
36
+
37
+ /* Labels styling */
38
+ label, .label {
39
+ font-size: 1rem !important;
40
+ font-weight: 600 !important;
41
+ color: white !important;
42
+ margin-bottom: 6px !important;
43
+ }
44
+
45
+ /* Input and slider styling */
46
+ .slider-label {
47
+ font-weight: 600 !important;
48
+ color: white !important;
49
+ font-size: 0.95rem !important;
50
+ }
51
+
52
+ /* Button styling */
53
+ button.primary {
54
+ background: linear-gradient(135deg, #3498db, #2980b9) !important;
55
+ color: white !important;
56
+ font-weight: 600 !important;
57
+ border-radius: 8px !important;
58
+ padding: 12px 24px !important;
59
+ font-size: 1.1rem !important;
60
+ transition: all 0.3s ease !important;
61
+ border: none !important;
62
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
63
+ }
64
+
65
+ button.primary:hover {
66
+ background: linear-gradient(135deg, #2980b9, #2573a7) !important;
67
+ box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2) !important;
68
+ transform: translateY(-2px) !important;
69
+ }
70
+
71
+ /* Radio buttons */
72
+ .radio-group label {
73
+ font-weight: 600 !important;
74
+ color: white !important;
75
+ }
76
+
77
+ /* Tab styling */
78
+ .tab-nav {
79
+ font-weight: 600 !important;
80
+ font-size: 1.05rem !important;
81
+ }
82
+
83
+ /* Tool tips */
84
+ .tooltip {
85
+ position: relative;
86
+ display: inline-block;
87
+ margin-left: 8px;
88
+ cursor: help;
89
+ }
90
+
91
+ .tooltip .tooltip-icon {
92
+ color: #3498db;
93
+ font-size: 16px;
94
+ font-weight: bold;
95
+ width: 18px;
96
+ height: 18px;
97
+ border-radius: 50%;
98
+ display: inline-flex;
99
+ align-items: center;
100
+ justify-content: center;
101
+ border: 2px solid #3498db;
102
+ }
103
+
104
+ .tooltip .tooltip-text {
105
+ visibility: hidden;
106
+ width: 200px;
107
+ background-color: #34495e;
108
+ color: #fff;
109
+ text-align: center;
110
+ border-radius: 6px;
111
+ padding: 8px;
112
+ position: absolute;
113
+ z-index: 1;
114
+ bottom: 125%;
115
+ left: 50%;
116
+ margin-left: -100px;
117
+ opacity: 0;
118
+ transition: opacity 0.3s;
119
+ font-size: 0.9rem;
120
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
121
+ }
122
+
123
+ .tooltip:hover .tooltip-text {
124
+ visibility: visible;
125
+ opacity: 1;
126
+ }
127
+
128
+ /* Responsive adjustments */
129
+ @media (max-width: 768px) {
130
+ .gradio-container {
131
+ padding: 10px !important;
132
+ }
133
+
134
+ label, .label {
135
+ font-size: 0.95rem !important;
136
+ }
137
+
138
+ button.primary {
139
+ padding: 10px 18px !important;
140
+ font-size: 1rem !important;
141
+ }
142
+ }
143
+ """
144
 
145
  # Enable OpenCL for better performance
146
  cv2.ocl.setUseOpenCL(True)
147
 
148
+ # ------------------- Helper Functions ------------------- #
149
+ def create_tooltip(label: str, tooltip_text: str) -> str:
150
+ """Create a tooltip HTML element"""
151
+ return f"""
152
+ <div style="display: flex; align-items: center;">
153
+ <span>{label}</span>
154
+ <div class="tooltip">
155
+ <span class="tooltip-icon">?</span>
156
+ <span class="tooltip-text">{tooltip_text}</span>
157
+ </div>
158
+ </div>
159
+ """
160
+
161
  # ------------------- Black & White Converter Functions ------------------- #
162
  def convert_to_black_white(image, threshold_value=127, method="otsu"):
163
  """Convert image to black and white using specified thresholding method"""
 
338
  else:
339
  raise gr.Error(message)
340
 
 
 
 
 
 
 
 
 
 
 
341
  # ------------------- Create Gradio Interface ------------------- #
342
  def create_interface():
343
+ # Tooltip content
344
+ otsu_tooltip = "Otsu automatically determines the optimal threshold value by analyzing the image histogram."
345
+ adaptive_tooltip = "Adaptive thresholding calculates different thresholds for different areas of the image, useful for images with varying lighting conditions."
346
+ manual_tooltip = "Manual threshold lets you set a specific brightness cutoff point between black and white pixels."
347
+ intensity_tooltip = "Controls the strength of the pencil sketch effect. Higher values create more contrast."
348
+ blur_tooltip = "Controls how much the image is blurred. Higher values create a softer sketch effect."
349
+ sigma_tooltip = "Controls the standard deviation of the Gaussian blur. Higher values increase the blurring effect."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
 
351
  # Black and White Image Interface
352
+ with gr.Blocks(title="Image Processor", css=custom_css, theme=gr.themes.Base()) as app:
353
+ with gr.Row(elem_classes="container"):
354
+ gr.Markdown("""
355
  # Image and Video Processor
356
+ Transform your media with professional black & white conversion and pencil sketch effects
357
+ """)
 
 
358
 
359
  with gr.Tabs() as tabs:
360
+ with gr.TabItem("Black & White Converter", elem_classes="app-card"):
361
  with gr.Tabs() as bw_tabs:
362
+ with gr.TabItem("Image Processing"):
363
  with gr.Row(equal_height=True):
364
  with gr.Column(scale=1):
365
+ bw_image_input = gr.Image(label="Input Image", elem_classes="input-image")
 
 
 
 
366
 
367
  with gr.Group():
368
+ gr.HTML(create_tooltip("Thresholding Method", otsu_tooltip))
369
  bw_method = gr.Radio(
370
  choices=["otsu", "adaptive", "manual"],
371
  value="otsu",
372
  label="",
373
+ elem_classes="radio-group"
374
  )
375
 
376
+ gr.HTML(create_tooltip("Manual Threshold Value", manual_tooltip))
377
+ bw_threshold = gr.Slider(
378
+ minimum=0,
379
+ maximum=255,
380
+ value=127,
381
+ step=1,
382
+ label="",
383
+ interactive=True,
384
+ elem_classes="slider-label"
385
+ )
386
 
387
+ bw_image_btn = gr.Button("Convert", elem_classes="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
 
389
  with gr.Column(scale=1):
390
+ bw_image_output = gr.Image(label="Processed Image")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
 
392
+ with gr.TabItem("Video Processing"):
393
  with gr.Row(equal_height=True):
394
  with gr.Column(scale=1):
395
+ bw_video_input = gr.Video(label="Input Video")
 
 
 
 
396
 
397
  with gr.Group():
398
+ gr.HTML(create_tooltip("Thresholding Method", otsu_tooltip))
399
  bw_video_method = gr.Radio(
400
  choices=["otsu", "adaptive", "manual"],
401
  value="otsu",
402
  label="",
403
+ elem_classes="radio-group"
404
  )
405
 
406
+ gr.HTML(create_tooltip("Manual Threshold Value", manual_tooltip))
407
+ bw_video_threshold = gr.Slider(
408
+ minimum=0,
409
+ maximum=255,
410
+ value=127,
411
+ step=1,
412
+ label="",
413
+ interactive=True,
414
+ elem_classes="slider-label"
415
+ )
416
 
417
+ bw_video_btn = gr.Button("Convert", elem_classes="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
  with gr.Column(scale=1):
420
+ bw_video_output = gr.Video(label="Processed Video")
 
 
 
 
421
 
422
+ with gr.TabItem("Pencil Sketch Converter", elem_classes="app-card"):
423
  with gr.Tabs() as sketch_tabs:
424
+ with gr.TabItem("Image Processing"):
425
  with gr.Row(equal_height=True):
426
  with gr.Column(scale=1):
427
+ sketch_image_input = gr.Image(label="Input Image")
 
 
 
 
428
 
429
  with gr.Group():
430
+ gr.HTML(create_tooltip("Intensity", intensity_tooltip))
431
+ sketch_intensity = gr.Slider(
432
+ minimum=1,
433
+ maximum=255,
434
+ value=255,
435
+ step=1,
436
+ label="",
437
+ elem_classes="slider-label"
438
+ )
 
 
 
 
439
 
440
+ gr.HTML(create_tooltip("Blur Kernel Size", blur_tooltip))
441
+ sketch_blur = gr.Slider(
442
+ minimum=1,
443
+ maximum=99,
444
+ value=21,
445
+ step=2,
446
+ label="",
447
+ elem_classes="slider-label"
448
+ )
 
 
 
 
449
 
450
+ gr.HTML(create_tooltip("Standard Deviation", sigma_tooltip))
451
+ sketch_sigma = gr.Slider(
452
+ minimum=0,
453
+ maximum=50,
454
+ value=0,
455
+ step=0.1,
456
+ label="",
457
+ elem_classes="slider-label"
458
+ )
459
+
460
+ sketch_image_btn = gr.Button("Convert", elem_classes="primary")
 
 
 
 
 
 
 
 
461
 
462
  with gr.Column(scale=1):
463
+ sketch_image_output = gr.Image(label="Processed Image")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
 
465
+ with gr.TabItem("Video Processing"):
466
  with gr.Row(equal_height=True):
467
  with gr.Column(scale=1):
468
+ sketch_video_input = gr.Video(label="Input Video")
 
 
 
 
469
 
470
  with gr.Group():
471
+ gr.HTML(create_tooltip("Intensity", intensity_tooltip))
472
+ sketch_video_intensity = gr.Slider(
473
+ minimum=1,
474
+ maximum=255,
475
+ value=255,
476
+ step=1,
477
+ label="",
478
+ elem_classes="slider-label"
479
+ )
 
 
 
 
480
 
481
+ gr.HTML(create_tooltip("Blur Kernel Size", blur_tooltip))
482
+ sketch_video_blur = gr.Slider(
483
+ minimum=1,
484
+ maximum=99,
485
+ value=21,
486
+ step=2,
487
+ label="",
488
+ elem_classes="slider-label"
489
+ )
 
 
 
 
490
 
491
+ gr.HTML(create_tooltip("Standard Deviation", sigma_tooltip))
492
+ sketch_video_sigma = gr.Slider(
493
+ minimum=0,
494
+ maximum=50,
495
+ value=0,
496
+ step=0.1,
497
+ label="",
498
+ elem_classes="slider-label"
499
+ )
500
+
501
+ sketch_video_btn = gr.Button("Convert", elem_classes="primary")
 
 
 
 
 
 
 
 
502
 
503
  with gr.Column(scale=1):
504
+ sketch_video_output = gr.Video(label="Processed Video")
505
+
506
+ with gr.Row(elem_classes="container"):
507
+ gr.Markdown("""
508
+ ### How to use:
509
+ 1. Upload an image or video
510
+ 2. Adjust the settings as needed
511
+ 3. Click the Convert button to process your media
512
+ """)
513
 
514
  # Set up event listeners
515
  bw_image_btn.click(
 
536
  outputs=sketch_video_output
537
  )
538
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  # Make blur slider always odd
540
  def update_blur(value):
541
  return value if value % 2 == 1 else value + 1
 
543
  sketch_blur.change(update_blur, sketch_blur, sketch_blur)
544
  sketch_video_blur.change(update_blur, sketch_video_blur, sketch_video_blur)
545
 
546
+ # Add visibility toggle based on method selection
547
+ def update_threshold_visibility(method):
548
+ return gr.update(visible=(method == "manual"))
549
 
550
+ bw_method.change(update_threshold_visibility, bw_method, bw_threshold)
551
+ bw_video_method.change(update_threshold_visibility, bw_video_method, bw_video_threshold)
 
 
 
552
 
553
  return app
554