eienmojiki commited on
Commit
c5900d7
·
verified ·
1 Parent(s): 96cd1bf

Update Gradio app with multiple files

Browse files
Files changed (4) hide show
  1. app.py +58 -53
  2. components.py +2 -2
  3. filters.py +56 -37
  4. requirements.txt +6 -2
app.py CHANGED
@@ -108,74 +108,79 @@ def create_app():
108
  with gr.Column(elem_classes="filter-header"):
109
  gr.Markdown("""
110
  # 📷 Photo Filter App
111
- Chỉnh sửa ảnh với các bộ lọc chuyên nghiệp - Nhanh chóng & Dễ dàng
112
 
113
  Built with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder)
114
  """)
115
 
116
- # Khởi tạo components
117
  filter_names = list(registry.filters.keys())
118
 
 
119
  with gr.Row():
120
- # Left Column - Input & Controls
121
- with gr.Column(scale=2):
122
  with gr.Group(elem_classes="image-container"):
123
  input_image = gr.Image(
124
- label="📤 Ảnh gốc",
125
  type="numpy",
126
  height=500
127
  )
 
 
 
 
 
 
 
 
 
 
128
 
129
  with gr.Row():
130
- apply_button = gr.Button(
131
- " Áp dụng bộ lọc",
132
- variant="primary",
133
- size="lg",
134
- scale=2
135
- )
136
- reset_button = gr.Button(
137
- "🔄 Làm mới",
138
- variant="secondary",
139
- size="lg",
140
- scale=1
141
  )
142
-
143
- # Middle Column - Filter Selection & Parameters
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  with gr.Column(scale=1):
145
  with gr.Group(elem_classes="control-panel"):
146
- gr.Markdown("### 🎨 Chọn bộ lọc")
147
  filter_select = gr.Dropdown(
148
- label="Bộ lọc",
149
  choices=filter_names,
150
  value="Original",
151
  interactive=True
152
  )
153
 
154
  filter_doc = gr.Markdown(
155
- value="Chọn một bộ lọc để xem mô tả chi tiết.",
156
  elem_classes="filter-description"
157
  )
158
-
159
- gr.Markdown("### ⚙️ Tùy chỉnh")
160
- # Tạo các điều khiển bộ lọc động
161
- filter_controls, control_components = create_filter_controls()
162
 
163
- # Right Column - Output
164
- with gr.Column(scale=2):
165
- with gr.Group(elem_classes="image-container"):
166
- output_image = gr.Image(
167
- label="✅ Ảnh đã chỉnh sửa",
168
- height=500
169
- )
170
-
171
- error_message = gr.Markdown(visible=False)
172
-
173
- with gr.Row():
174
- download_button = gr.Button(
175
- "💾 Tải xuống",
176
- visible=False,
177
- size="lg"
178
- )
179
 
180
  # Stats panel
181
  with gr.Row():
@@ -183,31 +188,31 @@ def create_app():
183
  gr.Markdown(
184
  f"""
185
  <div class="stats-panel">
186
- 📊 <b>Tổng số bộ lọc:</b> {len(filter_names)} |
187
- 🎯 <b>Bộ lọc có tham số:</b> {sum(1 for f in filter_names if registry.params_map.get(f))} |
188
- 🚀 <b>Bộ lọc nhanh:</b> {sum(1 for f in filter_names if not registry.params_map.get(f))}
189
  </div>
190
  """
191
  )
192
 
193
- # Xử cập nhật UI
194
  def update_controls(filter_name):
195
  updates = []
196
  for group_name in filter_controls:
197
  updates.append(gr.update(visible=group_name == filter_name))
198
 
199
- doc = registry.filters[filter_name].__doc__ or "Không tả chi tiết."
200
  return updates + [doc]
201
 
202
- # Xử ảnh
203
  def process(image, filter_name, *args):
204
  if image is None:
205
- return None, gr.update(visible=True, value="⚠️ **Lưu ý:** Vui lòng tải ảnh lên trước khi áp dụng bộ lọc!"), gr.update(visible=False)
206
 
