Views
No views yet
model.export(format="onnx") and placed in its own folder. The exports are meant to be used directly with ONNX Runtime, with no ultralytics package required at inference time.| Size | Detect | Segment | OBB | Pose | Classify |
|---|---|---|---|---|---|
| n | yolo26n | yolo26n-seg | yolo26n-obb | yolo26n-pose | yolo26n-cls |
| s | yolo26s | yolo26s-seg | yolo26s-obb | yolo26s-pose | yolo26s-cls |
| m | yolo26m | yolo26m-seg | yolo26m-obb | yolo26m-pose | yolo26m-cls |
| l | yolo26l | yolo26l-seg | yolo26l-obb | yolo26l-pose | yolo26l-cls |
| x | yolo26x | yolo26x-seg | yolo26x-obb | yolo26x-pose | yolo26x-cls |
YOLO26-ONNX/
├── README.md
├── yolo26n/yolo26n.onnx
├── yolo26s/yolo26s.onnx
├── yolo26m/yolo26m.onnx
├── yolo26l/yolo26l.onnx
├── yolo26x/yolo26x.onnx
├── yolo26n-seg/yolo26n-seg.onnx
├── yolo26s-seg/yolo26s-seg.onnx
├── yolo26m-seg/yolo26m-seg.onnx
├── yolo26l-seg/yolo26l-seg.onnx
├── yolo26x-seg/yolo26x-seg.onnx
├── yolo26n-obb/yolo26n-obb.onnx
├── yolo26s-obb/yolo26s-obb.onnx
├── yolo26m-obb/yolo26m-obb.onnx
├── yolo26l-obb/yolo26l-obb.onnx
├── yolo26x-obb/yolo26x-obb.onnx
├── yolo26n-pose/yolo26n-pose.onnx
├── yolo26s-pose/yolo26s-pose.onnx
├── yolo26m-pose/yolo26m-pose.onnx
├── yolo26l-pose/yolo26l-pose.onnx
├── yolo26x-pose/yolo26x-pose.onnx
├── yolo26n-cls/yolo26n-cls.onnx
├── yolo26s-cls/yolo26s-cls.onnx
├── yolo26m-cls/yolo26m-cls.onnx
├── yolo26l-cls/yolo26l-cls.onnx
├── yolo26x-cls/yolo26x-cls.onnx
└── yolo26_onnx_utils.py!pip install \
gradio \
ultralytics \
huggingface_hub \
onnx>=1.16.0 \
onnxslim>=0.1.31 \
onnxruntime>=1.18.0 \
opencv-python-headless>=4.9.0 \
numpy1import json
2import tempfile
3import time
4from pathlib import Path
5
6import cv2
7import gradio as gr
8import numpy as np
9import onnxruntime as ort
10import PIL.Image as Image
11from huggingface_hub import hf_hub_download
12
13# ============================================================================
14# Config
15# ============================================================================
16
17MODEL_REPO = "prithivMLmods/YOLO26-ONNX"
18
19SIZES = ["n", "s", "m", "l", "x"]
20TASK_SUFFIX = {"detect": "", "seg": "-seg", "obb": "-obb", "pose": "-pose", "cls": "-cls"}
21TASK_ORDER = ["detect", "seg", "obb", "pose", "cls"]
22TASK_IMGSZ = {"detect": 640, "seg": 640, "obb": 640, "pose": 640, "cls": 224}
23IMAGE_SIZE_CHOICES = [320, 640, 1024]
24
25
26def variant_name(size, task):
27 return f"yolo26{size}{TASK_SUFFIX[task]}"
28
29
30MODEL_CHOICES = [variant_name(s, t) for t in TASK_ORDER for s in SIZES]
31
32COCO80 = [
33 "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat",
34 "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat",
35 "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack",
36 "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball",
37 "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket",
38 "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
39 "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair",
40 "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse",
41 "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator",
42 "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush",
43]
44
45# COCO 17-keypoint skeleton (0-indexed) + keypoint colors
46POSE_SKELETON = [
47 (15, 13), (13, 11), (16, 14), (14, 12), (11, 12), (5, 11), (6, 12), (5, 6), (5, 7),
48 (6, 8), (7, 9), (8, 10), (1, 2), (0, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 6),
49]
50
51
52def class_color(idx):
53 """Deterministic BGR color per class index."""
54 hue = (idx * 47) % 180
55 hsv = np.uint8([[[hue, 200, 255]]])
56 bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)[0][0]
57 return tuple(int(c) for c in bgr)
58
59
60# ============================================================================
61# Model cache + preload
62# ============================================================================
63
64MODEL_CACHE = {} # name -> dict(session, task, imgsz, input_name, output_names)
65_IMAGENET_LABELS = None
66
67
68def task_for_name(name):
69 for task in ("cls", "seg", "obb", "pose"): # check longest/most-specific suffixes first
70 if name.endswith(TASK_SUFFIX[task]) and TASK_SUFFIX[task]:
71 return task
72 return "detect"
73
74
75def load_imagenet_labels():
76 """Lazily fetch ImageNet-1k id->label names (used by yolo26*-cls variants)."""
77 global _IMAGENET_LABELS
78 if _IMAGENET_LABELS is not None:
79 return _IMAGENET_LABELS
80 try:
81 path = hf_hub_download(repo_id="huggingface/label-files", filename="imagenet-1k-id2label.json", repo_type="dataset")
82 with open(path) as f:
83 id2label = json.load(f)
84 _IMAGENET_LABELS = [id2label[str(i)] for i in range(len(id2label))]
85 except Exception as e:
86 print(f"[YOLO26-ONNX] could not load ImageNet labels ({e}); classification will show raw indices.")
87 _IMAGENET_LABELS = []
88 return _IMAGENET_LABELS
89
90
91def preload_all_models():
92 providers = ["CUDAExecutionProvider", "CPUExecutionProvider"]
93 print(f"[YOLO26-ONNX] preloading {len(MODEL_CHOICES)} variants from {MODEL_REPO} ...")
94 for i, name in enumerate(MODEL_CHOICES):
95 task = task_for_name(name)
96 t0 = time.time()
97 try:
98 onnx_path = hf_hub_download(repo_id=MODEL_REPO, filename=f"{name}/{name}.onnx")
99 session = ort.InferenceSession(onnx_path, providers=providers)
100 in_shape = session.get_inputs()[0].shape
101 h = in_shape[2] if isinstance(in_shape[2], int) else TASK_IMGSZ[task]
102 w = in_shape[3] if isinstance(in_shape[3], int) else TASK_IMGSZ[task]
103 MODEL_CACHE[name] = {
104 "session": session,
105 "task": task,
106 "imgsz": (h, w),
107 "input_name": session.get_inputs()[0].name,
108 "output_names": [o.name for o in session.get_outputs()],
109 }
110 print(f"[YOLO26-ONNX] [{i + 1}/{len(MODEL_CHOICES)}] loaded {name} ({task}) in {time.time() - t0:.1f}s")
111 except Exception as e:
112 print(f"[YOLO26-ONNX] [{i + 1}/{len(MODEL_CHOICES)}] FAILED to load {name}: {e}")
113
114 if any(task_for_name(n) == "cls" for n in MODEL_CACHE):
115 load_imagenet_labels()
116
117 print(f"[YOLO26-ONNX] preload complete: {len(MODEL_CACHE)}/{len(MODEL_CHOICES)} models ready.")
118
119
120preload_all_models()
121
122# ============================================================================
123# Preprocessing
124# ============================================================================
125
126
127def letterbox(image, new_shape=640, color=(114, 114, 114)):
128 if isinstance(new_shape, int):
129 new_shape = (new_shape, new_shape)
130 h0, w0 = image.shape[:2]
131 r = min(new_shape[0] / h0, new_shape[1] / w0)
132 new_unpad = (int(round(w0 * r)), int(round(h0 * r)))
133 dw = (new_shape[1] - new_unpad[0]) / 2
134 dh = (new_shape[0] - new_unpad[1]) / 2
135 if (w0, h0) != new_unpad:
136 image = cv2.resize(image, new_unpad, interpolation=cv2.INTER_LINEAR)
137 top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
138 left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
139 image = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)
140 return image, r, (left, top)
141
142
143def preprocess_spatial(image_bgr, imgsz):
144 padded, ratio, pad = letterbox(image_bgr, imgsz)
145 img = padded[:, :, ::-1].transpose(2, 0, 1)
146 img = np.ascontiguousarray(img, dtype=np.float32) / 255.0
147 return img[None], ratio, pad, image_bgr.shape[:2]
148
149
150def preprocess_cls(image_bgr, imgsz):
151 """Classification preprocessing: plain resize (no letterbox padding)."""
152 h, w = imgsz
153 resized = cv2.resize(image_bgr, (w, h), interpolation=cv2.INTER_LINEAR)
154 img = resized[:, :, ::-1].transpose(2, 0, 1)
155 img = np.ascontiguousarray(img, dtype=np.float32) / 255.0
156 return img[None]
157
158
159def scale_xy_back(xy, ratio, pad, orig_shape):
160 out = xy.copy()
161 out[..., 0] -= pad[0]
162 out[..., 1] -= pad[1]
163 out /= ratio
164 h0, w0 = orig_shape
165 out[..., 0] = out[..., 0].clip(0, w0)
166 out[..., 1] = out[..., 1].clip(0, h0)
167 return out
168
169
170def scale_boxes_back(boxes_xyxy, ratio, pad, orig_shape):
171 boxes = boxes_xyxy.copy()
172 boxes[:, [0, 2]] -= pad[0]
173 boxes[:, [1, 3]] -= pad[1]
174 boxes /= ratio
175 h0, w0 = orig_shape
176 boxes[:, [0, 2]] = boxes[:, [0, 2]].clip(0, w0)
177 boxes[:, [1, 3]] = boxes[:, [1, 3]].clip(0, h0)
178 return boxes
179
180
181def extra_nms(boxes, scores, classes, iou_thres):
182 """Optional belt-and-suspenders NMS per class on top of YOLO26's native
183 end-to-end (NMS-free) output. Usually a no-op since the model already
184 returns filtered detections, but keeps the IoU slider meaningful."""
185 if len(boxes) == 0:
186 return np.arange(0)
187 keep_all = []
188 for c in np.unique(classes):
189 idx = np.where(classes == c)[0]
190 b = boxes[idx]
191 s = scores[idx]
192 xywh = np.stack([b[:, 0], b[:, 1], b[:, 2] - b[:, 0], b[:, 3] - b[:, 1]], axis=1)
193 keep = cv2.dnn.NMSBoxes(xywh.tolist(), s.tolist(), score_threshold=0.0, nms_threshold=iou_thres)
194 if len(keep) > 0:
195 keep = np.array(keep).reshape(-1)
196 keep_all.extend(idx[keep].tolist())
197 return np.array(sorted(keep_all), dtype=int)
198
199
200# ============================================================================
201# Inference + decode
202# ============================================================================
203
204
205def run_inference(model_name, image_bgr, conf_thres, iou_thres, imgsz_override=None):
206 entry = MODEL_CACHE[model_name]
207 session, task = entry["session"], entry["task"]
208 imgsz = (int(imgsz_override), int(imgsz_override)) if imgsz_override else entry["imgsz"]
209
210 if task == "cls":
211 blob = preprocess_cls(image_bgr, imgsz)
212 outputs = session.run(entry["output_names"], {entry["input_name"]: blob})
213 logits = outputs[0][0]
214 exp = np.exp(logits - logits.max())
215 probs = exp / exp.sum()
216 top5_idx = probs.argsort()[::-1][:5]
217 labels = load_imagenet_labels()
218 top5_labels = [labels[i] if labels and i < len(labels) else str(i) for i in top5_idx]
219 return {"task": "cls", "top5_idx": top5_idx, "top5_conf": probs[top5_idx], "top5_labels": top5_labels}
220
221 blob, ratio, pad, orig_shape = preprocess_spatial(image_bgr, imgsz)
222 outputs = session.run(entry["output_names"], {entry["input_name"]: blob})
223
224 det = outputs[0]
225 if det.ndim == 3:
226 det = det[0]
227 keep = det[:, 4] >= conf_thres
228 det = det[keep]
229
230 result = {"task": task, "boxes": np.zeros((0, 4)), "scores": np.zeros((0,)), "classes": np.zeros((0,), dtype=int)}
231 if det.shape[0] == 0:
232 return result
233
234 boxes = scale_boxes_back(det[:, :4].astype(np.float32), ratio, pad, orig_shape)
235 scores = det[:, 4]
236 classes = det[:, 5].astype(int)
237
238 order = extra_nms(boxes, scores, classes, iou_thres)
239 if len(order) == 0:
240 return result
241 boxes, scores, classes, det = boxes[order], scores[order], classes[order], det[order]
242
243 result.update(boxes=boxes, scores=scores, classes=classes)
244
245 if task == "obb" and det.shape[1] >= 7:
246 result["angles"] = det[:, 6]
247 elif task == "pose" and det.shape[1] > 6:
248 n_kpt = (det.shape[1] - 6) // 3
249 kpts = det[:, 6:6 + n_kpt * 3].reshape(-1, n_kpt, 3).copy()
250 kpts[..., :2] = scale_xy_back(kpts[..., :2], ratio, pad, orig_shape)
251 result["keypoints"] = kpts
252 elif task == "seg" and len(outputs) > 1:
253 proto = outputs[1][0] # (32, mh, mw)
254 n_mask = proto.shape[0]
255 mask_coeffs = det[:, 6:6 + n_mask]
256 result["masks"] = decode_masks(mask_coeffs, proto, pad, orig_shape, imgsz)
257
258 return result
259
260
261def decode_masks(mask_coeffs, proto, pad, orig_shape, imgsz):
262 n_mask, mh, mw = proto.shape
263 proto_flat = proto.reshape(n_mask, -1)
264 masks = 1 / (1 + np.exp(-(mask_coeffs @ proto_flat)))
265 masks = masks.reshape(-1, mh, mw)
266 ih, iw = imgsz
267 h0, w0 = orig_shape
268 left, top = pad
269 out = np.zeros((masks.shape[0], h0, w0), dtype=np.uint8)
270 for i, m in enumerate(masks):
271 m_full = cv2.resize(m, (iw, ih), interpolation=cv2.INTER_LINEAR)
272 m_cropped = m_full[top: ih - top, left: iw - left]
273 if m_cropped.size == 0:
274 m_cropped = m_full
275 m_resized = cv2.resize(m_cropped, (w0, h0), interpolation=cv2.INTER_LINEAR)
276 out[i] = (m_resized > 0.5).astype(np.uint8)
277 return out
278
279
280def obb_corners(box, angle):
281 """box=[x1,y1,x2,y2] axis-aligned extent, angle in radians -> 4 rotated corner points.
282 NOTE: verify angle sign/units against your specific export in Netron before
283 relying on this for anything beyond visualization."""
284 x1, y1, x2, y2 = box
285 cx, cy = (x1 + x2) / 2, (y1 + y2) / 2
286 w, h = x2 - x1, y2 - y1
287 cos_a, sin_a = np.cos(angle), np.sin(angle)
288 pts = np.array([[-w / 2, -h / 2], [w / 2, -h / 2], [w / 2, h / 2], [-w / 2, h / 2]])
289 rot = np.array([[cos_a, -sin_a], [sin_a, cos_a]])
290 pts = pts @ rot.T + np.array([cx, cy])
291 return pts.astype(int)
292
293
294# ============================================================================
295# Drawing
296# ============================================================================
297
298
299def draw_result(image_bgr, result, show_labels=True, show_conf=True, class_names=None):
300 img = image_bgr.copy()
301 task = result["task"]
302
303 if task == "cls":
304 for i, (label, conf) in enumerate(zip(result["top5_labels"], result["top5_conf"])):
305 text = f"{label}: {conf * 100:.1f}%" if show_conf else label
306 cv2.putText(img, text, (10, 30 + 28 * i), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 0), 4, cv2.LINE_AA)
307 cv2.putText(img, text, (10, 30 + 28 * i), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 1, cv2.LINE_AA)
308 return img
309
310 names = class_names or (COCO80 if task != "pose" else ["person"])
311 boxes, scores, classes = result["boxes"], result["scores"], result["classes"]
312
313 for i in range(len(boxes)):
314 cls_id = int(classes[i])
315 color = class_color(cls_id)
316 label_txt = names[cls_id] if cls_id < len(names) else str(cls_id)
317 if show_conf:
318 label_txt = f"{label_txt} {scores[i]:.2f}"
319
320 if task == "obb" and "angles" in result:
321 pts = obb_corners(boxes[i], result["angles"][i])
322 cv2.polylines(img, [pts], True, color, 2)
323 anchor = tuple(pts[0])
324 else:
325 x1, y1, x2, y2 = boxes[i].astype(int)
326 cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)
327 anchor = (x1, y1)
328
329 if show_labels:
330 (tw, th), _ = cv2.getTextSize(label_txt, cv2.FONT_HERSHEY_SIMPLEX, 0.55, 1)
331 ax, ay = anchor
332 cv2.rectangle(img, (ax, max(0, ay - th - 6)), (ax + tw + 4, ay), color, -1)
333 cv2.putText(img, label_txt, (ax + 2, max(12, ay - 4)), cv2.FONT_HERSHEY_SIMPLEX, 0.55, (255, 255, 255), 1, cv2.LINE_AA)
334
335 if task == "seg" and "masks" in result and i < len(result["masks"]):
336 mask = result["masks"][i].astype(bool)
337 overlay = img.copy()
338 overlay[mask] = color
339 img = cv2.addWeighted(overlay, 0.4, img, 0.6, 0)
340
341 if task == "pose" and "keypoints" in result:
342 kpts = result["keypoints"][i]
343 for x, y, v in kpts:
344 if v > 0.3:
345 cv2.circle(img, (int(x), int(y)), 3, (0, 255, 0), -1)
346 for a, b in POSE_SKELETON:
347 if a < len(kpts) and b < len(kpts) and kpts[a][2] > 0.3 and kpts[b][2] > 0.3:
348 pa, pb = kpts[a][:2].astype(int), kpts[b][:2].astype(int)
349 cv2.line(img, tuple(pa), tuple(pb), (0, 200, 255), 2)
350
351 return img
352
353
354# ============================================================================
355# Gradio callbacks
356# ============================================================================
357
358
359def predict_image(img, conf_threshold, iou_threshold, model_name, show_labels, show_conf, imgsz):
360 if img is None or model_name not in MODEL_CACHE:
361 return None
362 image_bgr = cv2.cvtColor(np.array(img.convert("RGB")), cv2.COLOR_RGB2BGR)
363 result = run_inference(model_name, image_bgr, conf_threshold, iou_threshold, imgsz)
364 annotated = draw_result(image_bgr, result, show_labels, show_conf)
365 return Image.fromarray(cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB))
366
367
368def predict_video(video_path, conf_threshold, iou_threshold, model_name, show_labels, show_conf, imgsz):
369 if video_path is None or model_name not in MODEL_CACHE:
370 return None
371
372 cap = cv2.VideoCapture(video_path)
373 if not cap.isOpened():
374 return None
375
376 fps = int(cap.get(cv2.CAP_PROP_FPS)) or 25
377 width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
378 height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
379
380 temp_output = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
381 output_path = temp_output.name
382 temp_output.close()
383
384 fourcc = cv2.VideoWriter_fourcc(*"mp4v")
385 out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
386
387 while True:
388 ret, frame = cap.read()
389 if not ret:
390 break
391 result = run_inference(model_name, frame, conf_threshold, iou_threshold, imgsz)
392 annotated = draw_result(frame, result, show_labels, show_conf)
393 out.write(annotated)
394
395 cap.release()
396 out.release()
397 return output_path
398
399
400def predict_webcam(frame, conf_threshold, iou_threshold, model_name, show_labels, show_conf, imgsz):
401 if frame is None or model_name not in MODEL_CACHE:
402 return None
403 if isinstance(frame, np.ndarray):
404 frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
405 result = run_inference(model_name, frame_bgr, conf_threshold, iou_threshold, imgsz)
406 annotated = draw_result(frame_bgr, result, show_labels, show_conf)
407 return cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)
408 return None
409
410
411# ============================================================================
412# UI
413# ============================================================================
414
415with gr.Blocks(title="YOLO26-ONNX") as demo:
416 gr.Markdown(
417 f"""
418# YOLO26-ONNX
419
420Real-time detection, segmentation, OBB, pose, and classification, running
421pure ONNX Runtime, no ultralytics install required at inference time.
422All {len(MODEL_CHOICES)} model variants are pulled from
423[{MODEL_REPO}](https://huggingface.co/{MODEL_REPO}) and preloaded at startup
424({len(MODEL_CACHE)}/{len(MODEL_CHOICES)} loaded successfully).
425"""
426 )
427
428 with gr.Tabs():
429 with gr.TabItem("Image"):
430 with gr.Row():
431 with gr.Column():
432 img_input = gr.Image(type="pil", label="Upload Image")
433 img_conf = gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold")
434 img_iou = gr.Slider(minimum=0, maximum=1, value=0.7, label="IoU threshold (extra NMS pass)")
435 img_model = gr.Radio(choices=MODEL_CHOICES, label="Model", value="yolo26n")
436 img_labels = gr.Checkbox(value=True, label="Show Labels")
437 img_conf_show = gr.Checkbox(value=True, label="Show Confidence")
438 img_size = gr.Radio(choices=IMAGE_SIZE_CHOICES, label="Image Size", value=640)
439 img_btn = gr.Button("Detect", variant="primary")
440 with gr.Column():
441 img_output = gr.Image(type="pil", label="Result")
442
443 img_btn.click(
444 predict_image,
445 inputs=[img_input, img_conf, img_iou, img_model, img_labels, img_conf_show, img_size],
446 outputs=img_output,
447 )
448
449 gr.Examples(
450 examples=[
451 ["https://ultralytics.com/images/bus.jpg", 0.25, 0.7, "yolo26n", True, True, 640],
452 ["https://ultralytics.com/images/zidane.jpg", 0.25, 0.7, "yolo26n-seg", True, True, 640],
453 ["https://ultralytics.com/images/boats.jpg", 0.25, 0.7, "yolo26n-obb", True, True, 1024],
454 ["https://ultralytics.com/images/zidane.jpg", 0.25, 0.7, "yolo26n-pose", True, True, 640],
455 ["https://ultralytics.com/images/bus.jpg", 0.25, 0.7, "yolo26n-cls", True, True, 224],
456 ],
457 inputs=[img_input, img_conf, img_iou, img_model, img_labels, img_conf_show, img_size],
458 )
459
460 with gr.TabItem("Video"):
461 with gr.Row():
462 with gr.Column():
463 vid_input = gr.Video(label="Upload Video")
464 vid_conf = gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold")
465 vid_iou = gr.Slider(minimum=0, maximum=1, value=0.7, label="IoU threshold (extra NMS pass)")
466 vid_model = gr.Radio(choices=MODEL_CHOICES, label="Model", value="yolo26n")
467 vid_labels = gr.Checkbox(value=True, label="Show Labels")
468 vid_conf_show = gr.Checkbox(value=True, label="Show Confidence")
469 vid_size = gr.Radio(choices=IMAGE_SIZE_CHOICES, label="Image Size", value=640)
470 vid_btn = gr.Button("Process Video", variant="primary")
471 with gr.Column():
472 vid_output = gr.Video(label="Result")
473
474 vid_btn.click(
475 predict_video,
476 inputs=[vid_input, vid_conf, vid_iou, vid_model, vid_labels, vid_conf_show, vid_size],
477 outputs=vid_output,
478 )
479
480 with gr.TabItem("Webcam"):
481 gr.Markdown("### Real-time Webcam Inference")
482 with gr.Row():
483 with gr.Column():
484 webcam_conf = gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold")
485 webcam_iou = gr.Slider(minimum=0, maximum=1, value=0.7, label="IoU threshold (extra NMS pass)")
486 webcam_model = gr.Radio(choices=MODEL_CHOICES, label="Model", value="yolo26n")
487 webcam_labels = gr.Checkbox(value=True, label="Show Labels")
488 webcam_conf_show = gr.Checkbox(value=True, label="Show Confidence")
489 webcam_size = gr.Radio(choices=IMAGE_SIZE_CHOICES, label="Image Size", value=640)
490 with gr.Column():
491 webcam_input = gr.Image(sources=["webcam"], type="numpy", label="Webcam (streaming)", streaming=True)
492 webcam_output = gr.Image(type="numpy", label="Detection Result")
493
494 webcam_input.stream(
495 predict_webcam,
496 inputs=[webcam_input, webcam_conf, webcam_iou, webcam_model, webcam_labels, webcam_conf_show, webcam_size],
497 outputs=webcam_output,
498 )
499
500if __name__ == "__main__":
501 demo.launch(ssr_mode=False)(1, 300, 6) as [x1, y1, x2, y2, confidence, class_id] in letterboxed pixel coordinates, already filtered without a separate NMS step.(1, num_classes) logits vector; softmax is applied client-side.-sem) variants are not included in this repository, only the five task heads shown above.