ultralytics 8.3.126__py3-none-any.whl → 8.3.128__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tests/test_cuda.py CHANGED
@@ -71,8 +71,13 @@ def test_export_engine_matrix(task, dynamic, int8, half, batch):
71
71
  @pytest.mark.skipif(not DEVICES, reason="No CUDA devices available")
72
72
  def test_train():
73
73
  """Test model training on a minimal dataset using available CUDA devices."""
74
- device = DEVICES if len(DEVICES) > 1 else DEVICES[0]
75
- YOLO(MODEL).train(data="coco8.yaml", imgsz=64, epochs=1, device=device) # requires imgsz>=64
74
+ import os
75
+
76
+ device = tuple(DEVICES) if len(DEVICES) > 1 else DEVICES[0]
77
+ results = YOLO(MODEL).train(data="coco8.yaml", imgsz=64, epochs=1, device=device) # requires imgsz>=64
78
+ visible = eval(os.environ["CUDA_VISIBLE_DEVICES"])
79
+ assert visible == device, f"Passed GPUs '{device}', but used GPUs '{visible}'"
80
+ assert results is (None if len(DEVICES) > 1 else not None) # DDP returns None, single-GPU returns metrics
76
81
 
77
82
 
78
83
  @pytest.mark.slow
tests/test_python.py CHANGED
@@ -188,11 +188,11 @@ def test_track_stream():
188
188
  model.track(video_url, imgsz=160, tracker="bytetrack.yaml")
189
189
  model.track(video_url, imgsz=160, tracker="botsort.yaml", save_frames=True) # test frame saving also
190
190
 
191
- # Test Global Motion Compensation (GMC) methods
192
- for gmc in "orb", "sift", "ecc":
191
+ # Test Global Motion Compensation (GMC) methods and ReID
192
+ for gmc, reidm in zip(["orb", "sift", "ecc"], ["auto", "auto", "yolo11n-cls.pt"]):
193
193
  default_args = YAML.load(ROOT / "cfg/trackers/botsort.yaml")
194
194
  custom_yaml = TMP / f"botsort-{gmc}.yaml"
195
- YAML.save(custom_yaml, {**default_args, "gmc_method": gmc})
195
+ YAML.save(custom_yaml, {**default_args, "gmc_method": gmc, "with_reid": True, "model": reidm})
196
196
  model.track(video_url, imgsz=160, tracker=custom_yaml)
197
197
 
198
198
 
tests/test_solutions.py CHANGED
@@ -174,3 +174,14 @@ def test_solution(name, solution_class, needs_frame_count, video, kwargs):
174
174
  video_path=str(TMP / video),
175
175
  needs_frame_count=needs_frame_count,
176
176
  )
177
+
178
+
179
+ @pytest.mark.slow
180
+ @pytest.mark.skipif(checks.IS_PYTHON_3_8, reason="Disabled due to unsupported CLIP dependencies.")
181
+ @pytest.mark.skipif(IS_RASPBERRYPI, reason="Disabled due to slow performance on Raspberry Pi.")
182
+ def test_similarity_search():
183
+ """Test similarity search solution."""
184
+ from ultralytics import solutions
185
+
186
+ searcher = solutions.VisualAISearch()
187
+ _ = searcher("a dog sitting on a bench") # Returns the results in format "- img name | similarity score"
ultralytics/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
- __version__ = "8.3.126"
3
+ __version__ = "8.3.128"
4
4
 
5
5
  import os
6
6
 
