dibend commited on
Commit
b8b15c0
·
verified ·
1 Parent(s): 279fc21

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -0
app.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from PIL import Image, ImageOps
3
+ import numpy as np
4
+
5
+ # --- Filter Functions ---
6
+ # Each function takes a PIL Image and returns a processed PIL Image.
7
+
8
+ def apply_grayscale(image):
9
+ """Converts the image to grayscale."""
10
+ if image is None:
11
+ return None
12
+ return ImageOps.grayscale(image.convert("RGB"))
13
+
14
+ def apply_sepia(image):
15
+ """Applies a sepia tone filter to the image."""
16
+ if image is None:
17
+ return None
18
+ img = image.convert("RGB")
19
+ width, height = img.size
20
+ pixels = img.load()
21
+
22
+ for py in range(height):
23
+ for px in range(width):
24
+ r, g, b = img.getpixel((px, py))
25
+ tr = int(0.393 * r + 0.769 * g + 0.189 * b)
26
+ tg = int(0.349 * r + 0.686 * g + 0.168 * b)
27
+ tb = int(0.272 * r + 0.534 * g + 0.131 * b)
28
+ if tr > 255: tr = 255
29
+ if tg > 255: tg = 255
30
+ if tb > 255: tb = 255
31
+ pixels[px, py] = (tr, tg, tb)
32
+ return img
33
+
34
+ def apply_invert(image):
35
+ """Inverts the colors of the image."""
36
+ if image is None:
37
+ return None
38
+ return ImageOps.invert(image.convert("RGB"))
39
+
40
+ def apply_posterize(image):
41
+ """Reduces the number of bits for each color channel."""
42
+ if image is None:
43
+ return None
44
+ # Posterize to 4 bits per channel
45
+ return ImageOps.posterize(image.convert("RGB"), 4)
46
+
47
+ def apply_solarize(image):
48
+ """Inverts pixel values above a threshold."""
49
+ if image is None:
50
+ return None
51
+ return ImageOps.solarize(image.convert("RGB"), threshold=128)
52
+
53
+ # --- Main Processing Function ---
54
+ def apply_filter(image, filter_name):
55
+ """
56
+ Dispatcher function that calls the appropriate filter
57
+ based on the user's selection.
58
+ """
59
+ if image is None:
60
+ return None
61
+
62
+ # Convert Gradio's numpy array to a PIL Image if necessary
63
+ if isinstance(image, np.ndarray):
64
+ pil_image = Image.fromarray(image)
65
+ else:
66
+ pil_image = image
67
+
68
+ filter_map = {
69
+ "Grayscale": apply_grayscale,
70
+ "Sepia": apply_sepia,
71
+ "Invert": apply_invert,
72
+ "Posterize": apply_posterize,
73
+ "Solarize": apply_solarize,
74
+ "None": lambda img: img # Return original if no filter
75
+ }
76
+
77
+ # Get the function from the map and apply it
78
+ filter_function = filter_map.get(filter_name, lambda img: img)
79
+ return filter_function(pil_image)
80
+
81
+ # --- Gradio UI ---
82
+ css = """
83
+ #title {
84
+ text-align: center;
85
+ color: #1d1e22;
86
+ font-size: 2.8em;
87
+ font-weight: 700;
88
+ }
89
+ #subtitle {
90
+ text-align: center;
91
+ color: #57606a;
92
+ font-size: 1.2em;
93
+ }
94
+ .gradio-container {
95
+ max-width: 980px !important;
96
+ margin: auto !important;
97
+ }
98
+ """
99
+
100
+ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
101
+ gr.Markdown("# Old School Image Filters", elem_id="title")
102
+ gr.Markdown("Apply classic filters to your images or live webcam feed. All processing is done on the server's CPU.", elem_id="subtitle")
103
+
104
+ filter_choices = ["None", "Grayscale", "Sepia", "Invert", "Posterize", "Solarize"]
105
+
106
+ with gr.Tabs():
107
+ with gr.TabItem("Live Webcam"):
108
+ with gr.Row(equal_height=True):
109
+ with gr.Column():
110
+ webcam_input = gr.Image(sources=["webcam"], streaming=True, label="Webcam Input")
111
+ with gr.Column():
112
+ webcam_output = gr.Image(label="Filtered Output")
113
+ webcam_filter = gr.Radio(filter_choices, value="None", label="Select Filter")
114
+
115
+ # When the webcam input or filter changes, apply the filter
116
+ webcam_input.stream(apply_filter, [webcam_input, webcam_filter], webcam_output)
117
+ webcam_filter.change(apply_filter, [webcam_input, webcam_filter], webcam_output)
118
+
119
+ with gr.TabItem("Image File"):
120
+ with gr.Row(equal_height=True):
121
+ with gr.Column():
122
+ upload_input = gr.Image(type="pil", label="Upload an Image")
123
+ with gr.Column():
124
+ upload_output = gr.Image(label="Filtered Output")
125
+ upload_filter = gr.Radio(filter_choices, value="None", label="Select Filter")
126
+
127
+ gr.Examples(
128
+ examples=[
129
+ ["./examples/cat.jpg", "Sepia"],
130
+ ["./examples/cheetah.jpg", "Posterize"],
131
+ ["./examples/lion.jpg", "Grayscale"],
132
+ ],
133
+ inputs=[upload_input, upload_filter],
134
+ outputs=upload_output,
135
+ fn=apply_filter,
136
+ cache_examples=True
137
+ )
138
+
139
+ # When the uploaded image or filter changes, apply the filter
140
+ upload_input.change(apply_filter, [upload_input, upload_filter], upload_output)
141
+ upload_filter.change(apply_filter, [upload_input, upload_filter], upload_output)
142
+
143
+ # Create a dummy examples directory for local testing
144
+ if not demo.examples:
145
+ import os
146
+ os.makedirs("examples", exist_ok=True)
147
+ try:
148
+ # Create a simple placeholder image
149
+ Image.new('RGB', (200, 200), color = 'red').save('examples/cat.jpg')
150
+ Image.new('RGB', (200, 200), color = 'green').save('examples/cheetah.jpg')
151
+ Image.new('RGB', (200, 200), color = 'blue').save('examples/lion.jpg')
152
+ except Exception as e:
153
+ print(f"Could not create example images: {e}")
154
+
155
+
156
+ if __name__ == "__main__":
157
+ demo.launch(debug=True)