jeffliulab commited on
Commit
6cf5f32
·
verified ·
1 Parent(s): ed43afb

Initial deploy

Browse files
Files changed (5) hide show
  1. README.md +10 -5
  2. app.py +143 -0
  3. examples/room.jpg +0 -0
  4. examples/street.jpg +0 -0
  5. requirements.txt +5 -0
README.md CHANGED
@@ -1,12 +1,17 @@
1
  ---
2
  title: Semantic Segmentation
3
- emoji: 📉
4
- colorFrom: green
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 6.11.0
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
1
  ---
2
  title: Semantic Segmentation
3
+ emoji: "\U0001F3A8"
4
+ colorFrom: blue
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: "5.29.0"
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
11
  ---
12
 
13
+ # Semantic Segmentation
14
+
15
+ Upload an image to see pixel-level classification with DeepLabV3.
16
+
17
+ **Courses**: 100 ch3 (Computer Vision), 360 ch4 (Perception)
app.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Semantic Segmentation — Pixel-level classification with DeepLabV3
3
+ Courses: 100 ch3, 360 ch4
4
+ """
5
+
6
+ import numpy as np
7
+ import torch
8
+ import torchvision.models.segmentation as seg_models
9
+ import torchvision.transforms as T
10
+ import gradio as gr
11
+ from PIL import Image
12
+
13
+ device = torch.device("cpu")
14
+
15
+ # Load DeepLabV3 with MobileNetV3 backbone (lightweight)
16
+ model = seg_models.deeplabv3_mobilenet_v3_large(
17
+ weights=seg_models.DeepLabV3_MobileNet_V3_Large_Weights.DEFAULT
18
+ ).eval().to(device)
19
+
20
+ preprocess = T.Compose([
21
+ T.ToTensor(),
22
+ T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
23
+ ])
24
+
25
+ # PASCAL VOC class names (21 classes)
26
+ CLASS_NAMES = [
27
+ "background", "aeroplane", "bicycle", "bird", "boat",
28
+ "bottle", "bus", "car", "cat", "chair",
29
+ "cow", "dining table", "dog", "horse", "motorbike",
30
+ "person", "potted plant", "sheep", "sofa", "train",
31
+ "tv/monitor",
32
+ ]
33
+
34
+ # Color palette for each class
35
+ PALETTE = np.array([
36
+ [0, 0, 0], # background
37
+ [128, 0, 0], # aeroplane
38
+ [0, 128, 0], # bicycle
39
+ [128, 128, 0], # bird
40
+ [0, 0, 128], # boat
41
+ [128, 0, 128], # bottle
42
+ [0, 128, 128], # bus
43
+ [128, 128, 128], # car
44
+ [64, 0, 0], # cat
45
+ [192, 0, 0], # chair
46
+ [64, 128, 0], # cow
47
+ [192, 128, 0], # dining table
48
+ [64, 0, 128], # dog
49
+ [192, 0, 128], # horse
50
+ [64, 128, 128], # motorbike
51
+ [192, 128, 128], # person
52
+ [0, 64, 0], # potted plant
53
+ [128, 64, 0], # sheep
54
+ [0, 192, 0], # sofa
55
+ [128, 192, 0], # train
56
+ [0, 64, 128], # tv/monitor
57
+ ], dtype=np.uint8)
58
+
59
+
60
+ def segment(image: Image.Image, display_mode: str):
61
+ if image is None:
62
+ return None, None, ""
63
+
64
+ img = image.convert("RGB")
65
+ w, h = img.size
66
+
67
+ # Inference
68
+ inp = preprocess(img).unsqueeze(0).to(device)
69
+ with torch.no_grad():
70
+ output = model(inp)["out"]
71
+ pred = output.argmax(1).squeeze().cpu().numpy()
72
+
73
+ # Resize prediction to original size
74
+ pred_resized = np.array(
75
+ Image.fromarray(pred.astype(np.uint8)).resize((w, h), Image.NEAREST)
76
+ )
77
+
78
+ # Color segmentation map
79
+ seg_color = PALETTE[pred_resized]
80
+
81
+ # Overlay
82
+ img_np = np.array(img)
83
+ overlay = (img_np * 0.5 + seg_color * 0.5).astype(np.uint8)
84
+
85
+ # Detected classes
86
+ unique_classes = np.unique(pred_resized)
87
+ detected = [CLASS_NAMES[c] for c in unique_classes if c != 0]
88
+
89
+ legend = "**Detected classes:**\n\n"
90
+ for c in unique_classes:
91
+ if c == 0:
92
+ continue
93
+ color = PALETTE[c]
94
+ pixel_pct = np.sum(pred_resized == c) / pred_resized.size * 100
95
+ color_hex = f"#{color[0]:02x}{color[1]:02x}{color[2]:02x}"
96
+ legend += f"- <span style='color:{color_hex};font-weight:bold;'>██</span> {CLASS_NAMES[c]} ({pixel_pct:.1f}%)\n"
97
+
98
+ if not detected:
99
+ legend += "- No objects detected (background only)"
100
+
101
+ if display_mode == "Overlay":
102
+ return overlay, seg_color, legend
103
+ elif display_mode == "Segmentation Only":
104
+ return seg_color, seg_color, legend
105
+ else: # Side by Side
106
+ return overlay, seg_color, legend
107
+
108
+
109
+ with gr.Blocks(title="Semantic Segmentation") as demo:
110
+ gr.Markdown(
111
+ "# Semantic Segmentation\n"
112
+ "Upload an image to see pixel-level classification (21 PASCAL VOC classes).\n"
113
+ "*Courses: 100 Deep Learning ch3, 360 Autonomous Driving ch4*"
114
+ )
115
+
116
+ with gr.Row():
117
+ with gr.Column(scale=1):
118
+ input_image = gr.Image(type="pil", label="Upload Image")
119
+ mode = gr.Radio(
120
+ ["Overlay", "Segmentation Only", "Side by Side"],
121
+ value="Overlay",
122
+ label="Display Mode",
123
+ )
124
+ btn = gr.Button("Segment", variant="primary")
125
+
126
+ with gr.Column(scale=2):
127
+ with gr.Row():
128
+ overlay_out = gr.Image(label="Result")
129
+ seg_out = gr.Image(label="Segmentation Map")
130
+ legend_md = gr.Markdown()
131
+
132
+ btn.click(segment, [input_image, mode], [overlay_out, seg_out, legend_md])
133
+
134
+ gr.Examples(
135
+ examples=[
136
+ ["examples/street.jpg", "Overlay"],
137
+ ["examples/room.jpg", "Side by Side"],
138
+ ],
139
+ inputs=[input_image, mode],
140
+ )
141
+
142
+ if __name__ == "__main__":
143
+ demo.launch()
examples/room.jpg ADDED
examples/street.jpg ADDED
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio>=5.0.0
2
+ torch>=2.0.0
3
+ torchvision>=0.15.0
4
+ numpy
5
+ Pillow