207
  try:
208
  image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
209
 
210
- # Lấy các tham số cho filter hiện tại
211
  params = {}
212
  if filter_name in control_components:
213
  param_names = list(registry.params_map.get(filter_name, {}).keys())
@@ -225,18 +230,18 @@ def create_app():
225
 
226
  return processed, gr.update(visible=False), gr.update(visible=True)
227
  except Exception as e:
228
- return None, gr.update(visible=True, value=f"❌ **Lỗi:** {str(e)}"), gr.update(visible=False)
229
 
230
- # Xử reset
231
  def reset_all():
232
  return None, None, gr.update(visible=False), gr.update(visible=False), "Original"
233
 
234
- # Thu thập tất cả control components
235
  all_control_components = []
236
  for filter_name in control_components:
237
  all_control_components.extend(control_components[filter_name])
238
 
239
- # Kết nối sự kiện
240
  filter_select.change(
241
  update_controls,
242
  inputs=filter_select,
 
108
  with gr.Column(elem_classes="filter-header"):
109
  gr.Markdown("""
110
  # 📷 Photo Filter App
111
+ Professional photo editing with powerful filters - Fast & Easy
112
 
113
  Built with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder)
114
  """)
115
 
116
+ # Initialize components
117
  filter_names = list(registry.filters.keys())
118
 
119
+ # Top Row - Images side by side
120
  with gr.Row():
121
+ # Left Column - Input Image
122
+ with gr.Column(scale=1):
123
  with gr.Group(elem_classes="image-container"):
124
  input_image = gr.Image(
125
+ label="📤 Original Image",
126
  type="numpy",
127
  height=500
128
  )
129
+
130
+ # Right Column - Output Image
131
+ with gr.Column(scale=1):
132
+ with gr.Group(elem_classes="image-container"):
133
+ output_image = gr.Image(
134
+ label="✅ Edited Image",
135
+ height=500
136
+ )
137
+
138
+ error_message = gr.Markdown(visible=False)
139
 
140
  with gr.Row():
141
+ download_button = gr.Button(
142
+ "💾 Download",
143
+ visible=False,
144
+ size="lg"
 
 
 
 
 
 
 
145
  )
146
+
147
+ # Action Buttons
148
+ with gr.Row():
149
+ apply_button = gr.Button(
150
+ "✨ Apply Filter",
151
+ variant="primary",
152
+ size="lg",
153
+ scale=2
154
+ )
155
+ reset_button = gr.Button(
156
+ "🔄 Reset",
157
+ variant="secondary",
158
+ size="lg",
159
+ scale=1
160
+ )
161
+
162
+ # Bottom Row - Filter Selection & Parameters
163
+ with gr.Row():
164
  with gr.Column(scale=1):
165
  with gr.Group(elem_classes="control-panel"):
166
+ gr.Markdown("### 🎨 Select Filter")
167
  filter_select = gr.Dropdown(
168
+ label="Filter",
169
  choices=filter_names,
170
  value="Original",
171
  interactive=True
172
  )
173
 
174
  filter_doc = gr.Markdown(
175
+ value="Select a filter to see detailed description.",
176
  elem_classes="filter-description"
177
  )
 
 
 
 
178
 
179
+ with gr.Column(scale=1):
180
+ with gr.Group(elem_classes="control-panel"):
181
+ gr.Markdown("### ⚙️ Customize")
182
+ # Create dynamic filter controls
183
+ filter_controls, control_components = create_filter_controls()
 
 
 
 
 
 
 
 
 
 
 
184
 
185
  # Stats panel
186
  with gr.Row():
 
188
  gr.Markdown(
189
  f"""
190
  <div class="stats-panel">
191
+ 📊 <b>Total Filters:</b> {len(filter_names)} |
192
+ 🎯 <b>Parameterized Filters:</b> {sum(1 for f in filter_names if registry.params_map.get(f))} |
193
+ 🚀 <b>Quick Filters:</b> {sum(1 for f in filter_names if not registry.params_map.get(f))}
194
  </div>
195
  """
196
  )
197
 
198
+ # Handle UI updates
199
  def update_controls(filter_name):
200
  updates = []
201
  for group_name in filter_controls:
202
  updates.append(gr.update(visible=group_name == filter_name))
203
 
204
+ doc = registry.filters[filter_name].__doc__ or "No detailed description available."
205
  return updates + [doc]
206
 
207
+ # Handle image processing
208
  def process(image, filter_name, *args):
209
  if image is None:
210
+ return None, gr.update(visible=True, value="⚠️ **Note:** Please upload an image before applying filters!"), gr.update(visible=False)
211
 
212
  try:
213
  image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
214
 
215
+ # Get parameters for current filter
216
  params = {}
217
  if filter_name in control_components:
218
  param_names = list(registry.params_map.get(filter_name, {}).keys())
 
230
 
231
  return processed, gr.update(visible=False), gr.update(visible=True)
232
  except Exception as e:
233
+ return None, gr.update(visible=True, value=f"❌ **Error:** {str(e)}"), gr.update(visible=False)
234
 
235
+ # Handle reset
236
  def reset_all():
237
  return None, None, gr.update(visible=False), gr.update(visible=False), "Original"
238
 
239
+ # Collect all control components
240
  all_control_components = []
241
  for filter_name in control_components:
242
  all_control_components.extend(control_components[filter_name])
243
 
244
+ # Connect events
245
  filter_select.change(
246
  update_controls,
247
  inputs=filter_select,
components.py CHANGED
@@ -2,7 +2,7 @@ import gradio as gr
2
  from registry import registry
3
 
4
  def create_filter_controls():
5
- """Tạo các điều khiển cho từng bộ lọc"""
6
  controls = {}
7
  control_components = {}
8
 
@@ -42,7 +42,7 @@ def create_filter_controls():
42
  )
43
  filter_controls_list.append(checkbox)
44
  else:
45
- gr.Markdown("*✨ Bộ lọc này không tham số tùy chỉnh - Nhấn 'Áp dụng' để sử dụng!*")
46
 
47
  controls[filter_name] = filter_group
48
  control_components[filter_name] = filter_controls_list
 
2
  from registry import registry
3
 
4
  def create_filter_controls():
5
+ """Create controls for each filter"""
6
  controls = {}
7
  control_components = {}
8
 
 
42
  )
