refactor: ♻️ update gradio add video and webcam and update styling of gradio

#1
by onuralpszr - opened
Files changed (2) hide show
  1. app.py +213 -27
  2. ultralytics.css +70 -0
app.py CHANGED
@@ -1,48 +1,234 @@
1
- # Ultralytics YOLO 🚀, AGPL-3.0 license
2
 
 
 
3
  import gradio as gr
 
4
  import PIL.Image as Image
5
  from ultralytics import YOLO
 
6
 
7
- model = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  def predict_image(img, conf_threshold, iou_threshold, model_name, show_labels, show_conf, imgsz):
10
- """Predicts objects in an image using a YOLOv8 model with adjustable confidence and IOU thresholds."""
11
  model = YOLO(model_name)
12
  results = model.predict(
13
  source=img,
14
  conf=conf_threshold,
15
  iou=iou_threshold,
16
- show_labels=show_labels,
17
- show_conf=show_conf,
18
  imgsz=imgsz,
 
19
  )
20
 
21
  for r in results:
22
- im_array = r.plot()
23
  im = Image.fromarray(im_array[..., ::-1])
24
 
25
  return im
26
 
27
 
28
- iface = gr.Interface(
29
- fn=predict_image,
30
- inputs=[
31
- gr.Image(type="pil", label="Upload Image"),
32
- gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold"),
33
- gr.Slider(minimum=0, maximum=1, value=0.45, label="IoU threshold"),
34
- gr.Radio(choices=["yolov8n", "yolov8s", "yolov8m", "yolov8n-seg", "yolov8s-seg", "yolov8m-seg", "yolov8n-pose", "yolov8s-pose", "yolov8m-pose", "yolov8n-obb", "yolov8s-obb", "yolov8m-obb"], label="Model Name", value="yolov8n"),
35
- gr.Checkbox(value=True, label="Show Labels"),
36
- gr.Checkbox(value=True, label="Show Confidence"),
37
- gr.Radio(choices=[320, 640, 1024], label="Image Size", value=640),
38
- ],
39
- outputs=gr.Image(type="pil", label="Result"),
40
- title="Ultralytics YOLOv8 Inference 🚀",
41
- description="Upload images for inference. The Ultralytics YOLOv8n model is used by default.",
42
- examples=[
43
- ["https://ultralytics.com/images/bus.jpg", 0.25, 0.45, "yolov8n", True, True, 640],
44
- ["https://ultralytics.com/images/zidane.jpg", 0.25, 0.45, "yolov8n-seg", True, True, 640],
45
- ["https://ultralytics.com/images/boats.jpg", 0.25, 0.45, "yolov8n-obb", True, True, 1024],
46
- ],
47
- )
48
- iface.launch(share=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
 
3
+ import tempfile
4
+ import cv2
5
  import gradio as gr
6
+ import numpy as np
7
  import PIL.Image as Image
8
  from ultralytics import YOLO
9
+ from pathlib import Path
10
 
11
+
12
+ MODEL_CHOICES = [
13
+ "yolov8n",
14
+ "yolov8s",
15
+ "yolov8m",
16
+ "yolov8n-seg",
17
+ "yolov8s-seg",
18
+ "yolov8m-seg",
19
+ "yolov8n-pose",
20
+ "yolov8s-pose",
21
+ "yolov8m-pose",
22
+ "yolov8n-obb",
23
+ "yolov8s-obb",
24
+ "yolov8m-obb",
25
+ "yolov8n-cls",
26
+ "yolov8s-cls",
27
+ "yolov8m-cls",
28
+ ]
29
+
30
+ IMAGE_SIZE_CHOICES = [320, 640, 1024]
31
+ CUSTOM_CSS = (Path(__file__).parent / "ultralytics.css").read_text()
32
 
33
  def predict_image(img, conf_threshold, iou_threshold, model_name, show_labels, show_conf, imgsz):
34
+ """Predicts objects in an image using a Ultralytics YOLO model with adjustable confidence and IOU thresholds."""
35
  model = YOLO(model_name)
36
  results = model.predict(
37
  source=img,
38
  conf=conf_threshold,
39
  iou=iou_threshold,
 
 
40
  imgsz=imgsz,
41
+ verbose=False,
42
  )
43
 
44
  for r in results:
45
+ im_array = r.plot(labels=show_labels, conf=show_conf)
46
  im = Image.fromarray(im_array[..., ::-1])
47
 
48
  return im
49
 
50
 
51
+ def predict_video(video_path, conf_threshold, iou_threshold, model_name, show_labels, show_conf, imgsz):
52
+ """Predicts objects in a video using a Ultralytics YOLO model and returns the annotated video."""
53
+ if video_path is None:
54
+ return None
55
+
56
+ model = YOLO(model_name)
57
+
58
+ # Open the video
59
+ cap = cv2.VideoCapture(video_path)
60
+ if not cap.isOpened():
61
+ return None
62
+
63
+ # Get video properties
64
+ fps = int(cap.get(cv2.CAP_PROP_FPS))
65
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
66
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
67
+
68
+ # Create temporary output file
69
+ temp_output = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
70
+ output_path = temp_output.name
71
+ temp_output.close()
72
+
73
+ # Initialize video writer
74
+ fourcc = cv2.VideoWriter_fourcc(*"mp4v")
75
+ out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
76
+
77
+ while True:
78
+ ret, frame = cap.read()
79
+ if not ret:
80
+ break
81
+
82
+ # Run inference on the frame
83
+ results = model.predict(
84
+ source=frame,
85
+ conf=conf_threshold,
86
+ iou=iou_threshold,
87
+ imgsz=imgsz,
88
+ verbose=False,
89
+ )
90
+
91
+ # Get the annotated frame
92
+ annotated_frame = results[0].plot(labels=show_labels, conf=show_conf)
93
+ out.write(annotated_frame)
94
+
95
+ cap.release()
96
+ out.release()
97
+
98
+ return output_path
99
+
100
+ # Cache model for streaming performance
101
+ _model_cache = {}
102
+
103
+ def get_model(model_name):
104
+ """Get or create a cached model instance."""
105
+ if model_name not in _model_cache:
106
+ _model_cache[model_name] = YOLO(model_name)
107
+ return _model_cache[model_name]
108
+
109
+
110
+ def predict_webcam(frame, conf_threshold, iou_threshold, model_name, show_labels, show_conf, imgsz):
111
+ """Predicts objects in a webcam frame using a Ultralytics YOLO model (optimized for streaming)."""
112
+ if frame is None:
113
+ return None
114
+
115
+ # Use cached model for better streaming performance
116
+ model = get_model(model_name)
117
+
118
+ if isinstance(frame, np.ndarray):
119
+ # Gradio webcam sends RGB, but Ultralytics YOLO expects BGR for OpenCV operations
120
+ # Convert RGB to BGR for YOLO
121
+ frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
122
+
123
+ # Run inference
124
+ results = model.predict(
125
+ source=frame_bgr,
126
+ conf=conf_threshold,
127
+ iou=iou_threshold,
128
+ imgsz=imgsz,
129
+ verbose=False,
130
+ )
131
+
132
+ # YOLO's plot() returns BGR, convert back to RGB for Gradio display
133
+ annotated_frame = results[0].plot(labels=show_labels, conf=show_conf)
134
+ # Convert BGR to RGB for Gradio
135
+ return cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
136
+
137
+ return None
138
+
139
+
140
+ # Create the Gradio app with tabs
141
+ with gr.Blocks(title="Ultralytics YOLOv8 Inference 🚀") as demo:
142
+ gr.Markdown("# Ultralytics YOLOv8 Inference 🚀")
143
+ gr.Markdown("Upload images, videos, or use your webcam for real-time object detection.")
144
+
145
+ with gr.Tabs():
146
+ # Image Tab
147
+ with gr.TabItem("📷 Image"):
148
+ with gr.Row():
149
+ with gr.Column():
150
+ img_input = gr.Image(type="pil", label="Upload Image")
151
+ img_conf = gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold")
152
+ img_iou = gr.Slider(minimum=0, maximum=1, value=0.7, label="IoU threshold")
153
+ img_model = gr.Radio(choices=MODEL_CHOICES, label="Model Name", value="yolov8n")
154
+ img_labels = gr.Checkbox(value=True, label="Show Labels")
155
+ img_conf_show = gr.Checkbox(value=True, label="Show Confidence")
156
+ img_size = gr.Radio(choices=IMAGE_SIZE_CHOICES, label="Image Size", value=640)
157
+ img_btn = gr.Button("Detect Objects", variant="primary")
158
+ with gr.Column():
159
+ img_output = gr.Image(type="pil", label="Result")
160
+
161
+ img_btn.click(
162
+ predict_image,
163
+ inputs=[img_input, img_conf, img_iou, img_model, img_labels, img_conf_show, img_size],
164
+ outputs=img_output,
165
+ )
166
+
167
+ gr.Examples(
168
+ examples=[
169
+ ["https://ultralytics.com/images/bus.jpg", 0.25, 0.7, "yolov8n", True, True, 640],
170
+ ["https://ultralytics.com/images/zidane.jpg", 0.25, 0.7, "yolov8n-seg", True, True, 640],
171
+ ["https://ultralytics.com/images/boats.jpg", 0.25, 0.7, "yolov8n-obb", True, True, 1024],
172
+ ],
173
+ inputs=[img_input, img_conf, img_iou, img_model, img_labels, img_conf_show, img_size],
174
+ )
175
+
176
+ # Video Tab
177
+ with gr.TabItem("🎬 Video"):
178
+ with gr.Row():
179
+ with gr.Column():
180
+ vid_input = gr.Video(label="Upload Video")
181
+ vid_conf = gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold")
182
+ vid_iou = gr.Slider(minimum=0, maximum=1, value=0.7, label="IoU threshold")
183
+ vid_model = gr.Radio(choices=MODEL_CHOICES, label="Model Name", value="yolov8n")
184
+ vid_labels = gr.Checkbox(value=True, label="Show Labels")
185
+ vid_conf_show = gr.Checkbox(value=True, label="Show Confidence")
186
+ vid_size = gr.Radio(choices=IMAGE_SIZE_CHOICES, label="Image Size", value=640)
187
+ vid_btn = gr.Button("Process Video", variant="primary")
188
+ with gr.Column():
189
+ vid_output = gr.Video(label="Result")
190
+
191
+ vid_btn.click(
192
+ predict_video,
193
+ inputs=[vid_input, vid_conf, vid_iou, vid_model, vid_labels, vid_conf_show, vid_size],
194
+ outputs=vid_output,
195
+ )
196
+
197
+ # Webcam Tab - Real-time streaming
198
+ with gr.TabItem("📹 Webcam"):
199
+ gr.Markdown("### Real-time Webcam Detection")
200
+ gr.Markdown("Enable streaming for live detection as you move!")
201
+ with gr.Row():
202
+ with gr.Column():
203
+ webcam_conf = gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold")
204
+ webcam_iou = gr.Slider(minimum=0, maximum=1, value=0.7, label="IoU threshold")
205
+ webcam_model = gr.Radio(choices=MODEL_CHOICES, label="Model Name", value="yolov8n")
206
+ webcam_labels = gr.Checkbox(value=True, label="Show Labels")
207
+ webcam_conf_show = gr.Checkbox(value=True, label="Show Confidence")
208
+ webcam_size = gr.Radio(choices=IMAGE_SIZE_CHOICES, label="Image Size", value=640)
209
+ with gr.Column():
210
+ # Streaming webcam input with real-time output
211
+ webcam_input = gr.Image(
212
+ sources=["webcam"],
213
+ type="numpy",
214
+ label="Webcam (streaming)",
215
+ streaming=True,
216
+ )
217
+ webcam_output = gr.Image(type="numpy", label="Detection Result")
218
+
219
+ # Stream event for real-time detection
220
+ webcam_input.stream(
221
+ predict_webcam,
222
+ inputs=[
223
+ webcam_input,
224
+ webcam_conf,
225
+ webcam_iou,
226
+ webcam_model,
227
+ webcam_labels,
228
+ webcam_conf_show,
229
+ webcam_size,
230
+ ],
231
+ outputs=webcam_output,
232
+ )
233
+
234
+ demo.launch(share=True, css=CUSTOM_CSS)
ultralytics.css ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
3
+ *
4
+ * Ultralytics Gradio Theme CSS
5
+ * Use this CSS file for consistent Ultralytics blue (#042AFF) styling across Gradio apps
6
+ * Compatible with Gradio 6.x
7
+ *
8
+ * Usage in app.py:
9
+ * from pathlib import Path
10
+ * custom_css = Path("ultralytics.css").read_text()
11
+ * demo.launch(css=custom_css)
12
+ */
13
+
14
+ /* Override Gradio CSS variables for Ultralytics blue */
15
+ .gradio-container {
16
+ --slider-color: #042AFF !important;
17
+ --checkbox-background-color-selected: #042AFF !important;
18
+ --checkbox-border-color-selected: #042AFF !important;
19
+ --checkbox-border-color-focus: #042AFF !important;
20
+ --button-primary-background-fill: #042AFF !important;
21
+ --button-primary-background-fill-hover: #0320CC !important;
22
+ --button-primary-border-color: #042AFF !important;
23
+ --color-accent: #042AFF !important;
24
+ --color-accent-soft: rgba(4, 42, 255, 0.15) !important;
25
+ }
26
+
27
+ /* Slider filled track */
28
+ input[type="range"]::-webkit-slider-runnable-track {
29
+ background: linear-gradient(to right, #042AFF var(--range_progress, 25%), var(--neutral-200, #e5e7eb) var(--range_progress, 25%)) !important;
30
+ }
31
+ input[type="range"]::-moz-range-progress {
32
+ background: #042AFF !important;
33
+ }
34
+
35
+ /* Radio and checkbox accent */
36
+ input[type="radio"],
37
+ input[type="checkbox"] {
38
+ accent-color: #042AFF !important;
39
+ }
40
+
41
+ /* Tab styling - remove orange, make blue */
42
+ button[role="tab"] {
43
+ border-bottom-color: transparent !important;
44
+ }
45
+ button[role="tab"].selected,
46
+ button[role="tab"][aria-selected="true"] {
47
+ background: transparent !important;
48
+ color: #042AFF !important;
49
+ border-bottom: 2px solid #042AFF !important;
50
+ }
51
+
52
+ /* Radio group selected item: blue background, white text */
53
+ .wrap.selected,
54
+ label.selected {
55
+ background: #042AFF !important;
56
+ border-color: #042AFF !important;
57
+ color: white !important;
58
+ }
59
+ label.selected span {
60
+ color: white !important;
61
+ }
62
+
63
+ /* Primary button */
64
+ button.primary {
65
+ background: #042AFF !important;
66
+ border-color: #042AFF !important;
67
+ }
68
+ button.primary:hover {
69
+ background: #0320CC !important;
70
+ }