@@ -82,6 +82,7 @@ from ultralytics.utils import (
82
82
  ARM64,
83
83
  DEFAULT_CFG,
84
84
  IS_COLAB,
85
+ IS_JETSON,
85
86
  LINUX,
86
87
  LOGGER,
87
88
  MACOS,
@@ -682,6 +683,7 @@ class Exporter:
682
683
  @try_export
683
684
  def export_paddle(self, prefix=colorstr("PaddlePaddle:")):
684
685
  """YOLO Paddle export."""
686
+ assert not IS_JETSON, "Jetson Paddle exports not supported yet"
685
687
  check_requirements(("paddlepaddle-gpu" if torch.cuda.is_available() else "paddlepaddle>=3.0.0", "x2paddle"))
686
688
  import x2paddle # noqa
687
689
  from x2paddle.convert import pytorch2paddle # noqa
@@ -105,7 +105,8 @@ class BaseTrainer:
105
105
  self.args = get_cfg(cfg, overrides)
106
106
  self.check_resume(overrides)
107
107
  self.device = select_device(self.args.device, self.args.batch)
108
- self.args.device = str(self.device) # ensure -1 is updated to selected CUDA device
108
+ # update "-1" devices so post-training val does not repeat search
109
+ self.args.device = os.getenv("CUDA_VISIBLE_DEVICES") if "cuda" in str(self.device) else str(self.device)
109
110
  self.validator = None
110
111
  self.metrics = None
111
112
  self.plots = {}
@@ -82,11 +82,9 @@ class DetectionPredictor(BasePredictor):
82
82
 
83
83
  def get_obj_feats(self, feat_maps, idxs):
84
84
  """Extract object features from the feature maps."""
85
- from math import gcd
86
-
87
85
  import torch
88
86
 
89
- s = gcd(*[x.shape[1] for x in feat_maps]) # find smallest vector length
87
+ s = min([x.shape[1] for x in feat_maps]) # find smallest vector length
90
88
  obj_feats = torch.cat(
91
89
  [x.permute(0, 2, 3, 1).reshape(x.shape[0], -1, s, x.shape[1] // s).mean(dim=-1) for x in feat_maps], dim=1
92
90
  ) # mean reduce all vectors to same length
@@ -290,8 +290,8 @@ class AutoBackend(nn.Module):
290
290
  elif engine:
291
291
  LOGGER.info(f"Loading {w} for TensorRT inference...")
292
292
 
293
- if IS_JETSON and check_version(PYTHON_VERSION, "<=3.8.0"):
294
- # fix error: `np.bool` was a deprecated alias for the builtin `bool` for JetPack 4 with Python <= 3.8.0
293
+ if IS_JETSON and check_version(PYTHON_VERSION, "<=3.8.10"):
294
+ # fix error: `np.bool` was a deprecated alias for the builtin `bool` for JetPack 4 and JetPack 5 with Python <= 3.8.10
295
295
  check_requirements("numpy==1.23.5")
296
296
 
297
297
  try: # https://developer.nvidia.com/nvidia-tensorrt-download
@@ -12,6 +12,7 @@ from .parking_management import ParkingManagement, ParkingPtsSelection
12
12
  from .queue_management import QueueManager
13
13
  from .region_counter import RegionCounter
14
14
  from .security_alarm import SecurityAlarm
15
+ from .similarity_search import SearchApp, VisualAISearch
15
16
  from .speed_estimation import SpeedEstimator
16
17
  from .streamlit_inference import Inference
17
18
  from .trackzone import TrackZone
@@ -35,4 +36,6 @@ __all__ = (
35
36
  "Analytics",
36
37
  "Inference",
37
38
  "TrackZone",
39
+ "SearchApp",
40
+ "VisualAISearch",
38
41
  )
@@ -48,6 +48,7 @@ class SolutionConfig:
48
48
  half (bool): Whether to use FP16 precision (requires a supported CUDA device).
49
49
  tracker (str): Path to tracking configuration YAML file (e.g., 'botsort.yaml').
50
50
  verbose (bool): Enable verbose logging output for debugging or diagnostics.
51
+ data (str): Path to image directory used for similarity search.
51
52
 
52
53
  Methods:
53
54
  update: Update the configuration with user-defined keyword arguments and raise error on invalid keys.
@@ -91,6 +92,7 @@ class SolutionConfig:
91
92
  half: bool = False
92
93
  tracker: str = "botsort.yaml"
93
94
  verbose: bool = True
95
+ data: str = "images"
94
96
 
95
97
  def update(self, **kwargs):
96
98
  """Update configuration parameters with new values provided as keyword arguments."""
@@ -0,0 +1,172 @@
1
+ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
+
3
+ import os
4
+ from pathlib import Path
5
+
6
+ import numpy as np
7
+ import torch
8
+ from PIL import Image
9
+
10
+ from ultralytics.data.utils import IMG_FORMATS
11
+ from ultralytics.solutions.solutions import BaseSolution
12
+ from ultralytics.utils.checks import check_requirements
13
+ from ultralytics.utils.torch_utils import select_device
14
+
15
+ os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # Avoid OpenMP conflict on some systems
16
+
17
+
18
+ class VisualAISearch(BaseSolution):
19
+ """
20
+ VisualAISearch leverages OpenCLIP to generate high-quality image and text embeddings, aligning them in a shared
21
+ semantic space. It then uses FAISS to perform fast and scalable similarity-based retrieval, allowing users to search
22
+ large collections of images using natural language queries with high accuracy and speed.
23
+
24
+ Attributes:
25
+ data (str): Directory containing images.
26
+ device (str): Computation device, e.g., 'cpu' or 'cuda'.
27
+ """
28
+
29
+ def __init__(self, **kwargs):
30
+ """Initializes the VisualAISearch class with the FAISS index file and CLIP model."""
31
+ super().__init__(**kwargs)
32
+ check_requirements(["git+https://github.com/ultralytics/CLIP.git", "faiss-cpu"])
33
+ import clip
34
+ import faiss
35
+
36
+ self.faiss = faiss
37
+ self.clip = clip
38
+
39
+ self.faiss_index = "faiss.index"
40
+ self.data_path_npy = "paths.npy"
41
+ self.model_name = "ViT-B/32"
42
+ self.data_dir = Path(self.CFG["data"])
43
+ self.device = select_device(self.CFG["device"])
44
+
45
+ if not self.data_dir.exists():
46
+ from ultralytics.utils import ASSETS_URL
47
+
48
+ self.LOGGER.warning(f"{self.data_dir} not found. Downloading images.zip from {ASSETS_URL}/images.zip")
49
+ from ultralytics.utils.downloads import safe_download
50
+
51
+ safe_download(url=f"{ASSETS_URL}/images.zip", unzip=True, retry=3)
52
+ self.data_dir = Path("images")
53
+
54
+ self.model, self.preprocess = clip.load(self.model_name, device=self.device)
55
+
56
+ self.index = None
57
+ self.image_paths = []
58
+
59
+ self.load_or_build_index()
60
+
61
+ def extract_image_feature(self, path):
62
+ """Extract CLIP image embedding."""
63
+ image = Image.open(path)
64
+ tensor = self.preprocess(image).unsqueeze(0).to(self.device)
65
+ with torch.no_grad():
66
+ return self.model.encode_image(tensor).cpu().numpy()
67
+
68
+ def extract_text_feature(self, text):
69
+ """Extract CLIP text embedding."""
70
+ tokens = self.clip.tokenize([text]).to(self.device)
71
+ with torch.no_grad():
72
+ return self.model.encode_text(tokens).cpu().numpy()
73
+
74
+ def load_or_build_index(self):
75
+ """Loads FAISS index or builds a new one from image features."""
76
+ # Check if the FAISS index and corresponding image paths already exist
77
+ if Path(self.faiss_index).exists() and Path(self.data_path_npy).exists():
78
+ self.LOGGER.info("Loading existing FAISS index...")
79
+ self.index = self.faiss.read_index(self.faiss_index) # Load the FAISS index from disk
80
+ self.image_paths = np.load(self.data_path_npy) # Load the saved image path list
81
+ return # Exit the function as the index is successfully loaded
82
+
83
+ # If the index doesn't exist, start building it from scratch
84
+ self.LOGGER.info("Building FAISS index from images...")
85
+ vectors = [] # List to store feature vectors of images
86
+
87
+ # Iterate over all image files in the data directory
88
+ for file in self.data_dir.iterdir():
89
+ # Skip files that are not valid image formats
90
+ if file.suffix.lower().lstrip(".") not in IMG_FORMATS:
91
+ continue
92
+ try:
93
+ # Extract feature vector for the image and add to the list
94
+ vectors.append(self.extract_image_feature(file))
95
+ self.image_paths.append(file.name) # Store the corresponding image name
96
+ except Exception as e:
97
+ self.LOGGER.warning(f"Skipping {file.name}: {e}")
98
+
99
+ # If no vectors were successfully created, raise an error
100
+ if not vectors:
101
+ raise RuntimeError("No image embeddings could be generated.")
102
+
103
+ vectors = np.vstack(vectors).astype("float32") # Stack all vectors into a NumPy array and convert to float32
104
+ self.faiss.normalize_L2(vectors) # Normalize vectors to unit length for cosine similarity
105
+
106
+ self.index = self.faiss.IndexFlatIP(vectors.shape[1]) # Create a new FAISS index using inner product
107
+ self.index.add(vectors) # Add the normalized vectors to the FAISS index
108
+ self.faiss.write_index(self.index, self.faiss_index) # Save the newly built FAISS index to disk
109
+ np.save(self.data_path_npy, np.array(self.image_paths)) # Save the list of image paths to disk
110
+
111
+ self.LOGGER.info(f"Indexed {len(self.image_paths)} images.")
112
+
113
+ def search(self, query, k=30, similarity_thresh=0.1):
114
+ """Returns top-k semantically similar images to the given query."""
115
+ text_feat = self.extract_text_feature(query).astype("float32")
116
+ self.faiss.normalize_L2(text_feat)
117
+
118
+ D, index = self.index.search(text_feat, k)
119
+ results = [
120
+ (self.image_paths[i], float(D[0][idx])) for idx, i in enumerate(index[0]) if D[0][idx] >= similarity_thresh
121
+ ]
122
+ results.sort(key=lambda x: x[1], reverse=True)
123
+
124
+ self.LOGGER.info("\nRanked Results:")
125
+ for name, score in results:
126
+ self.LOGGER.info(f" - {name} | Similarity: {score:.4f}")
127
+
128
+ return [r[0] for r in results]
129
+
130
+ def __call__(self, query):
131
+ """Direct call for search function."""
132
+ return self.search(query)
133
+
134
+
135
+ class SearchApp:
136
+ """
137
+ A Flask-based web interface powers the semantic image search experience, enabling users to input natural language
138
+ queries and instantly view the most relevant images retrieved from the indexed database—all through a clean,
139
+ responsive, and easily customizable frontend.
140
+
141
+ Args:
142
+ data (str): Path to images to index and search.
143
+ device (str): Device to run inference on (e.g. 'cpu', 'cuda').
144
+ """
145
+
146
+ def __init__(self, data="images", device=None):
147
+ """Initialization of the VisualAISearch class for performing semantic image search."""
148
+ check_requirements("flask")
149
+ from flask import Flask, render_template, request
150
+
151
+ self.render_template = render_template
152
+ self.request = request
153
+ self.searcher = VisualAISearch(data=data, device=device)
154
+ self.app = Flask(
155
+ __name__,
156
+ template_folder="templates",
157
+ static_folder=Path(data).resolve(), # Absolute path to serve images
158
+ static_url_path="/images", # URL prefix for images
159
+ )
160
+ self.app.add_url_rule("/", view_func=self.index, methods=["GET", "POST"])
161
+
162
+ def index(self):
163
+ """Function to process the user query and display output."""
164
+ results = []
165
+ if self.request.method == "POST":
166
+ query = self.request.form.get("query", "").strip()
167
+ results = self.searcher(query)
168
+ return self.render_template("similarity-search.html", results=results)
169
+
170
+ def run(self, debug=False):
171
+ """Runs the Flask web app."""
172
+ self.app.run(debug=debug)
@@ -54,55 +54,56 @@ class BaseSolution:
54
54
  is_cli (bool): Enables CLI mode if set to True.
55
55
  **kwargs (Any): Additional configuration parameters that override defaults.
56
56
  """
57
- check_requirements("shapely>=2.0.0")
58
- from shapely.geometry import LineString, Point, Polygon
59
- from shapely.prepared import prep
60
-
61
- self.LineString = LineString
62
- self.Polygon = Polygon
63
- self.Point = Point
64
- self.prep = prep
65
- self.annotator = None # Initialize annotator
66
- self.tracks = None
67
- self.track_data = None
68
- self.boxes = []
69
- self.clss = []
70
- self.track_ids = []
71
- self.track_line = None
72
- self.masks = None
73
- self.r_s = None
74
-
75
- self.LOGGER = LOGGER # Store logger object to be used in multiple solution classes
76
57
  self.CFG = vars(SolutionConfig().update(**kwargs))
77
- self.LOGGER.info(f"Ultralytics Solutions: {self.CFG}")
78
-
79
- self.region = self.CFG["region"] # Store region data for other classes usage
80
- self.line_width = self.CFG["line_width"]
81
-
82
- # Load Model and store additional information (classes, show_conf, show_label)
83
- if self.CFG["model"] is None:
84
- self.CFG["model"] = "yolo11n.pt"
85
- self.model = YOLO(self.CFG["model"])
86
- self.names = self.model.names
87
- self.classes = self.CFG["classes"]
88
- self.show_conf = self.CFG["show_conf"]
89
- self.show_labels = self.CFG["show_labels"]
90
-
91
- self.track_add_args = { # Tracker additional arguments for advance configuration
92
- k: self.CFG[k] for k in ["iou", "conf", "device", "max_det", "half", "tracker", "device", "verbose"]
93
- } # verbose must be passed to track method; setting it False in YOLO still logs the track information.
94
-
95
- if is_cli and self.CFG["source"] is None:
96
- d_s = "solutions_ci_demo.mp4" if "-pose" not in self.CFG["model"] else "solution_ci_pose_demo.mp4"
97
- self.LOGGER.warning(f"source not provided. using default source {ASSETS_URL}/{d_s}")
98
- from ultralytics.utils.downloads import safe_download
99
-
100
- safe_download(f"{ASSETS_URL}/{d_s}") # download source from ultralytics assets
101
- self.CFG["source"] = d_s # set default source
102
-
103
- # Initialize environment and region setup
104
- self.env_check = check_imshow(warn=True)
105
- self.track_history = defaultdict(list)
58
+ self.LOGGER = LOGGER # Store logger object to be used in multiple solution classes
59
+
60
+ if self.__class__.__name__ != "VisualAISearch":
61
+ check_requirements("shapely>=2.0.0")
62
+ from shapely.geometry import LineString, Point, Polygon
63
+ from shapely.prepared import prep
64
+
65
+ self.LineString = LineString
66
+ self.Polygon = Polygon
67
+ self.Point = Point
68
+ self.prep = prep
69
+ self.annotator = None # Initialize annotator
70
+ self.tracks = None
71
+ self.track_data = None
72
+ self.boxes = []
73
+ self.clss = []
74
+ self.track_ids = []
75
+ self.track_line = None
76
+ self.masks = None
77
+ self.r_s = None
78
+
79
+ self.LOGGER.info(f"Ultralytics Solutions: ✅ {self.CFG}")
80
+ self.region = self.CFG["region"] # Store region data for other classes usage
81
+ self.line_width = self.CFG["line_width"]
82
+
83
+ # Load Model and store additional information (classes, show_conf, show_label)
84
+ if self.CFG["model"] is None:
85
+ self.CFG["model"] = "yolo11n.pt"
86
+ self.model = YOLO(self.CFG["model"])
87
+ self.names = self.model.names
88
+ self.classes = self.CFG["classes"]
89
+ self.show_conf = self.CFG["show_conf"]
90
+ self.show_labels = self.CFG["show_labels"]
91
+
92
+ self.track_add_args = { # Tracker additional arguments for advance configuration
93
+ k: self.CFG[k] for k in ["iou", "conf", "device", "max_det", "half", "tracker", "device", "verbose"]
94
+ } # verbose must be passed to track method; setting it False in YOLO still logs the track information.
95
+
96
+ if is_cli and self.CFG["source"] is None:
97
+ d_s = "solutions_ci_demo.mp4" if "-pose" not in self.CFG["model"] else "solution_ci_pose_demo.mp4"
98
+ self.LOGGER.warning(f"source not provided. using default source {ASSETS_URL}/{d_s}")
99
+ from ultralytics.utils.downloads import safe_download
100
+
101
+ safe_download(f"{ASSETS_URL}/{d_s}") # download source from ultralytics assets
102
+ self.CFG["source"] = d_s # set default source
103
+
104
+ # Initialize environment and region setup
105
+ self.env_check = check_imshow(warn=True)
106
+ self.track_history = defaultdict(list)
106
107
 
107
108
  def adjust_box_label(self, cls, conf, track_id=None):
108
109
  """
@@ -0,0 +1,160 @@
1
+ <!-- Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license -->
2
+
3
+ <!--Similarity search webpage-->
4
+ <!doctype html>
5
+ <html lang="en">
6
+ <head>
7
+ <meta charset="UTF-8" />
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
9
+ <title>Semantic Image Search</title>
10
+ <link
11
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap"
12
+ rel="stylesheet"
13
+ />
14
+ <style>
15
+ body {
16
+ background: linear-gradient(135deg, #f0f4ff, #f9fbff);
17
+ font-family: "Inter", sans-serif;
18
+ color: #111e68;
19
+ padding: 2rem;
20
+ margin: 0;
21
+ min-height: 100vh;
22
+ }
23
+
24
+ h1 {
25
+ text-align: center;
26
+ margin-bottom: 2rem;
27
+ font-size: 2.5rem;
28
+ font-weight: 600;
29
+ }
30
+
31
+ form {
32
+ display: flex;
33
+ flex-wrap: wrap;
34
+ justify-content: center;
35
+ align-items: center;
36
+ gap: 1rem;
37
+ margin-bottom: 3rem;
38
+ animation: fadeIn 1s ease-in-out;
39
+ }
40
+
41
+ input[type="text"] {
42
+ width: 300px;
43
+ padding: 0.75rem 1rem;
44
+ font-size: 1rem;
45
+ border-radius: 10px;
46
+ border: 1px solid #ccc;
47
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
48
+ transition: box-shadow 0.3s ease;
49
+ }
50
+
51
+ input[type="text"]:focus {
52
+ outline: none;
53
+ box-shadow: 0 0 0 3px rgba(17, 30, 104, 0.2);
54
+ }
55
+
56
+ button {
57
+ background-color: #111e68;
58
+ color: white;
59
+ font-weight: 600;
60
+ font-size: 1rem;
61
+ padding: 0.75rem 1.5rem;
62
+ border-radius: 10px;
63
+ border: none;
64
+ cursor: pointer;
65
+ transition:
66
+ background-color 0.3s ease,
67
+ transform 0.2s ease;
68
+ }
69
+
70
+ button:hover {
71
+ background-color: #1f2e9f;
72
+ transform: translateY(-2px);
73
+ }
74
+
75
+ .grid {
76
+ display: grid;
77
+ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
78
+ gap: 1.5rem;
79
+ max-width: 1600px;
80
+ margin: auto;
81
+ animation: fadeInUp 1s ease-in-out;
82
+ }
83
+
84
+ .card {
85
+ background: white;
86
+ border-radius: 16px;
87
+ overflow: hidden;
88
+ box-shadow: 0 6px 14px rgba(0, 0, 0, 0.08);
89
+ transition:
90
+ transform 0.3s ease,
91
+ box-shadow 0.3s ease;
92
+ }
93
+
94
+ .card:hover {
95
+ transform: translateY(-6px);
96
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
97
+ }
98
+
99
+ .card img {
100
+ width: 100%;
101
+ height: 100%;
102
+ object-fit: cover;
103
+ display: block;
104
+ }
105
+
106
+ @keyframes fadeIn {
107
+ 0% {
108
+ opacity: 0;
109
+ transform: scale(0.95);
110
+ }
111
+ 100% {
112
+ opacity: 1;
113
+ transform: scale(1);
114
+ }
115
+ }
116
+
117
+ @keyframes fadeInUp {
118
+ 0% {
119
+ opacity: 0;
120
+ transform: translateY(20px);
121
+ }
122
+ 100% {
123
+ opacity: 1;
124
+ transform: translateY(0);
125
+ }
126
+ }
127
+ </style>
128
+ </head>
129
+ <body>
130
+ <div style="text-align: center; margin-bottom: 1rem">
131
+ <img
132
+ src="https://raw.githubusercontent.com/ultralytics/assets/main/logo/favicon.png"
133
+ alt="Ultralytics Logo"
134
+ style="height: 40px"
135
+ />
136
+ </div>
137
+ <h1>Semantic Image Search with AI</h1>
138
+
139
+ <!-- Search box -->
140
+ <form method="POST">
141
+ <input
142
+ type="text"
143
+ name="query"
144
+ placeholder="Describe the scene (e.g., man walking)"
145
+ value="{{ request.form['query'] }}"
146
+ required
147
+ />
148
+ <button type="submit">Search</button>
149
+ </form>
150
+
151
+ <!-- Search results grid -->
152
+ <div class="grid">
153
+ {% for img in results %}
154
+ <div class="card">
155
+ <img src="{{ url_for('static', filename=img) }}" alt="Result Image" />
156
+ </div>
157
+ {% endfor %}
158
+ </div>
159
+ </body>
160
+ </html>
@@ -255,6 +255,6 @@ class ReID:
255
255
  def __call__(self, img, dets):
256
256
  """Extract embeddings for detected objects."""
257
257
  feats = self.model([save_one_box(det, img, save=False) for det in xywh2xyxy(torch.from_numpy(dets[:, :4]))])
258
- if feats.shape[0] != dets.shape[0] and feats[0].shape[0] == dets.shape[0]:
258
+ if len(feats) != dets.shape[0] and feats[0].shape[0] == dets.shape[0]:
259
259
  feats = feats[0] # batched prediction with non-PyTorch backend
260
260
  return [f.cpu().numpy() for f in feats]
@@ -44,6 +44,8 @@ def on_predict_start(predictor: object, persist: bool = False) -> None:
44
44
  if cfg.tracker_type not in {"bytetrack", "botsort"}:
45
45
  raise AssertionError(f"Only 'bytetrack' and 'botsort' are supported for now, but got '{cfg.tracker_type}'")
46
46
 
47
+ predictor._feats = None # reset in case used earlier
48
+ predictor.save_feats = False
47
49
  if cfg.tracker_type == "botsort" and cfg.with_reid and cfg.model == "auto":
48
50
  from ultralytics.nn.modules.head import Detect
49
51
 
@@ -55,7 +57,6 @@ def on_predict_start(predictor: object, persist: bool = False) -> None:
55
57
  cfg.model = "yolo11n-cls.pt"
56
58
  else:
57
59
  predictor.save_feats = True
58
- predictor._feats = None
59
60
 
60
61
  # Register hook to extract input of Detect layer
61
62
  def pre_hook(module, input):
@@ -40,7 +40,7 @@ import torch.cuda
40
40
  from ultralytics import YOLO, YOLOWorld
41
41
  from ultralytics.cfg import TASK2DATA, TASK2METRIC
42
42
  from ultralytics.engine.exporter import export_formats
43
- from ultralytics.utils import ARM64, ASSETS, LINUX, LOGGER, MACOS, TQDM, WEIGHTS_DIR, YAML
43
+ from ultralytics.utils import ARM64, ASSETS, IS_JETSON, LINUX, LOGGER, MACOS, TQDM, WEIGHTS_DIR, YAML
44
44
  from ultralytics.utils.checks import IS_PYTHON_3_13, check_imgsz, check_requirements, check_yolo, is_rockchip
45
45
  from ultralytics.utils.downloads import safe_download
46
46
  from ultralytics.utils.files import file_size
@@ -126,7 +126,7 @@ def benchmark(
126
126
  assert not isinstance(model, YOLOWorld), "YOLOWorldv2 Paddle exports not supported yet"
127
127
  assert model.task != "obb", "Paddle OBB bug https://github.com/PaddlePaddle/Paddle/issues/72024"
128
128
  assert not is_end2end, "End-to-end models not supported by PaddlePaddle yet"
129
- assert LINUX or MACOS, "Windows Paddle exports not supported yet"
129
+ assert (LINUX and not IS_JETSON) or MACOS, "Windows and Jetson Paddle exports not supported yet"
130
130
  if i == 12: # MNN
131
131
  assert not isinstance(model, YOLOWorld), "YOLOWorldv2 MNN exports not supported yet"
132
132
  if i == 13: # NCNN
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ultralytics
3
- Version: 8.3.126
3
+ Version: 8.3.128
4
4
  Summary: Ultralytics YOLO 🚀 for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification.
5
5
  Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
6
6
  Maintainer-email: Ultralytics <hello@ultralytics.com>
@@ -70,6 +70,7 @@ Requires-Dist: h5py!=3.11.0; platform_machine == "aarch64" and extra == "export"
70
70
  Provides-Extra: solutions
71
71
  Requires-Dist: shapely>=2.0.0; extra == "solutions"
72
72
  Requires-Dist: streamlit>=1.29.0; extra == "solutions"
73
+ Requires-Dist: flask; extra == "solutions"
73
74
  Provides-Extra: logging
74
75
  Requires-Dist: wandb; extra == "logging"
75
76
  Requires-Dist: tensorboard; extra == "logging"
@@ -1,13 +1,13 @@
1
1
  tests/__init__.py,sha256=xnMhv3O_DF1YrW4zk__ZywQzAaoTDjPKPoiI1Ktss1w,670
2
2
  tests/conftest.py,sha256=rsIAipRKfrVNoTaJ1LdpYue8AbcJ_fr3d3WIlM_6uXY,2982
3
3
  tests/test_cli.py,sha256=PtMFl5Lp_6ygBbYDJ1ndofz2k7ZYupMPEAiZw6aZVm8,5450
4
- tests/test_cuda.py,sha256=vMjegc23QlEzMdpzav2JEjXR1n8W-lYZ-KLGiLiwLok,6167
4
+ tests/test_cuda.py,sha256=7HKiXWQM4hUdouksEB7DJILos0gb6St7fIGqx6YMkLQ,6448
5
5
  tests/test_engine.py,sha256=aGqZ8P7QO5C_nOa1b4FOyk92Ysdk5WiP-ST310Vyxys,4962
6
6
  tests/test_exports.py,sha256=dhZn86LdbapW15RthQF870LGxDjC1MUZhlGdBgPmgIQ,9716
7
7
  tests/test_integrations.py,sha256=dQteeRsRVuT_p5-T88-7jqT65Zm9iAXkyKg-KQ1_TQ8,6341
8
- tests/test_python.py,sha256=hkOJc0Ejin3Bywyw0BT4pPex5hwwfbmw0K5ChRtvdvw,25398
9
- tests/test_solutions.py,sha256=BIvg9zW0a_ggEmrPKgB_Y0MncveH-eYuN5KlqdJ6nHs,5726
10
- ultralytics/__init__.py,sha256=HfUbgU67v26Obhd8l6aWhYnTG8W_ycy0mBgszTdxe6E,730
8
+ tests/test_python.py,sha256=m3tV3atrc3DvXZ5S-_C1ief_pDo4KlLgudjc7rq26l0,25492
9
+ tests/test_solutions.py,sha256=IFlqyOUCvGbLe_YZqWmNCe_afg4as0p-SfAv3j7VURI,6205
10
+ ultralytics/__init__.py,sha256=eYHrIAy7F9bwg7pfP06EyjopprNxJRb4oqv7VuSEe8w,730
11
11
  ultralytics/assets/bus.jpg,sha256=wCAZxJecGR63Od3ZRERe9Aja1Weayrb9Ug751DS_vGM,137419
12
12
  ultralytics/assets/zidane.jpg,sha256=Ftc4aeMmen1O0A3o6GCDO9FlfBslLpTAw0gnetx7bts,50427
13
13
  ultralytics/cfg/__init__.py,sha256=We3ti0mvUQrGRmUPcufDGboW0YAO3nSRYuoWxGagk3M,39462
@@ -117,11 +117,11 @@ ultralytics/data/scripts/get_coco.sh,sha256=UuJpJeo3qQpTHVINeOpmP0NYmg8PhEFE3A8J
117
117
  ultralytics/data/scripts/get_coco128.sh,sha256=qmRQl_hOKrsdHrTrnyQuFIH01oDz3lfaz138OgGfLt8,650
118
118
  ultralytics/data/scripts/get_imagenet.sh,sha256=hr42H16bM47iT27rgS7MpEo-GeOZAYUQXgr0B2cwn48,1705
119
119
  ultralytics/engine/__init__.py,sha256=lm6MckFYCPTbqIoX7w0s_daxdjNeBeKW6DXppv1-QUM,70
120
- ultralytics/engine/exporter.py,sha256=aaZ_-np1q0klWtDXp6CxVjyiZ0DDXx-8Pqg4jZSByuE,70246
120
+ ultralytics/engine/exporter.py,sha256=XDJboUBDGDrFsppwTVujoGilf5vTkO14KYMhMu5YZQ0,70333
121
121
  ultralytics/engine/model.py,sha256=37qGh6aqqPTUyMfpsvBQMaZ1Av7eJDe6mfRl9GvlfKg,52860
122
122
  ultralytics/engine/predictor.py,sha256=YJ5l-0qIpr6JAJxowswtZ0IqmXBqVTvAA9vR40v0sCM,21752
123
123
  ultralytics/engine/results.py,sha256=-JPBn_YMyZv6HhdlyhjRIZCcMf41LTyWID7JrEP64rc,79632
124
- ultralytics/engine/trainer.py,sha256=sQCtjCI7_qOvXp4z-OPIQB1Nnqgeoi8YAIJAiCs_OOY,38951
124
+ ultralytics/engine/trainer.py,sha256=aj41kXVeNfJOlMhSNrW_XwElQ5D0jtuX6ezJC2w8xa8,39046
125
125
  ultralytics/engine/tuner.py,sha256=zEW1UpLlZ6N4xbvS7MxICkshRlaFgLNfuADA0VfRpao,12629
126
126
  ultralytics/engine/validator.py,sha256=jfV81wuFDgrVVXEcPzgOpxAPrAZn-1LgpKwu9l_1-ts,17050
127
127
  ultralytics/hub/__init__.py,sha256=wDtAUKdfqob95tfFHgDJFXcsNSDSdoIQkJTm-CfIUTI,6616
@@ -168,7 +168,7 @@ ultralytics/models/yolo/classify/predict.py,sha256=JV9szginTQ9Lpob0FozhKMiEIu1vV
168
168
  ultralytics/models/yolo/classify/train.py,sha256=rv2CJv9fzvtHf2q4l5g0RsjplWKeLpz637kKqjtrLNY,9737
169
169
  ultralytics/models/yolo/classify/val.py,sha256=xk-YwSQdl_oqyCBV0OOAOcXFL6CchebFOc36AkRSyjE,9992
170
170
  ultralytics/models/yolo/detect/__init__.py,sha256=GIRsLYR-kT4JJx7lh4ZZAFGBZj0aebokuU0A7JbjDVA,257
171
- ultralytics/models/yolo/detect/predict.py,sha256=n1-WmzkvW3dHglI7XrxDr4i0nZ236h6Wh37TAWXpFfo,5341
171
+ ultralytics/models/yolo/detect/predict.py,sha256=DOjhYCHPFPPAwZLWWmNt0d7lGka8GFeriM0OA9PTEGU,5310
172
172
  ultralytics/models/yolo/detect/train.py,sha256=YOEmUZkfJBq6hNbB_P10k-uy4_2fUgdPfVWzO4y8Egs,9538
173
173
  ultralytics/models/yolo/detect/val.py,sha256=7AB_wZi7aQ9_V1pZQSWk5qiJYS34fuO3P5aX7_3eeFE,18471
174
174
  ultralytics/models/yolo/obb/__init__.py,sha256=tQmpG8wVHsajWkZdmD6cjGohJ4ki64iSXQT8JY_dydo,221
@@ -192,7 +192,7 @@ ultralytics/models/yolo/yoloe/train.py,sha256=St3zw_XWRol9pODWU4lvKlJnWYr1lmWQNu
192
192
  ultralytics/models/yolo/yoloe/train_seg.py,sha256=l0SOMQQd0Y_EBBHhTNekgrQsftqhYyK4oWTdCg1dLrE,4633
193
193
  ultralytics/models/yolo/yoloe/val.py,sha256=oA8cVT3pBXF6aPZy7ITq0mDcktRuIgks8tTtqMRISyY,8431
194
194
  ultralytics/nn/__init__.py,sha256=rjociYD9lo_K-d-1s6TbdWklPLjTcEHk7OIlRDJstIE,615
195
- ultralytics/nn/autobackend.py,sha256=03DGRLuVDJ8T2zWFqmAX0eOhy42bhIRS7KdpSII8bEE,39309
195
+ ultralytics/nn/autobackend.py,sha256=9uuLVg5_1irhw2OYahkVoGWmcyB61jVFBVZEiN8GQ1A,39325
196
196
  ultralytics/nn/tasks.py,sha256=0rnM6Z01BUnRtUwCkTwVsPxZ_D3A5tNbBjd7aEoxxns,62943
197
197
  ultralytics/nn/text_model.py,sha256=8_7SRejKZA4Pi-ha0gjcWrQDDCDMBhtwlg8pPMWgjDE,13145
198
198
  ultralytics/nn/modules/__init__.py,sha256=dXLtIk9rt944WfsTdpgEdWOg3HQEHdwQztuZ6WNJygs,3144
@@ -202,10 +202,10 @@ ultralytics/nn/modules/conv.py,sha256=nxbfAxmvo6A9atuxY3LXTtzMXhihZapCSg1F5mI4sI
202
202
  ultralytics/nn/modules/head.py,sha256=FbFB-e44Zvxgzdfy0FqeGWUn0DDahmEZvD1W_N2olcM,38442
203
203
  ultralytics/nn/modules/transformer.py,sha256=tC80QKFaLtWZo0zVNTuORX4pOu6HVs2wS0vSM-3h5W4,28227
204
204
  ultralytics/nn/modules/utils.py,sha256=rn8yTObZGkQoqVzjbZWLaHiytppG4ffjMME4Lw60glM,6092
205
- ultralytics/solutions/__init__.py,sha256=pjNYva0qnw-4hf_tTLx_dgIfg24XrYLLp3kygPj95rs,1113
205
+ ultralytics/solutions/__init__.py,sha256=ZoeAQavTLp8aClnhZ9tbl6lxy86GxofyGvZWTx2aWkI,1209
206
206
  ultralytics/solutions/ai_gym.py,sha256=QRrZGMka83NY4B9gU3N2GxTaomo0WmTMNLxkNZTxo9U,5763
207
207
  ultralytics/solutions/analytics.py,sha256=u-khRAViGupjq9mkuAFCl9G3yE8hXfXASfKZd_SQZ-8,12111
208
- ultralytics/solutions/config.py,sha256=ogXWpE0LhVXHz05M2ChrVu5usIxsRy2yxraHuSyc_V0,5330
208
+ ultralytics/solutions/config.py,sha256=TLxQuZjqW-vhbS2OFmTT188-31ukHg1XP7l-BeOmqbU,5427
209
209
  ultralytics/solutions/distance_calculation.py,sha256=E13siGlQTqaGCk0xULk5Q86PwxiBAL4XWp83kQPb0YE,5751
210
210
  ultralytics/solutions/heatmap.py,sha256=lXYptA_EbypipF7YJMjsxxBzLAgsroLcdqypvNAhduA,5569
211
211
  ultralytics/solutions/instance_segmentation.py,sha256=HxzFf752PwjAjZhrf8BzI-gEey_f9mjxTOqJsLHSIB8,3498
@@ -216,16 +216,18 @@ ultralytics/solutions/parking_management.py,sha256=BV-2lpSfgmK7fib3DnPSZ5rtLdy11
216
216
  ultralytics/solutions/queue_management.py,sha256=p1-cuI_rs4ygtlBryXjE65NYG2bnZXhp3ylggFnWcRs,4344
217
217
  ultralytics/solutions/region_counter.py,sha256=Zn35YRXNzhBk27D9MLOHBYe2L1o6H2ey3mEwCXofB_E,5418
218
218
  ultralytics/solutions/security_alarm.py,sha256=cmUWvz7U9IAxlOr-QCIU_j95lc2c8eUx9wI04t1vDFU,6251
219
- ultralytics/solutions/solutions.py,sha256=MV2sKr0mHVMh-dT2SmiYkYLFCdoNz-2VA0z4a7fWK_8,32503
219
+ ultralytics/solutions/similarity_search.py,sha256=WTYmHNHfFrRiJ6mrZhJvGPsjt3szQUiM6VRpw2eBRjA,7332
220
+ ultralytics/solutions/solutions.py,sha256=aXU5p6zv8UPyaC8v51tsE9L_KzmnRCP4M9PP6pAYMXQ,32715
220
221
  ultralytics/solutions/speed_estimation.py,sha256=r7S5nGIx8PTV-zC4zCI36lQD2DVy5cen5cTXItfQIHo,5318
221
222
  ultralytics/solutions/streamlit_inference.py,sha256=M0ppTFInqSPrdytZBLH8x-XoA7zFc7PaRQ51wHG9ppU,9846
222
223
  ultralytics/solutions/trackzone.py,sha256=mfklnZcVRqI3bbhPiHF2iSoV6INcd10wwwGP4tlK7L0,3854
223
224
  ultralytics/solutions/vision_eye.py,sha256=7YrMqZkR28LLNHWxX3Ye78GvPdXXuouQAmgMdGwRLQ4,2953
225
+ ultralytics/solutions/templates/similarity-search.html,sha256=DPoAO-1H-KXNt_T8mGtSCsYUEi_5Nrx01p0cZfX-E8Q,3790
224
226
  ultralytics/trackers/__init__.py,sha256=Zlu_Ig5osn7hqch_g5Be_e4pwZUkeeTQiesJCi0pFGI,255
225
227
  ultralytics/trackers/basetrack.py,sha256=LYvWB5d7Woyrz_RlxaopjV07RQKH3sff_lZJfMcMxcA,4450
226
- ultralytics/trackers/bot_sort.py,sha256=rpaj7X8COT0Vi5GFR9z-CGSBgJ7gTfFx2wTSZFTnhco,11466
228
+ ultralytics/trackers/bot_sort.py,sha256=fAMV6PJE19jXe-6u524bpcz7x3Ssauk3b3wKXUYpvoY,11462
227
229
  ultralytics/trackers/byte_tracker.py,sha256=D7JQ_6V8OUMQryxTrAr010UXMSaboQnI7T1xppzHXYg,20921
228
- ultralytics/trackers/track.py,sha256=ghFyAaXg1fp7QPX_SDWkH05cx07xnAlhUypkT3djXD0,4825
230
+ ultralytics/trackers/track.py,sha256=hTh-qRZvCrnmo8TsfMQK8sp1F7qeUi97jgtXX-xhX3I,4880
229
231
  ultralytics/trackers/utils/__init__.py,sha256=lm6MckFYCPTbqIoX7w0s_daxdjNeBeKW6DXppv1-QUM,70
230
232
  ultralytics/trackers/utils/gmc.py,sha256=dz3I5LbIv7h1__Xg7rGHecQFE32VFTe54tUnxb8F0Z8,14466
231
233
  ultralytics/trackers/utils/kalman_filter.py,sha256=A0CqOnnaKH6kr0XwuHzyHmIU6aJAjJYxF9jVlNBKZHo,21326
@@ -233,7 +235,7 @@ ultralytics/trackers/utils/matching.py,sha256=7eIufSdeN7cXuFMjvcfvz0Ldq84m4YKZl5
233
235
  ultralytics/utils/__init__.py,sha256=YSBOQcgak2v6l03EHPjkpzH-ZtjVXrg2_4o0BF1cqDQ,52807
234
236
  ultralytics/utils/autobatch.py,sha256=kg05q2qKg74y_Uq2vvr01i3KhLfpVR7sT0IXBt3_kyI,4921
235
237
  ultralytics/utils/autodevice.py,sha256=OrLSk34UpW0I5ndxnkQEIWBxL--CvAON_W9Qw51zOGA,7233
236
- ultralytics/utils/benchmarks.py,sha256=1Y6R1DxdSOzeHRsKKgMOab_bdtEWF9z32HOU2hqgzss,30172
238
+ ultralytics/utils/benchmarks.py,sha256=lDNNnLeLUzmqKrqrqlCOiau-q7A-gcLooZP2dbxCu-U,30214
237
239
  ultralytics/utils/checks.py,sha256=Z87AuJ3C5JcTVYdhAn31BFErmF48bRyMc4_WZ9ku5-E,32711
238
240
  ultralytics/utils/dist.py,sha256=aytW0JEkcA5ZTZucV92ot7Bn-apiej8aLk3QNWicjAc,4103
239
241
  ultralytics/utils/downloads.py,sha256=Rn8xDwn2bzgBqiYz3Xn0rm3MWjk4T-QUd2Ajlu1EpQ4,22312
@@ -261,9 +263,9 @@ ultralytics/utils/callbacks/neptune.py,sha256=JaI95Cj2kIjUhlEEOiDN0-Drc-fDelLhNI
261
263
  ultralytics/utils/callbacks/raytune.py,sha256=A8amUGpux7dYES-L1iSeMoMXBySGWCD1aUqT7vcG-pU,1284
262
264
  ultralytics/utils/callbacks/tensorboard.py,sha256=jgYnym3cUQFAgN1GzTyO7l3jINtfAh8zhrllDvnLuVQ,5339
263
265
  ultralytics/utils/callbacks/wb.py,sha256=iDRFXI4IIDm8R5OI89DMTmjs8aHLo1HRCLkOFKdaMG4,7507
264
- ultralytics-8.3.126.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
265
- ultralytics-8.3.126.dist-info/METADATA,sha256=zkgsqHwnXIUCbSDzK_gK_HunHRJAQvvvIgix7NOzXgw,37180
266
- ultralytics-8.3.126.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
267
- ultralytics-8.3.126.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
268
- ultralytics-8.3.126.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
269
- ultralytics-8.3.126.dist-info/RECORD,,
266
+ ultralytics-8.3.128.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
267
+ ultralytics-8.3.128.dist-info/METADATA,sha256=-IGLMF2lUP_NBqvLF8v0L8mTJX9DuFEiU5yxPFcXlhY,37223
268
+ ultralytics-8.3.128.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
269
+ ultralytics-8.3.128.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
270
+ ultralytics-8.3.128.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
271
+ ultralytics-8.3.128.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.0)
2
+ Generator: setuptools (80.3.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5