43
  filter_controls_list.append(checkbox)
44
  else:
45
+ gr.Markdown("*✨ This filter has no custom parameters - Just click 'Apply' to use it!*")
46
 
47
  controls[filter_name] = filter_group
48
  control_components[filter_name] = filter_controls_list
filters.py CHANGED
@@ -6,7 +6,7 @@ from registry import registry
6
  @registry.register("Original")
7
  def original(image):
8
  """
9
- ## Ảnh gốc - không áp dụng bộ lọc nào.
10
 
11
  **Args:**
12
  * `image` (numpy.ndarray): Input image
@@ -33,13 +33,13 @@ def original(image):
33
  })
34
  def dot_effect(image, dot_size: int = 10, dot_spacing: int = 2, invert: bool = False):
35
  """
36
- ## Chuyển ảnh thành hiệu ứng chấm tròn nghệ thuật.
37
 
38
  **Args:**
39
  * `image` (numpy.ndarray): Input image (BGR or grayscale)
40
- * `dot_size` (int): Kích thước mỗi chấm
41
- * `dot_spacing` (int): Khoảng cách giữa các chấm
42
- * `invert` (bool): Đảo ngược màu chấm
43
 
44
  **Returns:**
45
  * `numpy.ndarray`: Dotted image
@@ -88,11 +88,11 @@ def dot_effect(image, dot_size: int = 10, dot_spacing: int = 2, invert: bool = F
88
  })
89
  def pixelize(image, pixel_size: int = 10):
