dibend commited on
Commit
eea28cb
·
verified ·
1 Parent(s): dc13b68

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -74
app.py CHANGED
@@ -81,43 +81,29 @@ def apply_pixelate(img_np):
81
  temp = cv2.resize(img_np, (w // pixel_size, h // pixel_size), interpolation=cv2.INTER_NEAREST)
82
  return cv2.resize(temp, (w, h), interpolation=cv2.INTER_NEAREST)
83
 
84
- # --- New Advanced Filters ---
85
 
86
  def apply_hdr_effect(img_np):
87
  """Simulates an HDR effect by enhancing details."""
88
  if img_np is None: return None
89
- # Using cv2.detailEnhance for a quick and effective HDR-like look
90
  return cv2.detailEnhance(img_np, sigma_s=12, sigma_r=0.15)
91
 
92
  def apply_color_splash(img_np, hex_color):
93
  """Keeps a selected color and converts the rest of the image to grayscale."""
94
  if img_np is None: return None
95
- # Convert hex to RGB
96
  h = hex_color.lstrip('#')
97
  rgb_color = tuple(int(h[i:i+2], 16) for i in (0, 2, 4))
98
-
99
- # Convert image and color to HSV
100
  hsv_img = cv2.cvtColor(img_np, cv2.COLOR_RGB2HSV)
101
  hsv_color = cv2.cvtColor(np.uint8([[rgb_color]]), cv2.COLOR_RGB2HSV)[0][0]
102
-
103
- # Define a color range in HSV. Hue tolerance is important.
104
  hue_tolerance = 10
105
  lower_bound = np.array([max(0, hsv_color[0] - hue_tolerance), 50, 50])
106
  upper_bound = np.array([min(179, hsv_color[0] + hue_tolerance), 255, 255])
107
-
108
- # Create the mask and its inverse
109
  mask = cv2.inRange(hsv_img, lower_bound, upper_bound)
110
  mask_inv = cv2.bitwise_not(mask)
111
-
112
- # Create grayscale version of the image
113
  gray_img = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
114
  gray_img_3_channel = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2RGB)
115
-
116
- # Isolate the colored parts and the grayscale parts
117
  colored_part = cv2.bitwise_and(img_np, img_np, mask=mask)
118
  grayscale_part = cv2.bitwise_and(gray_img_3_channel, gray_img_3_channel, mask=mask_inv)
119
-
120
- # Combine the two parts
121
  return cv2.add(colored_part, grayscale_part)
122
 
123
  def apply_sunburst_glow(img_np):
@@ -125,33 +111,24 @@ def apply_sunburst_glow(img_np):
125
  if img_np is None: return None
126
  gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
127
  minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(gray)
128
-
129
  overlay = img_np.copy()
130
-
131
- # Draw star-like rays from the brightest point
132
  for i in range(12):
133
- angle = i * 30 * np.pi / 180 # 30 degrees per line
134
  length = np.random.randint(int(maxVal/2), int(maxVal*1.5))
135
  pt2_x = int(maxLoc[0] + length * np.cos(angle))
136
  pt2_y = int(maxLoc[1] + length * np.sin(angle))
137
  cv2.line(overlay, maxLoc, (pt2_x, pt2_y), (255, 255, 220), 1)
138
-
139
- # Add a soft glow
140
  glow = cv2.GaussianBlur(overlay, (0,0), sigmaX=30, sigmaY=30)
141
-
142
- # Blend the original image with the glow
143
  return cv2.addWeighted(img_np, 0.8, glow, 0.4, 0)
144
 
145
  def apply_dreamy_glow(img_np):
146
  """Adds a soft, dreamy glow effect to the image."""
147
  if img_np is None: return None
148
- # Create a blurred version of the image
149
  blurred = cv2.GaussianBlur(img_np, (0,0), sigmaX=15, sigmaY=15)
150
- # Blend using addWeighted to simulate a 'Screen' blend mode
151
  return cv2.addWeighted(img_np, 1.0, blurred, 0.6, 0)
152
 
153
 
154
- # --- Face Effect Functions (Unchanged) ---
155
  def _create_sunglasses_mask():
156
  sunglasses = Image.new('RGBA', (300, 100), (0, 0, 0, 0))
157
  draw = ImageDraw.Draw(sunglasses)
@@ -257,11 +234,14 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
257
  gr.Markdown("# Advanced Image & Face Filter Studio", elem_id="title")
258
  gr.Markdown("Apply classic, artistic, and face-aware effects to your images.", elem_id="subtitle")
259
 
260
- filters_old = ["None", "Grayscale", "Sepia", "Invert", "Posterize", "Solarize"]
261
- filters_new = ["None", "Vignette", "Contour", "Sharpen"]
262
- filters_artistic = ["None", "Cartoon", "Sketch", "Pixelate"]
263
- filters_face = ["None", "Sunglasses", "Plumber", "Elf Hero", "Cowboy Hat", "Crown"]
264
- filters_advanced = ["None", "HDR Effect", "Color Splash", "Sunburst Glow", "Dreamy Glow"]
 
 
 
265
 
266
  with gr.Row(equal_height=False):
267
  with gr.Column(scale=2):
@@ -269,16 +249,8 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
269
 
270
  with gr.Column(scale=1):
271
  gr.Markdown("### Filter Controls")
272
- with gr.Accordion("Old School", open=True):
273
- radio_old = gr.Radio(filters_old, label="Filter", value="None")
274
- with gr.Accordion("New School", open=True):
275
- radio_new = gr.Radio(filters_new, label="Filter", value="None")
276
- with gr.Accordion("Artistic", open=True):
277
- radio_artistic = gr.Radio(filters_artistic, label="Filter", value="None")
278
- with gr.Accordion("Advanced (May be slow)", open=True):
279
- radio_advanced = gr.Radio(filters_advanced, label="Filter", value="None")
280
- with gr.Accordion("Face Effects", open=True):
281
- radio_face = gr.Radio(filters_face, label="Filter", value="None")
282
 
283
  color_picker = gr.ColorPicker(label="Color to Keep (for Color Splash)", value="#FF0000", visible=False)
284
  apply_button = gr.Button("Apply Filter", variant="primary")
@@ -286,45 +258,24 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
286
  with gr.Column(scale=2):
287
  output_image = gr.Image(label="Filtered Output")
288
 
289
- all_radios = [radio_old, radio_new, radio_artistic, radio_advanced, radio_face]
290
-
291
- def master_update_function(img, r_old, r_new, r_art, r_adv, r_face, splash_color):
292
  """This function is the single point of truth for applying filters."""
293
- # Find the single active filter. The logic assumes only one is selected at a time.
294
- active_filter = next((f for f in [r_old, r_new, r_art, r_adv, r_face] if f != "None"), "None")
295
 
296
- # Process the image
297
- processed_img = process_image(img, active_filter, splash_color)
298
-
299
- # Determine visibility of the color picker
300
- color_picker_visibility = gr.update(visible=True) if active_filter == "Color Splash" else gr.update(visible=False)
301
 
302
  return processed_img, color_picker_visibility
303
 
304
- # This function resets other radio buttons. It's crucial for the UX.
305
- def create_reset_function(radios_to_reset):
306
- def reset_func():
307
- return [gr.update(value="None") for _ in radios_to_reset]
308
- return reset_func
309
-
310
- # --- CORRECTED EVENT HANDLING ---
311
- # The key is chaining the UI reset with the image processing using .then()
312
- for i, radio in enumerate(all_radios):
313
- other_radios = [r for j, r in enumerate(all_radios) if i != j]
314
-
315
- # When a radio's value changes:
316
- # 1. First, create and trigger a function to reset all other radio groups.
317
- # The .change() method returns an event listener object.
318
- # 2. THEN, chain the main update function to that event listener object.
319
- radio.change(fn=create_reset_function(other_radios), inputs=None, outputs=other_radios, queue=False).then(
320
- fn=master_update_function,
321
- inputs=[input_image] + all_radios + [color_picker],
322
- outputs=[output_image, color_picker]
323
- )
324
-
325
- # Connect the Apply button and image upload/change events to the master function as well
326
- trigger_inputs = [input_image] + all_radios + [color_picker]
327
  trigger_outputs = [output_image, color_picker]
 
 
 
328
  apply_button.click(master_update_function, inputs=trigger_inputs, outputs=trigger_outputs)
329
  input_image.change(master_update_function, inputs=trigger_inputs, outputs=trigger_outputs)
330
  color_picker.change(master_update_function, inputs=trigger_inputs, outputs=trigger_outputs)
 
81
  temp = cv2.resize(img_np, (w // pixel_size, h // pixel_size), interpolation=cv2.INTER_NEAREST)
82
  return cv2.resize(temp, (w, h), interpolation=cv2.INTER_NEAREST)
83
 
84
+ # --- Advanced Filters ---
85
 
86
  def apply_hdr_effect(img_np):
87
  """Simulates an HDR effect by enhancing details."""
88
  if img_np is None: return None
 
89
  return cv2.detailEnhance(img_np, sigma_s=12, sigma_r=0.15)
90
 
91
  def apply_color_splash(img_np, hex_color):
92
  """Keeps a selected color and converts the rest of the image to grayscale."""
93
  if img_np is None: return None
 
94
  h = hex_color.lstrip('#')
95
  rgb_color = tuple(int(h[i:i+2], 16) for i in (0, 2, 4))
 
 
96
  hsv_img = cv2.cvtColor(img_np, cv2.COLOR_RGB2HSV)
97
  hsv_color = cv2.cvtColor(np.uint8([[rgb_color]]), cv2.COLOR_RGB2HSV)[0][0]
 
 
98
  hue_tolerance = 10
99
  lower_bound = np.array([max(0, hsv_color[0] - hue_tolerance), 50, 50])
100
  upper_bound = np.array([min(179, hsv_color[0] + hue_tolerance), 255, 255])
 
 
101
  mask = cv2.inRange(hsv_img, lower_bound, upper_bound)
102
  mask_inv = cv2.bitwise_not(mask)
 
 
103
  gray_img = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
104
  gray_img_3_channel = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2RGB)
 
 
105
  colored_part = cv2.bitwise_and(img_np, img_np, mask=mask)
106
  grayscale_part = cv2.bitwise_and(gray_img_3_channel, gray_img_3_channel, mask=mask_inv)
 
 
107
  return cv2.add(colored_part, grayscale_part)
108
 
109
  def apply_sunburst_glow(img_np):
 
111
  if img_np is None: return None
112
  gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
113
  minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(gray)
 
114
  overlay = img_np.copy()
 
 
115
  for i in range(12):
116
+ angle = i * 30 * np.pi / 180
117
  length = np.random.randint(int(maxVal/2), int(maxVal*1.5))
118
  pt2_x = int(maxLoc[0] + length * np.cos(angle))
119
  pt2_y = int(maxLoc[1] + length * np.sin(angle))
120
  cv2.line(overlay, maxLoc, (pt2_x, pt2_y), (255, 255, 220), 1)
 
 
121
  glow = cv2.GaussianBlur(overlay, (0,0), sigmaX=30, sigmaY=30)
 
 
122
  return cv2.addWeighted(img_np, 0.8, glow, 0.4, 0)
123
 
124
  def apply_dreamy_glow(img_np):
125
  """Adds a soft, dreamy glow effect to the image."""
126
  if img_np is None: return None
 
127
  blurred = cv2.GaussianBlur(img_np, (0,0), sigmaX=15, sigmaY=15)
 
128
  return cv2.addWeighted(img_np, 1.0, blurred, 0.6, 0)
129
 
130
 
131
+ # --- Face Effect Functions ---
132
  def _create_sunglasses_mask():
133
  sunglasses = Image.new('RGBA', (300, 100), (0, 0, 0, 0))
134
  draw = ImageDraw.Draw(sunglasses)
 
234
  gr.Markdown("# Advanced Image & Face Filter Studio", elem_id="title")
235
  gr.Markdown("Apply classic, artistic, and face-aware effects to your images.", elem_id="subtitle")
236
 
237
+ # Consolidate all filter lists into one for a single radio component
238
+ filters_old = ["Grayscale", "Sepia", "Invert", "Posterize", "Solarize"]
239
+ filters_new = ["Vignette", "Contour", "Sharpen"]
240
+ filters_artistic = ["Cartoon", "Sketch", "Pixelate"]
241
+ filters_advanced = ["HDR Effect", "Color Splash", "Sunburst Glow", "Dreamy Glow"]
242
+ filters_face = ["Sunglasses", "Plumber", "Elf Hero", "Cowboy Hat", "Crown"]
243
+
244
+ all_filters = ["None"] + filters_old + filters_new + filters_artistic + filters_advanced + filters_face
245
 
246
  with gr.Row(equal_height=False):
247
  with gr.Column(scale=2):
 
249
 
250
  with gr.Column(scale=1):
251
  gr.Markdown("### Filter Controls")
252
+ # A single radio component for all filters
253
+ filter_radio = gr.Radio(all_filters, label="Select a Filter", value="None")
 
 
 
 
 
 
 
 
254
 
255
  color_picker = gr.ColorPicker(label="Color to Keep (for Color Splash)", value="#FF0000", visible=False)
256
  apply_button = gr.Button("Apply Filter", variant="primary")
 
258
  with gr.Column(scale=2):
259
  output_image = gr.Image(label="Filtered Output")
260
 
261
+ # Simplified update function that takes the single filter selection
262
+ def master_update_function(img, selected_filter, splash_color):
 
263
  """This function is the single point of truth for applying filters."""
264
+ # Process the image with the selected filter
265
+ processed_img = process_image(img, selected_filter, splash_color)
266
 
267
+ # Determine visibility of the color picker based on the single filter selection
268
+ color_picker_visibility = gr.update(visible=True) if selected_filter == "Color Splash" else gr.update(visible=False)
 
 
 
269
 
270
  return processed_img, color_picker_visibility
271
 
272
+ # --- SIMPLIFIED EVENT HANDLING ---
273
+ # Define the inputs and outputs for the master function
274
+ trigger_inputs = [input_image, filter_radio, color_picker]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  trigger_outputs = [output_image, color_picker]
276
+
277
+ # Connect all triggers to the single update function
278
+ filter_radio.change(master_update_function, inputs=trigger_inputs, outputs=trigger_outputs)
279
  apply_button.click(master_update_function, inputs=trigger_inputs, outputs=trigger_outputs)
280
  input_image.change(master_update_function, inputs=trigger_inputs, outputs=trigger_outputs)
281
  color_picker.change(master_update_function, inputs=trigger_inputs, outputs=trigger_outputs)