ultralytics
Eval Results
Files changed (3) hide show
  1. apps/README.md +29 -0
  2. apps/webcam_app.py +202 -0
  3. tools/pt_bundle.py +159 -0
apps/README.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # YOLO11 Webcam App
2
+
3
+ Basit bir Streamlit arayΓΌzΓΌ ile webcam ΓΌzerinden YOLO11 gerΓ§ek zamanlΔ± tespit.
4
+
5
+ ## Gereksinimler
6
+ - Python 3.9+
7
+ - Paketler: `ultralytics`, `streamlit`, `streamlit-webrtc`, `av`, (opsiyonel) `huggingface_hub`
8
+
9
+ ## Kurulum (PowerShell)
10
+ ```powershell
11
+ cd C:\yolov11\YOLO11
12
+ python -m venv .venv
13
+ . .venv\Scripts\Activate.ps1
14
+ pip install -U pip
15
+ pip install ultralytics streamlit streamlit-webrtc av huggingface_hub
16
+ ```
17
+
18
+ ## Γ‡alıştΔ±rma
19
+ ```powershell
20
+ cd C:\yolov11\YOLO11
21
+ . .venv\Scripts\Activate.ps1
22
+ streamlit run apps/webcam_app.py
23
+ ```
24
+
25
+ Sol menΓΌden modeli yΓΌkleyin (ΓΆrn. `yolo11n.pt`) ve kameraya izin verin.
26
+
27
+ Notlar:
28
+ - HF Hub’dan ΓΆzel model Γ§ekmek iΓ§in `HF_TOKEN` ortam değişkeni gerekebilir.
29
+ - CUDA yoksa cihazΔ± `cpu` seΓ§in.
apps/webcam_app.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ from typing import Optional
4
+
5
+ import av
6
+ import torch
7
+ import streamlit as st
8
+ from streamlit_webrtc import webrtc_streamer, VideoProcessorBase, RTCConfiguration
9
+
10
+ try:
11
+ from ultralytics import YOLO
12
+ except Exception as e:
13
+ st.error(f"Ultralytics import failed: {e}")
14
+ raise
15
+
16
+
17
+ st.set_page_config(page_title="YOLO11 Webcam", layout="wide")
18
+ st.title("YOLO11 Webcam Demo")
19
+ st.caption("Live object detection with YOLO11 using your webcam. Use the sidebar to configure the model and thresholds.")
20
+
21
+
22
+ def _resolve_device(device: str) -> str:
23
+ """Map UI device option to a valid torch/Ultralytics device string."""
24
+ d = (device or "").lower().strip()
25
+ if d in {"cpu", "cuda", "mps", "xpu", "dml"}:
26
+ return d
27
+ if d == "auto":
28
+ if torch.cuda.is_available():
29
+ return "cuda"
30
+ # Apple MPS (macOS). Kept for completeness even if not typical on Windows.
31
+ if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
32
+ return "mps"
33
+ # Windows DirectML (requires torch-directml)
34
+ try:
35
+ import torch_directml # noqa: F401
36
+ return "dml"
37
+ except Exception:
38
+ pass
39
+ return "cpu"
40
+ # Fallback to CPU for any unknown value
41
+ return "cpu"
42
+
43
+
44
+ @st.cache_resource(show_spinner=True)
45
+ def load_model(model_source: str, device: str = "auto"):
46
+ """
47
+ Load an Ultralytics model from a local path, built-in alias, or Hugging Face Hub path.
48
+ Examples for model_source:
49
+ - "yolo11n.pt" (auto-downloads if available)
50
+ - "C:/path/to/your_model.pt"
51
+ - "hf://Ultralytics/YOLO11/yolo11n.pt" (HF Hub file)
52
+ """
53
+ # Resolve device (maps 'auto' to an actual device)
54
+ resolved_device = _resolve_device(device)
55
+
56
+ # Gentle hint for common mistake: loading a multi-model container instead of a single YOLO weight
57
+ try:
58
+ base_name = os.path.basename(model_source)
59
+ if base_name.lower().startswith("models_multi"):
60
+ st.info("Seçilen .pt birden fazla ağırlık içeren bir paket olabilir. Lütfen tek bir YOLO ağırlık dosyası seçin (âr. yolo11n.pt).")
61
+ except Exception:
62
+ pass
63
+
64
+ # 1) Kaynağı yerel dosyaya indir/çâz ve YOLO nesnesini oluştur
65
+ def _create_yolo(path_or_alias: str):
66
+ if path_or_alias.startswith("hf://"):
67
+ try:
68
+ from huggingface_hub import hf_hub_download
69
+ except Exception:
70
+ st.error("huggingface_hub yüklü değil. Yükleyin veya yerel/yerleşik model kullanın.")
71
+ raise
72
+ path = path_or_alias.replace("hf://", "", 1)
73
+ if "/" not in path:
74
+ raise ValueError("hf:// iΓ§in hf://<repo_id>/<filename> biΓ§imini kullanΔ±n")
75
+ repo_id, filename = path.split("/", 1)
76
+ st.info(f"{repo_id} deposundan {filename} indiriliyor…")
77
+ local_path = hf_hub_download(repo_id=repo_id, filename=filename, token=os.getenv("HF_TOKEN"))
78
+ return YOLO(local_path)
79
+ else:
80
+ return YOLO(path_or_alias)
81
+
82
+ # Γ–nce modeli yΓΌklemeyi deneyin (hata ==> dosya/format sorunu)
83
+ try:
84
+ model = _create_yolo(model_source)
85
+ except Exception as e:
86
+ st.error(
87
+ "Model dosyası yüklenemedi. Bu dosya geçerli bir YOLO ağırlığı olmayabilir (ârn. eğitim checkpoint'i veya paketlenmiş container).\n"
88
+ f"Detay: {e}"
89
+ )
90
+ raise
91
+
92
+ # 2) Sonra cihaza taşımayΔ± deneyin (hata ==> CUDA/MPS taşınamΔ±yor β†’ CPU'ya düş)
93
+ try:
94
+ return model.to(resolved_device)
95
+ except Exception as e:
96
+ st.warning(f"{resolved_device} cihaza taşınamadı, CPU'ya düşülüyor. Detay: {e}")
97
+ try:
98
+ return model.to("cpu")
99
+ except Exception:
100
+ # CPU'ya taşınma da başarısızsa, ham modeli dândür (son çare)
101
+ return model
102
+
103
+
104
+ class YOLOProcessor(VideoProcessorBase):
105
+ def __init__(self, model: YOLO, conf: float, iou: float):
106
+ self.model = model
107
+ self.conf = conf
108
+ self.iou = iou
109
+
110
+ def recv(self, frame: av.VideoFrame) -> av.VideoFrame:
111
+ img = frame.to_ndarray(format="bgr24")
112
+ results = self.model.predict(img, conf=self.conf, iou=self.iou, verbose=False)
113
+ plotted = results[0].plot()
114
+ return av.VideoFrame.from_ndarray(plotted, format="bgr24")
115
+
116
+
117
+ with st.sidebar:
118
+ st.header("Ayarlar")
119
+ default_model = "yolo11n.pt" # Ultralytics dağıtımından otomatik indirilmeye çalışılır
120
+ model_path = st.text_input("Model yolu veya alias", value=default_model, help="Yerel .pt yolu, yerleşik alias (ârn. yolo11n.pt) veya hf://Ultralytics/YOLO11/yolo11n.pt")
121
+ device = st.selectbox("Cihaz", options=["auto", "cpu", "cuda", "dml"], index=0)
122
+ conf = st.slider("Confidence", min_value=0.1, max_value=0.9, value=0.25, step=0.05)
123
+ iou = st.slider("IoU", min_value=0.1, max_value=0.9, value=0.45, step=0.05)
124
+ load_btn = st.button("Modeli YΓΌkle")
125
+
126
+ # Ortam durumu (Torch/CUDA)
127
+ try:
128
+ tv = torch.__version__
129
+ cv = getattr(torch.version, "cuda", None)
130
+ ca = torch.cuda.is_available()
131
+ # Detect DirectML
132
+ has_dml = False
133
+ try:
134
+ import torch_directml # noqa: F401
135
+ has_dml = True
136
+ except Exception:
137
+ has_dml = False
138
+ dml_txt = " β€’ DirectML: HazΔ±r" if has_dml else ""
139
+ st.caption(f"Torch {tv} β€’ CUDA: {cv or 'yok'} β€’ GPU etkin (CUDA): {'Evet' if ca else 'HayΔ±r'}{dml_txt}")
140
+ except Exception:
141
+ pass
142
+
143
+
144
+ st.session_state.setdefault("model", None)
145
+
146
+
147
+ if load_btn:
148
+ try:
149
+ st.session_state.model = load_model(model_path, device=device)
150
+ names = getattr(st.session_state.model, "names", None)
151
+ if isinstance(names, dict):
152
+ st.success(f"Model yΓΌklendi. SΔ±nΔ±flar: {len(names)}")
153
+ else:
154
+ st.success("Model yΓΌklendi.")
155
+ try:
156
+ active_device = next((p.device.type for p in st.session_state.model.parameters()), "unknown")
157
+ st.info(f"Aktif cihaz: {active_device}")
158
+ except Exception:
159
+ pass
160
+ except Exception as e:
161
+ st.exception(e)
162
+
163
+
164
+ rtc_config = RTCConfiguration({
165
+ "iceServers": [{"urls": ["stun:stun.l.google.com:19302"]}],
166
+ })
167
+
168
+
169
+ col1, col2 = st.columns([2, 1])
170
+ with col1:
171
+ st.subheader("Webcam")
172
+ if st.session_state.get("model") is None:
173
+ st.info("Γ–nce soldan bir model yΓΌkleyin.")
174
+ else:
175
+ # Capture current values to avoid session_state race during worker creation
176
+ _model = st.session_state.get("model")
177
+ _conf = float(conf)
178
+ _iou = float(iou)
179
+
180
+ def video_processor_factory(model=_model, conf_val=_conf, iou_val=_iou):
181
+ return YOLOProcessor(model, conf=conf_val, iou=iou_val)
182
+
183
+ webrtc_streamer(
184
+ key="yolo11-webcam",
185
+ video_processor_factory=video_processor_factory,
186
+ rtc_configuration=rtc_config,
187
+ media_stream_constraints={"video": True, "audio": False},
188
+ )
189
+
190
+ with col2:
191
+ st.subheader("Δ°puΓ§larΔ±")
192
+ st.markdown(
193
+ """
194
+ - Model alanına şunlardan birini girebilirsiniz:
195
+ - Yerleşik: `yolo11n.pt` (veya sizde olan başka bir .pt)
196
+ - Yerel dosya: `C:/yolov11/weights/custom.pt`
197
+ - HF Hub: `hf://Ultralytics/YOLO11/yolo11n.pt`
198
+ - Hugging Face âzel/korumalı dosyalar için `HF_TOKEN` ortam değişkenini ayarlayabilirsiniz.
199
+ - GPU (CUDA) yoksa cihazΔ± `cpu` bΔ±rakabilirsiniz.
200
+ - Stream durmuyorsa tarayΔ±cΔ± izinlerini kontrol edin ve sayfayΔ± yenileyin.
201
+ """
202
+ )
tools/pt_bundle.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ PT bundler: Bundle multiple .pt files into a single archive without modifying originals.
4
+
5
+ Supports two formats:
6
+ 1) ZIP archive (recommended) – exact bytes of each .pt preserved.
7
+ 2) PT container – a single .pt (pickle) file containing a dict {relative_path: bytes}.
8
+
9
+ CLI examples (PowerShell):
10
+ # Create ZIP bundle from current repo
11
+ python tools/pt_bundle.py zip --source . --out models_bundle.zip
12
+
13
+ # Create PT container bundle
14
+ python tools/pt_bundle.py pt --source . --out models_multi.pt
15
+
16
+ # List contents
17
+ python tools/pt_bundle.py list --bundle models_bundle.zip
18
+ python tools/pt_bundle.py list --bundle models_multi.pt
19
+
20
+ # Extract a single model from bundle to a path
21
+ python tools/pt_bundle.py extract --bundle models_multi.pt --member path/to/model.pt --out C:/tmp/model.pt
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import argparse
27
+ import io
28
+ import os
29
+ import sys
30
+ from pathlib import Path
31
+ from typing import Iterable, List
32
+
33
+ try:
34
+ import torch # Only needed for PT container
35
+ except Exception: # pragma: no cover - optional for ZIP-only usage
36
+ torch = None # type: ignore
37
+
38
+ import zipfile
39
+
40
+
41
+ def find_pt_files(source: Path, include: Iterable[str] | None = None, exclude: Iterable[str] | None = None) -> List[Path]:
42
+ include = list(include or ["*.pt"]) # default include all .pt
43
+ exclude = list(exclude or [])
44
+ files: List[Path] = []
45
+ for p in source.rglob("*.pt"):
46
+ rel = p.relative_to(source)
47
+ rel_str = str(rel).replace("\\", "/")
48
+ if include and not any(Path(rel_str).match(pat) for pat in include):
49
+ continue
50
+ if exclude and any(Path(rel_str).match(pat) for pat in exclude):
51
+ continue
52
+ files.append(p)
53
+ return files
54
+
55
+
56
+ def create_zip_bundle(source: Path, out_path: Path, includes: Iterable[str] | None = None, excludes: Iterable[str] | None = None) -> int:
57
+ files = find_pt_files(source, includes, excludes)
58
+ out_path.parent.mkdir(parents=True, exist_ok=True)
59
+ with zipfile.ZipFile(out_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
60
+ for f in files:
61
+ zf.write(f, f.relative_to(source))
62
+ return len(files)
63
+
64
+
65
+ def create_pt_container(source: Path, out_path: Path, includes: Iterable[str] | None = None, excludes: Iterable[str] | None = None) -> int:
66
+ if torch is None:
67
+ raise RuntimeError("torch is required for PT container mode. Install torch and retry.")
68
+ files = find_pt_files(source, includes, excludes)
69
+ payload = {}
70
+ for f in files:
71
+ rel = str(f.relative_to(source)).replace("\\", "/")
72
+ with open(f, "rb") as fh:
73
+ payload[rel] = fh.read() # store exact bytes (no mutation)
74
+ out_path.parent.mkdir(parents=True, exist_ok=True)
75
+ torch.save(payload, out_path)
76
+ return len(files)
77
+
78
+
79
+ def list_bundle(bundle: Path) -> List[str]:
80
+ if bundle.suffix.lower() == ".zip":
81
+ with zipfile.ZipFile(bundle, "r") as zf:
82
+ return [i.filename for i in zf.infolist() if not i.is_dir()]
83
+ else:
84
+ if torch is None:
85
+ raise RuntimeError("torch is required to list PT container contents.")
86
+ data = torch.load(bundle, map_location="cpu")
87
+ if isinstance(data, dict):
88
+ return sorted(map(str, data.keys()))
89
+ raise ValueError("Unsupported PT container format: expected dict mapping.")
90
+
91
+
92
+ def extract_member(bundle: Path, member: str, out_path: Path) -> None:
93
+ if bundle.suffix.lower() == ".zip":
94
+ with zipfile.ZipFile(bundle, "r") as zf:
95
+ with zf.open(member, "r") as fh, open(out_path, "wb") as out:
96
+ out.write(fh.read())
97
+ else:
98
+ if torch is None:
99
+ raise RuntimeError("torch is required to extract from PT container.")
100
+ data = torch.load(bundle, map_location="cpu")
101
+ if not isinstance(data, dict):
102
+ raise ValueError("Unsupported PT container format: expected dict mapping.")
103
+ if member not in data:
104
+ raise FileNotFoundError(f"member not found in container: {member}")
105
+ out_path.parent.mkdir(parents=True, exist_ok=True)
106
+ with open(out_path, "wb") as fh:
107
+ fh.write(data[member])
108
+
109
+
110
+ def main(argv: List[str] | None = None) -> int:
111
+ parser = argparse.ArgumentParser(description="Bundle multiple .pt files without modifying originals.")
112
+ sub = parser.add_subparsers(dest="cmd", required=True)
113
+
114
+ p_zip = sub.add_parser("zip", help="Create a ZIP archive of .pt files.")
115
+ p_zip.add_argument("--source", default=".", help="Root directory to scan for .pt files.")
116
+ p_zip.add_argument("--out", required=True, help="Output ZIP path.")
117
+ p_zip.add_argument("--include", nargs="*", default=["*.pt"], help="Glob patterns to include.")
118
+ p_zip.add_argument("--exclude", nargs="*", default=[], help="Glob patterns to exclude.")
119
+
120
+ p_pt = sub.add_parser("pt", help="Create a single .pt container (dict of bytes).")
121
+ p_pt.add_argument("--source", default=".", help="Root directory to scan for .pt files.")
122
+ p_pt.add_argument("--out", required=True, help="Output PT path (e.g., models_multi.pt).")
123
+ p_pt.add_argument("--include", nargs="*", default=["*.pt"], help="Glob patterns to include.")
124
+ p_pt.add_argument("--exclude", nargs="*", default=[], help="Glob patterns to exclude.")
125
+
126
+ p_list = sub.add_parser("list", help="List contents of a bundle (ZIP or PT container).")
127
+ p_list.add_argument("--bundle", required=True, help="Path to models_bundle.zip or models_multi.pt.")
128
+
129
+ p_ext = sub.add_parser("extract", help="Extract a single member from the bundle.")
130
+ p_ext.add_argument("--bundle", required=True, help="Bundle path (ZIP or PT container).")
131
+ p_ext.add_argument("--member", required=True, help="Member path inside the bundle.")
132
+ p_ext.add_argument("--out", required=True, help="Destination file path to write.")
133
+
134
+ args = parser.parse_args(argv)
135
+
136
+ if args.cmd == "zip":
137
+ count = create_zip_bundle(Path(args.source), Path(args.out), args.include, args.exclude)
138
+ print(f"ZIP bundle written: {args.out} ({count} files)")
139
+ return 0
140
+ if args.cmd == "pt":
141
+ count = create_pt_container(Path(args.source), Path(args.out), args.include, args.exclude)
142
+ print(f"PT container written: {args.out} ({count} files)")
143
+ return 0
144
+ if args.cmd == "list":
145
+ items = list_bundle(Path(args.bundle))
146
+ for it in items:
147
+ print(it)
148
+ return 0
149
+ if args.cmd == "extract":
150
+ extract_member(Path(args.bundle), args.member, Path(args.out))
151
+ print(f"Extracted {args.member} -> {args.out}")
152
+ return 0
153
+
154
+ parser.print_help()
155
+ return 1
156
+
157
+
158
+ if __name__ == "__main__":
159
+ raise SystemExit(main())