90
  """
91
- ## Tạo hiệu ứng pixel hóa cho ảnh (8-bit retro style).
92
 
93
  **Args:**
94
  * `image` (numpy.ndarray): Input image
95
- * `pixel_size` (int): Kích thước mỗi khối pixel
96
 
97
  **Returns:**
98
  * `numpy.ndarray`: Pixelized image
@@ -108,7 +108,7 @@ def pixelize(image, pixel_size: int = 10):
108
  @registry.register("Sketch Effect")
109
  def sketch_effect(image):
110
  """
111
- ## Chuyển ảnh thành bản phác thảo bút chì.
112
 
113
  **Args:**
114
  * `image` (numpy.ndarray): Input image
@@ -138,11 +138,11 @@ def sketch_effect(image):
138
  })
139
  def warm_filter(image, intensity: int = 30):
140
  """
141
- ## Thêm tông màu ấm áp cho ảnh (hoàng hôn, mùa thu).
142
 
143
  **Args:**
144
  * `image` (numpy.ndarray): Input image (BGR)
145
- * `intensity` (int): Cường độ hiệu ứng (0-100)
146
 
147
  **Returns:**
148
  * `numpy.ndarray`: Warm-toned image
@@ -166,11 +166,11 @@ def warm_filter(image, intensity: int = 30):
166
  })
167
  def cool_filter(image, intensity: int = 30):
168
  """
169
- ## Thêm tông màu lạnh cho ảnh (băng tuyết, biển xanh).
170
 
171
  **Args:**
172
  * `image` (numpy.ndarray): Input image (BGR)
173
- * `intensity` (int): Cường độ hiệu ứng (0-100)
174
 
175
  **Returns:**
176
  * `numpy.ndarray`: Cool-toned image
@@ -194,11 +194,11 @@ def cool_filter(image, intensity: int = 30):
194
  })
195
  def adjust_saturation(image, factor: int = 50):
196
  """
197
- ## Điều chỉnh độ bão hòa màu sắc của ảnh.
198
 
199
  **Args:**
200
  * `image` (numpy.ndarray): Input image (BGR)
201
- * `factor` (int): Hệ số bão hòa (0-100, 50 bình thường)
202
 
203
  **Returns:**
204
  * `numpy.ndarray`: Saturation-adjusted image
@@ -220,11 +220,11 @@ def adjust_saturation(image, factor: int = 50):
220
  })
221
  def vintage_filter(image, intensity: int = 50):
222
  """
223
- ## Tạo hiệu ứng ảnh cổ điển/retro (phong cách những năm 70).
224
 
225
  **Args:**
226
  * `image` (numpy.ndarray): Input image (BGR)
227
- * `intensity` (int): Cường độ hiệu ứng vintage (0-100)
228
 
229
  **Returns:**
230
  * `numpy.ndarray`: Vintage-styled image
@@ -252,11 +252,11 @@ def vintage_filter(image, intensity: int = 50):
252
  })
253
  def vignette_effect(image, intensity: int = 50):
254
  """
255
- ## Thêm hiệu ứng làm tối các góc ảnh (vignette).
256
 
257
  **Args:**
258
  * `image` (numpy.ndarray): Input image (BGR)
259
- * `intensity` (int): Cường độ vignette (0-100)
260
 
261
  **Returns:**
262
  * `numpy.ndarray`: Vignetted image
@@ -284,11 +284,11 @@ def vignette_effect(image, intensity: int = 50):
284
  })
285
  def hdr_effect(image, strength: int = 50):
286
  """
287
- ## Tăng cường chi tiết ảnh với hiệu ứng HDR.
288
 
289
  **Args:**
290
  * `image` (numpy.ndarray): Input image (BGR)
291
- * `strength` (int): Cường độ HDR (0-100)
292
 
293
  **Returns:**
294
  * `numpy.ndarray`: HDR-enhanced image
@@ -318,11 +318,11 @@ def hdr_effect(image, strength: int = 50):
318
  })
319
  def gaussian_blur(image, kernel_size: int = 5):
