Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -95,15 +95,11 @@ def remove_background(image):
|
|
| 95 |
# ======================
|
| 96 |
# Dominant Color Detection using K-Means
|
| 97 |
# ======================
|
| 98 |
-
def get_dominant_color(image, n_colors=
|
| 99 |
"""
|
| 100 |
-
Get THE most dominant
|
| 101 |
|
| 102 |
-
|
| 103 |
-
1. Remove background
|
| 104 |
-
2. Extract only clothing pixels
|
| 105 |
-
3. Use K-means to find dominant color cluster
|
| 106 |
-
4. Convert to color name
|
| 107 |
"""
|
| 108 |
try:
|
| 109 |
# Step 1: Remove background
|
|
@@ -115,23 +111,14 @@ def get_dominant_color(image, n_colors=1):
|
|
| 115 |
|
| 116 |
# Step 3: Extract only non-transparent pixels (clothing only)
|
| 117 |
if img_array.shape[-1] == 4: # RGBA
|
| 118 |
-
# Get alpha channel
|
| 119 |
alpha = img_array[:, :, 3]
|
| 120 |
-
|
| 121 |
-
# Only pixels that are NOT transparent (alpha > 100)
|
| 122 |
mask = alpha > 100
|
| 123 |
-
|
| 124 |
-
# Get RGB pixels of clothing only
|
| 125 |
pixels = img_array[:, :, :3][mask]
|
| 126 |
else: # RGB
|
| 127 |
-
# Reshape all pixels
|
| 128 |
pixels = img_array.reshape(-1, 3)
|
| 129 |
|
| 130 |
-
# Step 4: Filter out pure white and pure black
|
| 131 |
-
# Remove whites (background)
|
| 132 |
pixels = pixels[~((pixels[:, 0] > 240) & (pixels[:, 1] > 240) & (pixels[:, 2] > 240))]
|
| 133 |
-
|
| 134 |
-
# Remove blacks (shadows)
|
| 135 |
pixels = pixels[~((pixels[:, 0] < 15) & (pixels[:, 1] < 15) & (pixels[:, 2] < 15))]
|
| 136 |
|
| 137 |
if len(pixels) < 10:
|
|
@@ -139,26 +126,24 @@ def get_dominant_color(image, n_colors=1):
|
|
| 139 |
|
| 140 |
print(f"[INFO] π Analyzing {len(pixels)} clothing pixels...")
|
| 141 |
|
| 142 |
-
# Step 5: Sample pixels if too many
|
| 143 |
if len(pixels) > 5000:
|
| 144 |
indices = np.random.choice(len(pixels), 5000, replace=False)
|
| 145 |
pixels = pixels[indices]
|
| 146 |
|
| 147 |
-
# Step 6:
|
| 148 |
kmeans = KMeans(n_clusters=min(n_colors, len(pixels)), random_state=42, n_init=10)
|
| 149 |
kmeans.fit(pixels)
|
| 150 |
|
| 151 |
-
# Step 7: Get
|
| 152 |
dominant_colors_rgb = kmeans.cluster_centers_
|
| 153 |
|
| 154 |
-
# Step 8:
|
| 155 |
labels = kmeans.labels_
|
| 156 |
label_counts = np.bincount(labels)
|
| 157 |
-
|
| 158 |
-
# Sort by frequency
|
| 159 |
sorted_indices = np.argsort(label_counts)[::-1]
|
| 160 |
|
| 161 |
-
# Step 9: Convert
|
| 162 |
color_names = []
|
| 163 |
color_rgb_values = []
|
| 164 |
|
|
@@ -166,12 +151,11 @@ def get_dominant_color(image, n_colors=1):
|
|
| 166 |
rgb = dominant_colors_rgb[idx].astype(int)
|
| 167 |
color_name = rgb_to_color_name(tuple(rgb))
|
| 168 |
|
| 169 |
-
# Avoid duplicates
|
| 170 |
if color_name not in color_names:
|
| 171 |
color_names.append(color_name)
|
| 172 |
color_rgb_values.append(rgb)
|
| 173 |
|
| 174 |
-
print(f"[INFO] π¨ Dominant
|
| 175 |
|
| 176 |
return color_names, color_rgb_values
|
| 177 |
|
|
@@ -185,14 +169,9 @@ def get_dominant_color(image, n_colors=1):
|
|
| 185 |
def rgb_to_color_name(rgb):
|
| 186 |
"""
|
| 187 |
Convert RGB to human-readable color name
|
| 188 |
-
Enhanced with more color ranges
|
| 189 |
"""
|
| 190 |
r, g, b = rgb
|
| 191 |
|
| 192 |
-
# Calculate color properties
|
| 193 |
-
max_val = max(r, g, b)
|
| 194 |
-
min_val = min(r, g, b)
|
| 195 |
-
|
| 196 |
# White
|
| 197 |
if r > 220 and g > 220 and b > 220:
|
| 198 |
return "White"
|
|
@@ -297,7 +276,7 @@ def rgb_to_color_name(rgb):
|
|
| 297 |
if r > 180 and g > 160 and b > 200:
|
| 298 |
return "Lavender"
|
| 299 |
|
| 300 |
-
# Default
|
| 301 |
return "Multicolor"
|
| 302 |
|
| 303 |
|
|
@@ -319,15 +298,55 @@ def detect_clothing_type(category):
|
|
| 319 |
return "π Western Wear"
|
| 320 |
|
| 321 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 322 |
# ======================
|
| 323 |
# Prediction Function
|
| 324 |
# ======================
|
| 325 |
def predict_fashion(image, custom_categories=None):
|
| 326 |
"""
|
| 327 |
-
Classify fashion item + detect dominant color
|
| 328 |
"""
|
| 329 |
if image is None:
|
| 330 |
-
return "β οΈ Please upload an image first!", {}
|
| 331 |
|
| 332 |
try:
|
| 333 |
# Step 1: Categories
|
|
@@ -356,18 +375,13 @@ def predict_fashion(image, custom_categories=None):
|
|
| 356 |
top_confidence = probs[top_prob_idx].item()
|
| 357 |
|
| 358 |
# Step 3: Dominant Color Detection
|
| 359 |
-
print("[INFO] π¨ Detecting dominant
|
| 360 |
dominant_colors, rgb_values = get_dominant_color(image, n_colors=3)
|
| 361 |
|
| 362 |
# Step 4: Type Detection
|
| 363 |
clothing_type = detect_clothing_type(top_category)
|
| 364 |
|
| 365 |
-
# Step 5:
|
| 366 |
-
color_preview = None
|
| 367 |
-
if rgb_values is not None and len(rgb_values) > 0:
|
| 368 |
-
color_preview = create_color_preview(rgb_values, dominant_colors)
|
| 369 |
-
|
| 370 |
-
# Step 6: Format result
|
| 371 |
result = f"""
|
| 372 |
### π― Fashion Item Detected
|
| 373 |
|
|
@@ -377,13 +391,32 @@ def predict_fashion(image, custom_categories=None):
|
|
| 377 |
|
| 378 |
---
|
| 379 |
|
| 380 |
-
### π¨
|
| 381 |
|
| 382 |
-
**Primary Color:** {dominant_colors[0] if dominant_colors else 'Unknown'} β¨
|
| 383 |
"""
|
| 384 |
|
| 385 |
-
|
| 386 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 387 |
|
| 388 |
result += f"""
|
| 389 |
---
|
|
@@ -413,6 +446,33 @@ def predict_fashion(image, custom_categories=None):
|
|
| 413 |
- Suitable for casual/formal settings
|
| 414 |
"""
|
| 415 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
# Top predictions
|
| 417 |
top_probs, top_indices = torch.topk(probs, k=min(5, len(categories)))
|
| 418 |
top_predictions = {}
|
|
@@ -420,50 +480,12 @@ def predict_fashion(image, custom_categories=None):
|
|
| 420 |
category = categories[idx.item()]
|
| 421 |
top_predictions[category] = float(prob.item())
|
| 422 |
|
| 423 |
-
return result, top_predictions
|
| 424 |
|
| 425 |
except Exception as e:
|
| 426 |
import traceback
|
| 427 |
error_msg = f"β Error: {str(e)}\n\n{traceback.format_exc()}"
|
| 428 |
-
return error_msg, {}
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
def create_color_preview(rgb_values, color_names):
|
| 432 |
-
"""
|
| 433 |
-
Create a visual preview of detected colors
|
| 434 |
-
"""
|
| 435 |
-
try:
|
| 436 |
-
# Create image with color swatches
|
| 437 |
-
num_colors = len(rgb_values)
|
| 438 |
-
swatch_height = 100
|
| 439 |
-
swatch_width = 200
|
| 440 |
-
|
| 441 |
-
img = Image.new('RGB', (swatch_width, swatch_height * num_colors), 'white')
|
| 442 |
-
|
| 443 |
-
import PIL.ImageDraw as ImageDraw
|
| 444 |
-
import PIL.ImageFont as ImageFont
|
| 445 |
-
|
| 446 |
-
draw = ImageDraw.Draw(img)
|
| 447 |
-
|
| 448 |
-
for i, (rgb, name) in enumerate(zip(rgb_values, color_names)):
|
| 449 |
-
y_start = i * swatch_height
|
| 450 |
-
y_end = (i + 1) * swatch_height
|
| 451 |
-
|
| 452 |
-
# Draw color swatch
|
| 453 |
-
draw.rectangle([0, y_start, swatch_width, y_end], fill=tuple(rgb))
|
| 454 |
-
|
| 455 |
-
# Add text (color name)
|
| 456 |
-
text = f"{name}\nRGB: {rgb[0]}, {rgb[1]}, {rgb[2]}"
|
| 457 |
-
|
| 458 |
-
# Use white or black text depending on background
|
| 459 |
-
text_color = 'white' if sum(rgb) < 384 else 'black'
|
| 460 |
-
draw.text((10, y_start + 30), text, fill=text_color)
|
| 461 |
-
|
| 462 |
-
return img
|
| 463 |
-
|
| 464 |
-
except Exception as e:
|
| 465 |
-
print(f"[ERROR] Color preview failed: {e}")
|
| 466 |
-
return None
|
| 467 |
|
| 468 |
|
| 469 |
# ======================
|
|
@@ -473,7 +495,7 @@ with gr.Blocks(title="Fashion-CLIP + Color Detection", theme=gr.themes.Soft()) a
|
|
| 473 |
|
| 474 |
gr.Markdown("""
|
| 475 |
# π AI Fashion Classifier with Smart Color Detection
|
| 476 |
-
### Background Removal + K-Means Clustering for Accurate Colors
|
| 477 |
""")
|
| 478 |
|
| 479 |
status = "π’ High Quality (rembg)" if REMBG_AVAILABLE else "π‘ Standard (GrabCut)"
|
|
@@ -481,13 +503,15 @@ with gr.Blocks(title="Fashion-CLIP + Color Detection", theme=gr.themes.Soft()) a
|
|
| 481 |
gr.Markdown(f"""
|
| 482 |
**Model:** Fashion-CLIP
|
| 483 |
**Color Detection:** K-Means Clustering
|
| 484 |
-
**Background Removal:** {status}
|
|
|
|
| 485 |
|
| 486 |
### β¨ How it works:
|
| 487 |
1. πΌοΈ **Upload** your fashion item image
|
| 488 |
2. π **Background** is automatically removed
|
| 489 |
-
3. π¨ **K-means** finds the dominant
|
| 490 |
4. π **Fashion-CLIP** classifies the item type
|
|
|
|
| 491 |
""")
|
| 492 |
|
| 493 |
with gr.Row():
|
|
@@ -507,6 +531,7 @@ with gr.Blocks(title="Fashion-CLIP + Color Detection", theme=gr.themes.Soft()) a
|
|
| 507 |
- Clear, well-lit photos work best
|
| 508 |
- Single clothing item preferred
|
| 509 |
- Background will be auto-removed
|
|
|
|
| 510 |
|
| 511 |
**π¦ For Best Results:**
|
| 512 |
```bash
|
|
@@ -517,13 +542,12 @@ with gr.Blocks(title="Fashion-CLIP + Color Detection", theme=gr.themes.Soft()) a
|
|
| 517 |
with gr.Column():
|
| 518 |
output_text = gr.Markdown(label="π Results")
|
| 519 |
output_label = gr.Label(label="π Top 5 Predictions", num_top_classes=5)
|
| 520 |
-
color_preview = gr.Image(label="π¨ Detected Colors", type="pil")
|
| 521 |
|
| 522 |
# Event
|
| 523 |
predict_btn.click(
|
| 524 |
fn=predict_fashion,
|
| 525 |
inputs=[input_image, custom_categories],
|
| 526 |
-
outputs=[output_text, output_label
|
| 527 |
)
|
| 528 |
|
| 529 |
gr.Markdown("""
|
|
@@ -539,10 +563,24 @@ with gr.Blocks(title="Fashion-CLIP + Color Detection", theme=gr.themes.Soft()) a
|
|
| 539 |
|
| 540 |
---
|
| 541 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 542 |
**π Powered by:**
|
| 543 |
- Fashion-CLIP (patrickjohncyh/fashion-clip)
|
| 544 |
- K-Means Clustering for dominant colors
|
| 545 |
- rembg/GrabCut for background removal
|
|
|
|
| 546 |
""")
|
| 547 |
|
| 548 |
# ======================
|
|
@@ -550,12 +588,13 @@ with gr.Blocks(title="Fashion-CLIP + Color Detection", theme=gr.themes.Soft()) a
|
|
| 550 |
# ======================
|
| 551 |
if __name__ == "__main__":
|
| 552 |
print("\n" + "="*60)
|
| 553 |
-
print("π FASHION CLASSIFIER WITH SMART COLOR DETECTION")
|
| 554 |
print("="*60)
|
| 555 |
print(f"β
Fashion-CLIP Model: Loaded")
|
| 556 |
print(f"β
Categories: {len(FASHION_CATEGORIES)}")
|
| 557 |
print(f"β
Background Removal: {'rembg (High Quality)' if REMBG_AVAILABLE else 'GrabCut (Standard)'}")
|
| 558 |
print(f"β
Color Detection: K-Means Clustering")
|
|
|
|
| 559 |
print("="*60 + "\n")
|
| 560 |
|
| 561 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
|
| 95 |
# ======================
|
| 96 |
# Dominant Color Detection using K-Means
|
| 97 |
# ======================
|
| 98 |
+
def get_dominant_color(image, n_colors=3):
|
| 99 |
"""
|
| 100 |
+
Get THE most dominant colors from clothing using K-means clustering
|
| 101 |
|
| 102 |
+
Returns: List of color names and their RGB values
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
"""
|
| 104 |
try:
|
| 105 |
# Step 1: Remove background
|
|
|
|
| 111 |
|
| 112 |
# Step 3: Extract only non-transparent pixels (clothing only)
|
| 113 |
if img_array.shape[-1] == 4: # RGBA
|
|
|
|
| 114 |
alpha = img_array[:, :, 3]
|
|
|
|
|
|
|
| 115 |
mask = alpha > 100
|
|
|
|
|
|
|
| 116 |
pixels = img_array[:, :, :3][mask]
|
| 117 |
else: # RGB
|
|
|
|
| 118 |
pixels = img_array.reshape(-1, 3)
|
| 119 |
|
| 120 |
+
# Step 4: Filter out pure white and pure black
|
|
|
|
| 121 |
pixels = pixels[~((pixels[:, 0] > 240) & (pixels[:, 1] > 240) & (pixels[:, 2] > 240))]
|
|
|
|
|
|
|
| 122 |
pixels = pixels[~((pixels[:, 0] < 15) & (pixels[:, 1] < 15) & (pixels[:, 2] < 15))]
|
| 123 |
|
| 124 |
if len(pixels) < 10:
|
|
|
|
| 126 |
|
| 127 |
print(f"[INFO] π Analyzing {len(pixels)} clothing pixels...")
|
| 128 |
|
| 129 |
+
# Step 5: Sample pixels if too many
|
| 130 |
if len(pixels) > 5000:
|
| 131 |
indices = np.random.choice(len(pixels), 5000, replace=False)
|
| 132 |
pixels = pixels[indices]
|
| 133 |
|
| 134 |
+
# Step 6: K-Means clustering
|
| 135 |
kmeans = KMeans(n_clusters=min(n_colors, len(pixels)), random_state=42, n_init=10)
|
| 136 |
kmeans.fit(pixels)
|
| 137 |
|
| 138 |
+
# Step 7: Get cluster centers
|
| 139 |
dominant_colors_rgb = kmeans.cluster_centers_
|
| 140 |
|
| 141 |
+
# Step 8: Sort by frequency
|
| 142 |
labels = kmeans.labels_
|
| 143 |
label_counts = np.bincount(labels)
|
|
|
|
|
|
|
| 144 |
sorted_indices = np.argsort(label_counts)[::-1]
|
| 145 |
|
| 146 |
+
# Step 9: Convert to color names
|
| 147 |
color_names = []
|
| 148 |
color_rgb_values = []
|
| 149 |
|
|
|
|
| 151 |
rgb = dominant_colors_rgb[idx].astype(int)
|
| 152 |
color_name = rgb_to_color_name(tuple(rgb))
|
| 153 |
|
|
|
|
| 154 |
if color_name not in color_names:
|
| 155 |
color_names.append(color_name)
|
| 156 |
color_rgb_values.append(rgb)
|
| 157 |
|
| 158 |
+
print(f"[INFO] π¨ Dominant colors detected: {', '.join(color_names)}")
|
| 159 |
|
| 160 |
return color_names, color_rgb_values
|
| 161 |
|
|
|
|
| 169 |
def rgb_to_color_name(rgb):
|
| 170 |
"""
|
| 171 |
Convert RGB to human-readable color name
|
|
|
|
| 172 |
"""
|
| 173 |
r, g, b = rgb
|
| 174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
# White
|
| 176 |
if r > 220 and g > 220 and b > 220:
|
| 177 |
return "White"
|
|
|
|
| 276 |
if r > 180 and g > 160 and b > 200:
|
| 277 |
return "Lavender"
|
| 278 |
|
| 279 |
+
# Default
|
| 280 |
return "Multicolor"
|
| 281 |
|
| 282 |
|
|
|
|
| 298 |
return "π Western Wear"
|
| 299 |
|
| 300 |
|
| 301 |
+
def get_color_emoji(color_name):
|
| 302 |
+
"""
|
| 303 |
+
Get emoji for color (visual representation)
|
| 304 |
+
"""
|
| 305 |
+
color_emojis = {
|
| 306 |
+
"Red": "π΄",
|
| 307 |
+
"Blue": "π΅",
|
| 308 |
+
"Green": "π’",
|
| 309 |
+
"Yellow": "π‘",
|
| 310 |
+
"Orange": "π ",
|
| 311 |
+
"Purple": "π£",
|
| 312 |
+
"Pink": "π©·",
|
| 313 |
+
"Brown": "π€",
|
| 314 |
+
"Black": "β«",
|
| 315 |
+
"White": "βͺ",
|
| 316 |
+
"Gray": "β«",
|
| 317 |
+
"Light Gray": "βͺ",
|
| 318 |
+
"Dark Gray": "β«",
|
| 319 |
+
"Navy": "π΅",
|
| 320 |
+
"Sky Blue": "π΅",
|
| 321 |
+
"Light Green": "π’",
|
| 322 |
+
"Dark Green": "π’",
|
| 323 |
+
"Maroon": "π΄",
|
| 324 |
+
"Coral": "π©·",
|
| 325 |
+
"Gold": "π‘",
|
| 326 |
+
"Beige": "π€",
|
| 327 |
+
"Cream": "βͺ",
|
| 328 |
+
"Olive": "π’",
|
| 329 |
+
"Cyan": "π΅",
|
| 330 |
+
"Magenta": "π£",
|
| 331 |
+
"Violet": "π£",
|
| 332 |
+
"Lavender": "π£",
|
| 333 |
+
"Light Yellow": "π‘",
|
| 334 |
+
"Dark Brown": "π€",
|
| 335 |
+
"Multicolor": "π"
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
return color_emojis.get(color_name, "π¨")
|
| 339 |
+
|
| 340 |
+
|
| 341 |
# ======================
|
| 342 |
# Prediction Function
|
| 343 |
# ======================
|
| 344 |
def predict_fashion(image, custom_categories=None):
|
| 345 |
"""
|
| 346 |
+
Classify fashion item + detect dominant color (TEXT OUTPUT)
|
| 347 |
"""
|
| 348 |
if image is None:
|
| 349 |
+
return "β οΈ Please upload an image first!", {}
|
| 350 |
|
| 351 |
try:
|
| 352 |
# Step 1: Categories
|
|
|
|
| 375 |
top_confidence = probs[top_prob_idx].item()
|
| 376 |
|
| 377 |
# Step 3: Dominant Color Detection
|
| 378 |
+
print("[INFO] π¨ Detecting dominant colors...")
|
| 379 |
dominant_colors, rgb_values = get_dominant_color(image, n_colors=3)
|
| 380 |
|
| 381 |
# Step 4: Type Detection
|
| 382 |
clothing_type = detect_clothing_type(top_category)
|
| 383 |
|
| 384 |
+
# Step 5: Format result with TEXT COLORS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 385 |
result = f"""
|
| 386 |
### π― Fashion Item Detected
|
| 387 |
|
|
|
|
| 391 |
|
| 392 |
---
|
| 393 |
|
| 394 |
+
### π¨ Detected Colors (Text Format)
|
| 395 |
|
|
|
|
| 396 |
"""
|
| 397 |
|
| 398 |
+
# β
DISPLAY COLORS AS TEXT
|
| 399 |
+
if dominant_colors and dominant_colors[0] != "Unable to detect":
|
| 400 |
+
# Primary Color
|
| 401 |
+
primary_color = dominant_colors[0]
|
| 402 |
+
primary_emoji = get_color_emoji(primary_color)
|
| 403 |
+
primary_rgb = rgb_values[0] if rgb_values else [0, 0, 0]
|
| 404 |
+
|
| 405 |
+
result += f"**Primary Color:** {primary_emoji} **{primary_color}** β¨\n"
|
| 406 |
+
result += f"*RGB Values: ({primary_rgb[0]}, {primary_rgb[1]}, {primary_rgb[2]})*\n\n"
|
| 407 |
+
|
| 408 |
+
# Secondary Colors
|
| 409 |
+
if len(dominant_colors) > 1:
|
| 410 |
+
result += "**Secondary Colors:**\n"
|
| 411 |
+
for i, (color, rgb) in enumerate(zip(dominant_colors[1:], rgb_values[1:]), 1):
|
| 412 |
+
emoji = get_color_emoji(color)
|
| 413 |
+
result += f" {i}. {emoji} **{color}** - RGB({rgb[0]}, {rgb[1]}, {rgb[2]})\n"
|
| 414 |
+
result += "\n"
|
| 415 |
+
|
| 416 |
+
# Color Summary
|
| 417 |
+
result += f"**Color Summary:** {', '.join(dominant_colors)} π\n"
|
| 418 |
+
else:
|
| 419 |
+
result += "β οΈ Unable to detect colors from image\n"
|
| 420 |
|
| 421 |
result += f"""
|
| 422 |
---
|
|
|
|
| 446 |
- Suitable for casual/formal settings
|
| 447 |
"""
|
| 448 |
|
| 449 |
+
# Color-based suggestions
|
| 450 |
+
if dominant_colors[0] != "Unable to detect":
|
| 451 |
+
primary = dominant_colors[0].lower()
|
| 452 |
+
|
| 453 |
+
result += f"\n**Color Styling Tips for {dominant_colors[0]}:**\n"
|
| 454 |
+
|
| 455 |
+
if "black" in primary:
|
| 456 |
+
result += "- Classic and versatile β«\n- Pairs well with any color\n- Perfect for formal events\n"
|
| 457 |
+
elif "white" in primary:
|
| 458 |
+
result += "- Clean and fresh look βͺ\n- Great for summer\n- Easy to accessorize\n"
|
| 459 |
+
elif "red" in primary:
|
| 460 |
+
result += "- Bold and confident π΄\n- Statement piece\n- Pair with neutral colors\n"
|
| 461 |
+
elif "blue" in primary:
|
| 462 |
+
result += "- Cool and calming π΅\n- Professional look\n- Versatile for day/night\n"
|
| 463 |
+
elif "green" in primary:
|
| 464 |
+
result += "- Natural and refreshing π’\n- Great for outdoor events\n- Pairs with earth tones\n"
|
| 465 |
+
elif "yellow" in primary or "gold" in primary:
|
| 466 |
+
result += "- Bright and cheerful π‘\n- Perfect for festivities\n- Eye-catching choice\n"
|
| 467 |
+
elif "pink" in primary:
|
| 468 |
+
result += "- Soft and feminine π©·\n- Romantic vibe\n- Great for parties\n"
|
| 469 |
+
elif "purple" in primary or "violet" in primary:
|
| 470 |
+
result += "- Royal and elegant π£\n- Sophisticated choice\n- Unique statement\n"
|
| 471 |
+
elif "brown" in primary or "beige" in primary:
|
| 472 |
+
result += "- Earthy and warm π€\n- Natural aesthetic\n- Timeless appeal\n"
|
| 473 |
+
elif "gray" in primary:
|
| 474 |
+
result += "- Neutral and modern β«\n- Professional look\n- Easy to style\n"
|
| 475 |
+
|
| 476 |
# Top predictions
|
| 477 |
top_probs, top_indices = torch.topk(probs, k=min(5, len(categories)))
|
| 478 |
top_predictions = {}
|
|
|
|
| 480 |
category = categories[idx.item()]
|
| 481 |
top_predictions[category] = float(prob.item())
|
| 482 |
|
| 483 |
+
return result, top_predictions
|
| 484 |
|
| 485 |
except Exception as e:
|
| 486 |
import traceback
|
| 487 |
error_msg = f"β Error: {str(e)}\n\n{traceback.format_exc()}"
|
| 488 |
+
return error_msg, {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 489 |
|
| 490 |
|
| 491 |
# ======================
|
|
|
|
| 495 |
|
| 496 |
gr.Markdown("""
|
| 497 |
# π AI Fashion Classifier with Smart Color Detection
|
| 498 |
+
### Background Removal + K-Means Clustering for Accurate Colors (Text Output)
|
| 499 |
""")
|
| 500 |
|
| 501 |
status = "π’ High Quality (rembg)" if REMBG_AVAILABLE else "π‘ Standard (GrabCut)"
|
|
|
|
| 503 |
gr.Markdown(f"""
|
| 504 |
**Model:** Fashion-CLIP
|
| 505 |
**Color Detection:** K-Means Clustering
|
| 506 |
+
**Background Removal:** {status}
|
| 507 |
+
**Output Format:** Text-based color names with RGB values
|
| 508 |
|
| 509 |
### β¨ How it works:
|
| 510 |
1. πΌοΈ **Upload** your fashion item image
|
| 511 |
2. π **Background** is automatically removed
|
| 512 |
+
3. π¨ **K-means** finds the dominant colors from clothing only
|
| 513 |
4. π **Fashion-CLIP** classifies the item type
|
| 514 |
+
5. π **Colors displayed as text** with emojis and RGB values
|
| 515 |
""")
|
| 516 |
|
| 517 |
with gr.Row():
|
|
|
|
| 531 |
- Clear, well-lit photos work best
|
| 532 |
- Single clothing item preferred
|
| 533 |
- Background will be auto-removed
|
| 534 |
+
- Colors shown as text with RGB values
|
| 535 |
|
| 536 |
**π¦ For Best Results:**
|
| 537 |
```bash
|
|
|
|
| 542 |
with gr.Column():
|
| 543 |
output_text = gr.Markdown(label="π Results")
|
| 544 |
output_label = gr.Label(label="π Top 5 Predictions", num_top_classes=5)
|
|
|
|
| 545 |
|
| 546 |
# Event
|
| 547 |
predict_btn.click(
|
| 548 |
fn=predict_fashion,
|
| 549 |
inputs=[input_image, custom_categories],
|
| 550 |
+
outputs=[output_text, output_label]
|
| 551 |
)
|
| 552 |
|
| 553 |
gr.Markdown("""
|
|
|
|
| 563 |
|
| 564 |
---
|
| 565 |
|
| 566 |
+
### π¨ Color Output Format:
|
| 567 |
+
|
| 568 |
+
**Primary Color:** π΄ **Red** β¨
|
| 569 |
+
*RGB Values: (255, 0, 0)*
|
| 570 |
+
|
| 571 |
+
**Secondary Colors:**
|
| 572 |
+
1. βͺ **White** - RGB(255, 255, 255)
|
| 573 |
+
2. β« **Black** - RGB(0, 0, 0)
|
| 574 |
+
|
| 575 |
+
**Color Summary:** Red, White, Black π
|
| 576 |
+
|
| 577 |
+
---
|
| 578 |
+
|
| 579 |
**π Powered by:**
|
| 580 |
- Fashion-CLIP (patrickjohncyh/fashion-clip)
|
| 581 |
- K-Means Clustering for dominant colors
|
| 582 |
- rembg/GrabCut for background removal
|
| 583 |
+
- Text-based color output with emojis
|
| 584 |
""")
|
| 585 |
|
| 586 |
# ======================
|
|
|
|
| 588 |
# ======================
|
| 589 |
if __name__ == "__main__":
|
| 590 |
print("\n" + "="*60)
|
| 591 |
+
print("π FASHION CLASSIFIER WITH SMART COLOR DETECTION (TEXT)")
|
| 592 |
print("="*60)
|
| 593 |
print(f"β
Fashion-CLIP Model: Loaded")
|
| 594 |
print(f"β
Categories: {len(FASHION_CATEGORIES)}")
|
| 595 |
print(f"β
Background Removal: {'rembg (High Quality)' if REMBG_AVAILABLE else 'GrabCut (Standard)'}")
|
| 596 |
print(f"β
Color Detection: K-Means Clustering")
|
| 597 |
+
print(f"β
Output Format: Text with RGB values")
|
| 598 |
print("="*60 + "\n")
|
| 599 |
|
| 600 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|