320
  """
321
- ## Làm mờ ảnh với bộ lọc Gaussian.
322
 
323
  **Args:**
324
  * `image` (numpy.ndarray): Input image
325
- * `kernel_size` (int): Kích thước kernel (phải số lẻ)
326
 
327
  **Returns:**
328
  * `numpy.ndarray`: Blurred image
@@ -343,11 +343,11 @@ def gaussian_blur(image, kernel_size: int = 5):
343
  })
344
  def sharpen(image, amount: int = 50):
345
  """
346
- ## Làm sắc nét ảnh.
347
 
348
  **Args:**
349
  * `image` (numpy.ndarray): Input image
350
- * `amount` (int): Cường độ làm sắc nét (0-100)
351
 
352
  **Returns:**
353
  * `numpy.ndarray`: Sharpened image
@@ -373,12 +373,12 @@ def sharpen(image, amount: int = 50):
373
  })
374
  def emboss(image, strength: int = 50, direction: int = 0):
375
  """
376
- ## Tạo hiệu ứng nổi 3D cho ảnh.
377
 
378
  **Args:**
379
  * `image` (numpy.ndarray): Input image
380
- * `strength` (int): Cường độ emboss (0-100)
381
- * `direction` (int): Hướng ánh sáng (0-7)
382
 
383
  **Returns:**
384
  * `numpy.ndarray`: Embossed image
@@ -416,12 +416,12 @@ def emboss(image, strength: int = 50, direction: int = 0):
416
  })
417
  def oil_painting(image, size: int = 5, dynRatio: int = 1):
418
  """
419
- ## Tạo hiệu ứng tranh sơn dầu.
420
 
421
  **Args:**
422
  * `image` (numpy.ndarray): Input image
423
- * `size` (int): Kích thước vùng xử lý
424
- * `dynRatio` (int): Tỷ lệ động ảnh hưởng đến cường độ màu
425
 
426
  **Returns:**
427
  * `numpy.ndarray`: Oil painting styled image
@@ -432,7 +432,7 @@ def oil_painting(image, size: int = 5, dynRatio: int = 1):
432
  @registry.register("Black and White")
433
  def black_and_white(image):
434
  """
435
- ## Chuyển ảnh sang đen trắng cổ điển.
436
 
437
  **Args:**
438
  * `image` (numpy.ndarray): Input image
@@ -446,7 +446,7 @@ def black_and_white(image):
446
  @registry.register("Sepia")
447
  def sepia(image):
448
  """
449
- ## Tạo hiệu ứng sepia tông màu nâu cổ điển.
450
 
451
  **Args:**
452
  * `image` (numpy.ndarray): Input image
@@ -468,7 +468,7 @@ def sepia(image):
468
  @registry.register("Negative")
469
  def negative(image):
470
  """
471
- ## Đảo ngược màu sắc tạo hiệu ứng negative film.
472
 
473
  **Args:**
474
  * `image` (numpy.ndarray): Input image
@@ -482,7 +482,7 @@ def negative(image):
482
  @registry.register("Watercolor")
483
  def watercolor(image):
484
  """
485
- ## Tạo hiệu ứng tranh màu nước.
486
 
487
  **Args:**
488
  * `image` (numpy.ndarray): Input image
@@ -496,7 +496,7 @@ def watercolor(image):
496
  @registry.register("Posterization")
497
  def posterize(image):
498
  """
499
- ## Giảm số màu tạo hiệu ứng poster nghệ thuật.
500
 
501
  **Args:**
502
  * `image` (numpy.ndarray): Input image
@@ -513,7 +513,7 @@ def posterize(image):
513
  @registry.register("Cross Process")
514
  def cross_process(image):
515
  """
516
- ## Hiệu ứng xử lý chéo film (cross-processing).
517
 
518
  **Args:**
519
  * `image` (numpy.ndarray): Input image
@@ -525,4 +525,23 @@ def cross_process(image):
525
  b = np.clip(b * 1.2, 0, 255)
526
  g = np.clip(g * 0.8, 0, 255)
527
  r = np.clip(r * 1.4, 0, 255)
528
- return cv2.merge([b, g, r]).astype(np.uint8)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  @registry.register("Original")
7
  def original(image):
8
  """
9
+ ## Original Image - no filter applied.
10
 
11
  **Args:**
12
  * `image` (numpy.ndarray): Input image
 
33
  })
34
  def dot_effect(image, dot_size: int = 10, dot_spacing: int = 2, invert: bool = False):
35
  """
36
+ ## Convert image to artistic dot pattern effect.
37
 
38
  **Args:**
39
  * `image` (numpy.ndarray): Input image (BGR or grayscale)
40
+ * `dot_size` (int): Size of each dot
41
+ * `dot_spacing` (int): Spacing between dots
42
+ * `invert` (bool): Invert dot colors
43
 
44
  **Returns:**
45
  * `numpy.ndarray`: Dotted image
 
88
  })
89
  def pixelize(image, pixel_size: int = 10):
90
  """
91
+ ## Create pixelated effect (8-bit retro style).
92
 
93
  **Args:**
94
  * `image` (numpy.ndarray): Input image
95
+ * `pixel_size` (int): Size of each pixel block
96
 
97
  **Returns:**
98
  * `numpy.ndarray`: Pixelized image
 
108
  @registry.register("Sketch Effect")
109
  def sketch_effect(image):
110
  """
111
+ ## Convert image to pencil sketch.
112
 
113
  **Args:**
114
  * `image` (numpy.ndarray): Input image
 
138
  })
139
  def warm_filter(image, intensity: int = 30):
140
  """
141
+ ## Add warm tones to image (sunset, autumn style).
142
 
143
  **Args:**
144
  * `image` (numpy.ndarray): Input image (BGR)
145
+ * `intensity` (int): Effect intensity (0-100)
146
 
147
  **Returns:**
148
  * `numpy.ndarray`: Warm-toned image
 
166
  })
167
  def cool_filter(image, intensity: int = 30):
168
  """
169
+ ## Add cool tones to image (ice, ocean style).
170
 
171
  **Args:**
172
  * `image` (numpy.ndarray): Input image (BGR)
173
+ * `intensity` (int): Effect intensity (0-100)
174
 
175
  **Returns:**
176
  * `numpy.ndarray`: Cool-toned image
 
194
  })
195
  def adjust_saturation(image, factor: int = 50):
196
  """
197
+ ## Adjust color saturation of image.
198
 
199
  **Args:**
200
  * `image` (numpy.ndarray): Input image (BGR)
201
+ * `factor` (int): Saturation factor (0-100, 50 is normal)
202
 
203
  **Returns:**
204
  * `numpy.ndarray`: Saturation-adjusted image
 
220
  })
221
  def vintage_filter(image, intensity: int = 50):
222
  """
223
+ ## Create vintage/retro photo effect (70s style).
224
 
225
  **Args:**
226
  * `image` (numpy.ndarray): Input image (BGR)
227
+ * `intensity` (int): Vintage effect intensity (0-100)
228
 
229
  **Returns:**
230
  * `numpy.ndarray`: Vintage-styled image
 
252
  })
253
  def vignette_effect(image, intensity: int = 50):
254
  """
255
+ ## Add darkening effect to image corners (vignette).
256
 
257
  **Args:**
258
  * `image` (numpy.ndarray): Input image (BGR)
259
+ * `intensity` (int): Vignette intensity (0-100)
260
 
261
  **Returns:**
262
  * `numpy.ndarray`: Vignetted image
 
284
  })
285
  def hdr_effect(image, strength: int = 50):
286
  """
287
+ ## Enhance image details with HDR effect.
288
 
289
  **Args:**
290
  * `image` (numpy.ndarray): Input image (BGR)
291
+ * `strength` (int): HDR strength (0-100)
292
 
293
  **Returns:**
294
  * `numpy.ndarray`: HDR-enhanced image
 
318
  })
319
  def gaussian_blur(image, kernel_size: int = 5):
320
  """
321
+ ## Blur image with Gaussian filter.
322
 
323
  **Args:**
324
  * `image` (numpy.ndarray): Input image
325
+ * `kernel_size` (int): Kernel size (must be odd number)
326
 
327
  **Returns:**
328
  * `numpy.ndarray`: Blurred image
 
343
  })
344
  def sharpen(image, amount: int = 50):
345
  """
346
+ ## Sharpen image details.
347
 
348
  **Args:**
349
  * `image` (numpy.ndarray): Input image
350
+ * `amount` (int): Sharpening intensity (0-100)
351
 
352
  **Returns:**
353
  * `numpy.ndarray`: Sharpened image
 
373
  })
374
  def emboss(image, strength: int = 50, direction: int = 0):
375
  """
376
+ ## Create 3D embossed effect.
377
 
378
  **Args:**
379
  * `image` (numpy.ndarray): Input image
380
+ * `strength` (int): Emboss strength (0-100)
381
+ * `direction` (int): Light direction (0-7)
382
 
383
  **Returns:**
384
  * `numpy.ndarray`: Embossed image
 
416
  })
417
  def oil_painting(image, size: int = 5, dynRatio: int = 1):
418
  """
419
+ ## Create oil painting effect.
420
 
421
  **Args:**
422
  * `image` (numpy.ndarray): Input image
423
+ * `size` (int): Processing area size
424
+ * `dynRatio` (int): Dynamic ratio affecting color intensity
425
 
426
  **Returns:**
427
  * `numpy.ndarray`: Oil painting styled image
 
432
  @registry.register("Black and White")
433
  def black_and_white(image):
434
  """
435
+ ## Convert to classic black and white.
436
 
437
  **Args:**
438
  * `image` (numpy.ndarray): Input image
 
446
  @registry.register("Sepia")
447
  def sepia(image):
448
  """
449
+ ## Create sepia tone classic brown effect.
450
 
451
  **Args:**
452
  * `image` (numpy.ndarray): Input image
 
468
  @registry.register("Negative")
469
  def negative(image):
470
  """
471
+ ## Invert colors for negative film effect.
472
 
473
  **Args:**
474
  * `image` (numpy.ndarray): Input image
 
482
  @registry.register("Watercolor")
483
  def watercolor(image):
484
  """
485
+ ## Create watercolor painting effect.
486
 
487
  **Args:**
488
  * `image` (numpy.ndarray): Input image
 
496
  @registry.register("Posterization")
497
  def posterize(image):
498
  """
499
+ ## Reduce colors for artistic poster effect.
500
 
501
  **Args:**
502
  * `image` (numpy.ndarray): Input image
 
513
  @registry.register("Cross Process")
514
  def cross_process(image):
515
  """
516
+ ## Film cross-processing effect.
517
 
518
  **Args:**
519
  * `image` (numpy.ndarray): Input image
 
525
  b = np.clip(b * 1.2, 0, 255)
526
  g = np.clip(g * 0.8, 0, 255)
527
  r = np.clip(r * 1.4, 0, 255)
528
+ return cv2.merge([b, g, r]).astype(np.uint8)
529
+
530
+ Perfect! I've updated the app with the following changes:
531
+
532
+ 1. **New Layout**:
533
+ - Input and output images are now side-by-side at the top for easy comparison
534
+ - Filter selection and customization controls moved to the bottom
535
+ - Action buttons (Apply Filter/Reset) placed between images and controls
536
+
537
+ 2. **Complete English Translation**:
538
+ - All Vietnamese text converted to English
539
+ - UI labels, descriptions, and messages in English
540
+ - Filter descriptions in English
541
+
542
+ 3. **Improved User Experience**:
543
+ - Images are now closer together for better before/after comparison
544
+ - More intuitive workflow: upload → select filter → customize → apply
545
+ - Cleaner visual hierarchy
546
+
547
+ The app maintains all functionality while providing a better layout and full English localization! 🎨✨
requirements.txt CHANGED
@@ -1,4 +1,8 @@
1
- gradio
2
  opencv-python
3
- opencv-contrib-python
4
  numpy
 
 
 
 
 
 
 
 
1
  opencv-python
 
2
  numpy
3
+ gradio
4
+ requests
5
+ Pillow
6
+ filter
7
+ registry
8
+ components