ultralytics 8.3.162__py3-none-any.whl → 8.3.164__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.
- ultralytics/__init__.py +1 -1
- ultralytics/data/augment.py +182 -153
- ultralytics/data/build.py +23 -3
- ultralytics/data/dataset.py +6 -2
- ultralytics/data/loaders.py +2 -2
- ultralytics/data/utils.py +12 -9
- ultralytics/engine/exporter.py +9 -5
- ultralytics/engine/predictor.py +6 -6
- ultralytics/engine/results.py +42 -42
- ultralytics/models/fastsam/model.py +1 -1
- ultralytics/models/fastsam/predict.py +1 -1
- ultralytics/models/sam/model.py +4 -4
- ultralytics/models/sam/modules/blocks.py +5 -5
- ultralytics/models/sam/modules/memory_attention.py +19 -19
- ultralytics/models/sam/modules/transformer.py +24 -22
- ultralytics/models/yolo/detect/val.py +2 -2
- ultralytics/models/yolo/world/train_world.py +9 -1
- ultralytics/nn/tasks.py +2 -0
- ultralytics/solutions/distance_calculation.py +1 -1
- ultralytics/solutions/instance_segmentation.py +2 -2
- ultralytics/solutions/object_blurrer.py +2 -2
- ultralytics/solutions/object_counter.py +2 -2
- ultralytics/solutions/object_cropper.py +1 -1
- ultralytics/solutions/queue_management.py +1 -1
- ultralytics/solutions/region_counter.py +29 -32
- ultralytics/solutions/security_alarm.py +2 -2
- ultralytics/solutions/templates/similarity-search.html +0 -24
- ultralytics/solutions/vision_eye.py +1 -1
- ultralytics/utils/benchmarks.py +2 -2
- ultralytics/utils/export.py +0 -2
- ultralytics/utils/instance.py +32 -25
- ultralytics/utils/ops.py +8 -8
- {ultralytics-8.3.162.dist-info → ultralytics-8.3.164.dist-info}/METADATA +1 -1
- {ultralytics-8.3.162.dist-info → ultralytics-8.3.164.dist-info}/RECORD +38 -38
- {ultralytics-8.3.162.dist-info → ultralytics-8.3.164.dist-info}/WHEEL +0 -0
- {ultralytics-8.3.162.dist-info → ultralytics-8.3.164.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.162.dist-info → ultralytics-8.3.164.dist-info}/licenses/LICENSE +0 -0
- {ultralytics-8.3.162.dist-info → ultralytics-8.3.164.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,7 @@ import copy
|
|
4
4
|
from typing import Optional
|
5
5
|
|
6
6
|
import torch
|
7
|
-
from torch import
|
7
|
+
from torch import nn
|
8
8
|
|
9
9
|
from .blocks import RoPEAttention
|
10
10
|
|
@@ -103,7 +103,7 @@ class MemoryAttentionLayer(nn.Module):
|
|
103
103
|
self.pos_enc_at_cross_attn_queries = pos_enc_at_cross_attn_queries
|
104
104
|
self.pos_enc_at_cross_attn_keys = pos_enc_at_cross_attn_keys
|
105
105
|
|
106
|
-
def _forward_sa(self, tgt: Tensor, query_pos: Optional[Tensor]) -> Tensor:
|
106
|
+
def _forward_sa(self, tgt: torch.Tensor, query_pos: Optional[torch.Tensor]) -> torch.Tensor:
|
107
107
|
"""Perform self-attention on input tensor using positional encoding and RoPE attention mechanism."""
|
108
108
|
tgt2 = self.norm1(tgt)
|
109
109
|
q = k = tgt2 + query_pos if self.pos_enc_at_attn else tgt2
|
@@ -113,12 +113,12 @@ class MemoryAttentionLayer(nn.Module):
|
|
113
113
|
|
114
114
|
def _forward_ca(
|
115
115
|
self,
|
116
|
-
tgt: Tensor,
|
117
|
-
memory: Tensor,
|
118
|
-
query_pos: Optional[Tensor],
|
119
|
-
pos: Optional[Tensor],
|
116
|
+
tgt: torch.Tensor,
|
117
|
+
memory: torch.Tensor,
|
118
|
+
query_pos: Optional[torch.Tensor],
|
119
|
+
pos: Optional[torch.Tensor],
|
120
120
|
num_k_exclude_rope: int = 0,
|
121
|
-
) -> Tensor:
|
121
|
+
) -> torch.Tensor:
|
122
122
|
"""Perform cross-attention between target and memory tensors using RoPEAttention mechanism."""
|
123
123
|
kwds = {}
|
124
124
|
if num_k_exclude_rope > 0:
|
@@ -138,20 +138,20 @@ class MemoryAttentionLayer(nn.Module):
|
|
138
138
|
|
139
139
|
def forward(
|
140
140
|
self,
|
141
|
-
tgt: Tensor,
|
142
|
-
memory: Tensor,
|
143
|
-
pos: Optional[Tensor] = None,
|
144
|
-
query_pos: Optional[Tensor] = None,
|
141
|
+
tgt: torch.Tensor,
|
142
|
+
memory: torch.Tensor,
|
143
|
+
pos: Optional[torch.Tensor] = None,
|
144
|
+
query_pos: Optional[torch.Tensor] = None,
|
145
145
|
num_k_exclude_rope: int = 0,
|
146
146
|
) -> torch.Tensor:
|
147
147
|
"""
|
148
148
|
Process input tensors through self-attention, cross-attention, and feedforward network layers.
|
149
149
|
|
150
150
|
Args:
|
151
|
-
tgt (Tensor): Target tensor for self-attention with shape (N, L, D).
|
152
|
-
memory (Tensor): Memory tensor for cross-attention with shape (N, S, D).
|
153
|
-
pos (Optional[Tensor]): Positional encoding for memory tensor.
|
154
|
-
query_pos (Optional[Tensor]): Positional encoding for target tensor.
|
151
|
+
tgt (torch.Tensor): Target tensor for self-attention with shape (N, L, D).
|
152
|
+
memory (torch.Tensor): Memory tensor for cross-attention with shape (N, S, D).
|
153
|
+
pos (Optional[torch.Tensor]): Positional encoding for memory tensor.
|
154
|
+
query_pos (Optional[torch.Tensor]): Positional encoding for target tensor.
|
155
155
|
num_k_exclude_rope (int): Number of keys to exclude from rotary position embedding.
|
156
156
|
|
157
157
|
Returns:
|
@@ -242,8 +242,8 @@ class MemoryAttention(nn.Module):
|
|
242
242
|
self,
|
243
243
|
curr: torch.Tensor, # self-attention inputs
|
244
244
|
memory: torch.Tensor, # cross-attention inputs
|
245
|
-
curr_pos: Optional[Tensor] = None, # pos_enc for self-attention inputs
|
246
|
-
memory_pos: Optional[Tensor] = None, # pos_enc for cross-attention inputs
|
245
|
+
curr_pos: Optional[torch.Tensor] = None, # pos_enc for self-attention inputs
|
246
|
+
memory_pos: Optional[torch.Tensor] = None, # pos_enc for cross-attention inputs
|
247
247
|
num_obj_ptr_tokens: int = 0, # number of object pointer *tokens*
|
248
248
|
) -> torch.Tensor:
|
249
249
|
"""
|
@@ -252,8 +252,8 @@ class MemoryAttention(nn.Module):
|
|
252
252
|
Args:
|
253
253
|
curr (torch.Tensor): Self-attention input tensor, representing the current state.
|
254
254
|
memory (torch.Tensor): Cross-attention input tensor, representing memory information.
|
255
|
-
curr_pos (Optional[Tensor]): Positional encoding for self-attention inputs.
|
256
|
-
memory_pos (Optional[Tensor]): Positional encoding for cross-attention inputs.
|
255
|
+
curr_pos (Optional[torch.Tensor]): Positional encoding for self-attention inputs.
|
256
|
+
memory_pos (Optional[torch.Tensor]): Positional encoding for cross-attention inputs.
|
257
257
|
num_obj_ptr_tokens (int): Number of object pointer tokens to exclude from rotary position embedding.
|
258
258
|
|
259
259
|
Returns:
|
@@ -82,21 +82,21 @@ class TwoWayTransformer(nn.Module):
|
|
82
82
|
|
83
83
|
def forward(
|
84
84
|
self,
|
85
|
-
image_embedding: Tensor,
|
86
|
-
image_pe: Tensor,
|
87
|
-
point_embedding: Tensor,
|
88
|
-
) -> Tuple[Tensor, Tensor]:
|
85
|
+
image_embedding: torch.Tensor,
|
86
|
+
image_pe: torch.Tensor,
|
87
|
+
point_embedding: torch.Tensor,
|
88
|
+
) -> Tuple[torch.Tensor, torch.Tensor]:
|
89
89
|
"""
|
90
90
|
Process image and point embeddings through the Two-Way Transformer.
|
91
91
|
|
92
92
|
Args:
|
93
|
-
image_embedding (Tensor): Image to attend to, with shape (B, embedding_dim, H, W).
|
94
|
-
image_pe (Tensor): Positional encoding to add to the image, with same shape as image_embedding.
|
95
|
-
point_embedding (Tensor): Embedding to add to query points, with shape (B, N_points, embedding_dim).
|
93
|
+
image_embedding (torch.Tensor): Image to attend to, with shape (B, embedding_dim, H, W).
|
94
|
+
image_pe (torch.Tensor): Positional encoding to add to the image, with same shape as image_embedding.
|
95
|
+
point_embedding (torch.Tensor): Embedding to add to query points, with shape (B, N_points, embedding_dim).
|
96
96
|
|
97
97
|
Returns:
|
98
|
-
queries (Tensor): Processed point embeddings with shape (B, N_points, embedding_dim).
|
99
|
-
keys (Tensor): Processed image embeddings with shape (B, H*W, embedding_dim).
|
98
|
+
queries (torch.Tensor): Processed point embeddings with shape (B, N_points, embedding_dim).
|
99
|
+
keys (torch.Tensor): Processed image embeddings with shape (B, H*W, embedding_dim).
|
100
100
|
"""
|
101
101
|
# BxCxHxW -> BxHWxC == B x N_image_tokens x C
|
102
102
|
image_embedding = image_embedding.flatten(2).permute(0, 2, 1)
|
@@ -196,19 +196,21 @@ class TwoWayAttentionBlock(nn.Module):
|
|
196
196
|
|
197
197
|
self.skip_first_layer_pe = skip_first_layer_pe
|
198
198
|
|
199
|
-
def forward(
|
199
|
+
def forward(
|
200
|
+
self, queries: torch.Tensor, keys: torch.Tensor, query_pe: torch.Tensor, key_pe: torch.Tensor
|
201
|
+
) -> Tuple[torch.Tensor, torch.Tensor]:
|
200
202
|
"""
|
201
203
|
Apply two-way attention to process query and key embeddings in a transformer block.
|
202
204
|
|
203
205
|
Args:
|
204
|
-
queries (Tensor): Query embeddings with shape (B, N_queries, embedding_dim).
|
205
|
-
keys (Tensor): Key embeddings with shape (B, N_keys, embedding_dim).
|
206
|
-
query_pe (Tensor): Positional encodings for queries with same shape as queries.
|
207
|
-
key_pe (Tensor): Positional encodings for keys with same shape as keys.
|
206
|
+
queries (torch.Tensor): Query embeddings with shape (B, N_queries, embedding_dim).
|
207
|
+
keys (torch.Tensor): Key embeddings with shape (B, N_keys, embedding_dim).
|
208
|
+
query_pe (torch.Tensor): Positional encodings for queries with same shape as queries.
|
209
|
+
key_pe (torch.Tensor): Positional encodings for keys with same shape as keys.
|
208
210
|
|
209
211
|
Returns:
|
210
|
-
queries (Tensor): Processed query embeddings with shape (B, N_queries, embedding_dim).
|
211
|
-
keys (Tensor): Processed key embeddings with shape (B, N_keys, embedding_dim).
|
212
|
+
queries (torch.Tensor): Processed query embeddings with shape (B, N_queries, embedding_dim).
|
213
|
+
keys (torch.Tensor): Processed key embeddings with shape (B, N_keys, embedding_dim).
|
212
214
|
"""
|
213
215
|
# Self attention block
|
214
216
|
if self.skip_first_layer_pe:
|
@@ -304,7 +306,7 @@ class Attention(nn.Module):
|
|
304
306
|
self.out_proj = nn.Linear(self.internal_dim, embedding_dim)
|
305
307
|
|
306
308
|
@staticmethod
|
307
|
-
def _separate_heads(x: Tensor, num_heads: int) -> Tensor:
|
309
|
+
def _separate_heads(x: torch.Tensor, num_heads: int) -> torch.Tensor:
|
308
310
|
"""Separate the input tensor into the specified number of attention heads."""
|
309
311
|
b, n, c = x.shape
|
310
312
|
x = x.reshape(b, n, num_heads, c // num_heads)
|
@@ -317,17 +319,17 @@ class Attention(nn.Module):
|
|
317
319
|
x = x.transpose(1, 2)
|
318
320
|
return x.reshape(b, n_tokens, n_heads * c_per_head) # B x N_tokens x C
|
319
321
|
|
320
|
-
def forward(self, q: Tensor, k: Tensor, v: Tensor) -> Tensor:
|
322
|
+
def forward(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
|
321
323
|
"""
|
322
324
|
Apply multi-head attention to query, key, and value tensors with optional downsampling.
|
323
325
|
|
324
326
|
Args:
|
325
|
-
q (Tensor): Query tensor with shape (B, N_q, embedding_dim).
|
326
|
-
k (Tensor): Key tensor with shape (B, N_k, embedding_dim).
|
327
|
-
v (Tensor): Value tensor with shape (B, N_k, embedding_dim).
|
327
|
+
q (torch.Tensor): Query tensor with shape (B, N_q, embedding_dim).
|
328
|
+
k (torch.Tensor): Key tensor with shape (B, N_k, embedding_dim).
|
329
|
+
v (torch.Tensor): Value tensor with shape (B, N_k, embedding_dim).
|
328
330
|
|
329
331
|
Returns:
|
330
|
-
(Tensor): Output tensor after attention with shape (B, N_q, embedding_dim).
|
332
|
+
(torch.Tensor): Output tensor after attention with shape (B, N_q, embedding_dim).
|
331
333
|
"""
|
332
334
|
# Input projections
|
333
335
|
q = self.q_proj(q)
|
@@ -450,8 +450,8 @@ class DetectionValidator(BaseValidator):
|
|
450
450
|
val.summarize()
|
451
451
|
|
452
452
|
# update mAP50-95 and mAP50
|
453
|
-
stats[f"metrics/mAP50({suffix[i][0]})"] = val.stats_as_dict["
|
454
|
-
stats[f"metrics/mAP50-95({suffix[i][0]})"] = val.stats_as_dict["
|
453
|
+
stats[f"metrics/mAP50({suffix[i][0]})"] = val.stats_as_dict["AP_50"]
|
454
|
+
stats[f"metrics/mAP50-95({suffix[i][0]})"] = val.stats_as_dict["AP_all"]
|
455
455
|
|
456
456
|
if self.is_lvis:
|
457
457
|
stats[f"metrics/APr({suffix[i][0]})"] = val.stats_as_dict["APr"]
|
@@ -107,7 +107,15 @@ class WorldTrainerFromScratch(WorldTrainer):
|
|
107
107
|
datasets = [
|
108
108
|
build_yolo_dataset(self.args, im_path, batch, self.training_data[im_path], stride=gs, multi_modal=True)
|
109
109
|
if isinstance(im_path, str)
|
110
|
-
else build_grounding(
|
110
|
+
else build_grounding(
|
111
|
+
# assign `nc` from validation set to max number of text samples for training consistency
|
112
|
+
self.args,
|
113
|
+
im_path["img_path"],
|
114
|
+
im_path["json_file"],
|
115
|
+
batch,
|
116
|
+
stride=gs,
|
117
|
+
max_samples=self.data["nc"],
|
118
|
+
)
|
111
119
|
for im_path in img_path
|
112
120
|
]
|
113
121
|
self.set_text_embeddings(datasets, batch) # cache text embeddings to accelerate training
|
ultralytics/nn/tasks.py
CHANGED
@@ -249,6 +249,8 @@ class BaseModel(torch.nn.Module):
|
|
249
249
|
m.forward = m.forward_fuse
|
250
250
|
if isinstance(m, v10Detect):
|
251
251
|
m.fuse() # remove one2many head
|
252
|
+
if isinstance(m, YOLOEDetect) and hasattr(self, "pe"):
|
253
|
+
m.fuse(self.pe.to(next(self.model.parameters()).device))
|
252
254
|
self.info(verbose=verbose)
|
253
255
|
|
254
256
|
return self
|
@@ -76,7 +76,7 @@ class DistanceCalculation(BaseSolution):
|
|
76
76
|
between two user-selected objects if they have been chosen.
|
77
77
|
|
78
78
|
Args:
|
79
|
-
im0 (
|
79
|
+
im0 (np.ndarray): The input image frame to process.
|
80
80
|
|
81
81
|
Returns:
|
82
82
|
(SolutionResults): Contains processed image `plot_im`, `total_tracks` (int) representing the total number
|
@@ -19,7 +19,7 @@ class InstanceSegmentation(BaseSolution):
|
|
19
19
|
names (Dict[int, str]): Dictionary mapping class indices to class names.
|
20
20
|
clss (List[int]): List of detected class indices.
|
21
21
|
track_ids (List[int]): List of track IDs for detected instances.
|
22
|
-
masks (List[
|
22
|
+
masks (List[np.ndarray]): List of segmentation masks for detected instances.
|
23
23
|
show_conf (bool): Whether to display confidence scores.
|
24
24
|
show_labels (bool): Whether to display class labels.
|
25
25
|
show_boxes (bool): Whether to display bounding boxes.
|
@@ -55,7 +55,7 @@ class InstanceSegmentation(BaseSolution):
|
|
55
55
|
Perform instance segmentation on the input image and annotate the results.
|
56
56
|
|
57
57
|
Args:
|
58
|
-
im0 (
|
58
|
+
im0 (np.ndarray): The input image for segmentation.
|
59
59
|
|
60
60
|
Returns:
|
61
61
|
(SolutionResults): Object containing the annotated image and total number of tracked instances.
|
@@ -56,11 +56,11 @@ class ObjectBlurrer(BaseSolution):
|
|
56
56
|
and annotates the image with bounding boxes.
|
57
57
|
|
58
58
|
Args:
|
59
|
-
im0 (
|
59
|
+
im0 (np.ndarray): The input image containing detected objects.
|
60
60
|
|
61
61
|
Returns:
|
62
62
|
(SolutionResults): Object containing the processed image and number of tracked objects.
|
63
|
-
- plot_im (
|
63
|
+
- plot_im (np.ndarray): The annotated output image with blurred objects.
|
64
64
|
- total_tracks (int): The total number of tracked objects in the frame.
|
65
65
|
|
66
66
|
Examples:
|
@@ -122,7 +122,7 @@ class ObjectCounter(BaseSolution):
|
|
122
122
|
Display object counts on the input image or frame.
|
123
123
|
|
124
124
|
Args:
|
125
|
-
plot_im (
|
125
|
+
plot_im (np.ndarray): The image or frame to display counts on.
|
126
126
|
|
127
127
|
Examples:
|
128
128
|
>>> counter = ObjectCounter()
|
@@ -146,7 +146,7 @@ class ObjectCounter(BaseSolution):
|
|
146
146
|
object counts, and displays the results on the input image.
|
147
147
|
|
148
148
|
Args:
|
149
|
-
im0 (
|
149
|
+
im0 (np.ndarray): The input image or frame to be processed.
|
150
150
|
|
151
151
|
Returns:
|
152
152
|
(SolutionResults): Contains processed image `im0`, 'in_count' (int, count of objects entering the region),
|
@@ -57,7 +57,7 @@ class ObjectCropper(BaseSolution):
|
|
57
57
|
Crop detected objects from the input image and save them as separate images.
|
58
58
|
|
59
59
|
Args:
|
60
|
-
im0 (
|
60
|
+
im0 (np.ndarray): The input image containing detected objects.
|
61
61
|
|
62
62
|
Returns:
|
63
63
|
(SolutionResults): A SolutionResults object containing the total number of cropped objects and processed
|
@@ -50,7 +50,7 @@ class QueueManager(BaseSolution):
|
|
50
50
|
Process queue management for a single frame of video.
|
51
51
|
|
52
52
|
Args:
|
53
|
-
im0 (
|
53
|
+
im0 (np.ndarray): Input image for processing, typically a frame from a video stream.
|
54
54
|
|
55
55
|
Returns:
|
56
56
|
(SolutionResults): Contains processed image `im0`, 'queue_count' (int, number of objects in the queue) and
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
|
-
from typing import Any, List, Tuple
|
3
|
+
from typing import Any, Dict, List, Tuple
|
4
4
|
|
5
5
|
import numpy as np
|
6
6
|
|
@@ -26,6 +26,7 @@ class RegionCounter(BaseSolution):
|
|
26
26
|
Methods:
|
27
27
|
add_region: Add a new counting region with specified attributes.
|
28
28
|
process: Process video frames to count objects in each region.
|
29
|
+
initialize_regions: Initialize zones to count the objects in each one. Zones could be multiple as well.
|
29
30
|
|
30
31
|
Examples:
|
31
32
|
Initialize a RegionCounter and add a counting region
|
@@ -42,12 +43,12 @@ class RegionCounter(BaseSolution):
|
|
42
43
|
"name": "Default Region",
|
43
44
|
"polygon": None,
|
44
45
|
"counts": 0,
|
45
|
-
"dragging": False,
|
46
46
|
"region_color": (255, 255, 255),
|
47
47
|
"text_color": (0, 0, 0),
|
48
48
|
}
|
49
49
|
self.region_counts = {}
|
50
50
|
self.counting_regions = []
|
51
|
+
self.initialize_regions()
|
51
52
|
|
52
53
|
def add_region(
|
53
54
|
self,
|
@@ -55,7 +56,7 @@ class RegionCounter(BaseSolution):
|
|
55
56
|
polygon_points: List[Tuple],
|
56
57
|
region_color: Tuple[int, int, int],
|
57
58
|
text_color: Tuple[int, int, int],
|
58
|
-
) ->
|
59
|
+
) -> Dict[str, Any]:
|
59
60
|
"""
|
60
61
|
Add a new region to the counting list based on the provided template with specific attributes.
|
61
62
|
|
@@ -64,6 +65,9 @@ class RegionCounter(BaseSolution):
|
|
64
65
|
polygon_points (List[Tuple]): List of (x, y) coordinates defining the region's polygon.
|
65
66
|
region_color (Tuple[int, int, int]): BGR color for region visualization.
|
66
67
|
text_color (Tuple[int, int, int]): BGR color for the text within the region.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
(Dict[str, any]): Returns a dictionary including the region information i.e. name, region_color etc.
|
67
71
|
"""
|
68
72
|
region = self.region_template.copy()
|
69
73
|
region.update(
|
@@ -75,6 +79,17 @@ class RegionCounter(BaseSolution):
|
|
75
79
|
}
|
76
80
|
)
|
77
81
|
self.counting_regions.append(region)
|
82
|
+
return region
|
83
|
+
|
84
|
+
def initialize_regions(self):
|
85
|
+
"""Initialize regions only once."""
|
86
|
+
if self.region is None:
|
87
|
+
self.initialize_region()
|
88
|
+
if not isinstance(self.region, dict): # Ensure self.region is initialized and structured as a dictionary
|
89
|
+
self.region = {"Region#01": self.region}
|
90
|
+
for i, (name, pts) in enumerate(self.region.items()):
|
91
|
+
region = self.add_region(name, pts, colors(i, True), (255, 255, 255))
|
92
|
+
region["prepared_polygon"] = self.prep(region["polygon"])
|
78
93
|
|
79
94
|
def process(self, im0: np.ndarray) -> SolutionResults:
|
80
95
|
"""
|
@@ -90,39 +105,21 @@ class RegionCounter(BaseSolution):
|
|
90
105
|
self.extract_tracks(im0)
|
91
106
|
annotator = SolutionAnnotator(im0, line_width=self.line_width)
|
92
107
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
annotator.draw_region(reg_pts, color, self.line_width * 2)
|
101
|
-
self.add_region(region_name, reg_pts, color, annotator.get_txt_color())
|
102
|
-
|
103
|
-
# Prepare regions for containment check (only process valid ones)
|
104
|
-
for region in self.counting_regions:
|
105
|
-
if "prepared_polygon" not in region:
|
106
|
-
region["prepared_polygon"] = self.prep(region["polygon"])
|
107
|
-
|
108
|
-
# Convert bounding boxes to NumPy array for center points
|
109
|
-
boxes_np = np.array([((box[0] + box[2]) / 2, (box[1] + box[3]) / 2) for box in self.boxes], dtype=np.float32)
|
110
|
-
points = [self.Point(pt) for pt in boxes_np] # Convert centers to Point objects
|
111
|
-
|
112
|
-
# Process bounding boxes & check containment
|
113
|
-
if points:
|
114
|
-
for point, cls, track_id, box, conf in zip(points, self.clss, self.track_ids, self.boxes, self.confs):
|
115
|
-
annotator.box_label(box, label=self.adjust_box_label(cls, conf, track_id), color=colors(track_id, True))
|
116
|
-
|
117
|
-
for region in self.counting_regions:
|
118
|
-
if region["prepared_polygon"].contains(point):
|
119
|
-
region["counts"] += 1
|
120
|
-
self.region_counts[region["name"]] = region["counts"]
|
108
|
+
for box, cls, track_id, conf in zip(self.boxes, self.clss, self.track_ids, self.confs):
|
109
|
+
annotator.box_label(box, label=self.adjust_box_label(cls, conf, track_id), color=colors(track_id, True))
|
110
|
+
center = self.Point(((box[0] + box[2]) / 2, (box[1] + box[3]) / 2))
|
111
|
+
for region in self.counting_regions:
|
112
|
+
if region["prepared_polygon"].contains(center):
|
113
|
+
region["counts"] += 1
|
114
|
+
self.region_counts[region["name"]] = region["counts"]
|
121
115
|
|
122
116
|
# Display region counts
|
123
117
|
for region in self.counting_regions:
|
118
|
+
x1, y1, x2, y2 = map(int, region["polygon"].bounds)
|
119
|
+
pts = [(x1, y1), (x2, y1), (x2, y2), (x1, y2)]
|
120
|
+
annotator.draw_region(pts, region["region_color"], self.line_width * 2)
|
124
121
|
annotator.text_label(
|
125
|
-
|
122
|
+
[x1, y1, x2, y2],
|
126
123
|
label=str(region["counts"]),
|
127
124
|
color=region["region_color"],
|
128
125
|
txt_color=region["text_color"],
|
@@ -76,7 +76,7 @@ class SecurityAlarm(BaseSolution):
|
|
76
76
|
Send an email notification with an image attachment indicating the number of objects detected.
|
77
77
|
|
78
78
|
Args:
|
79
|
-
im0 (
|
79
|
+
im0 (np.ndarray): The input image or frame to be attached to the email.
|
80
80
|
records (int, optional): The number of detected objects to be included in the email message.
|
81
81
|
|
82
82
|
This method encodes the input image, composes the email message with details about the detection, and sends it
|
@@ -121,7 +121,7 @@ class SecurityAlarm(BaseSolution):
|
|
121
121
|
Monitor the frame, process object detections, and trigger alerts if thresholds are exceeded.
|
122
122
|
|
123
123
|
Args:
|
124
|
-
im0 (
|
124
|
+
im0 (np.ndarray): The input image or frame to be processed and annotated.
|
125
125
|
|
126
126
|
Returns:
|
127
127
|
(SolutionResults): Contains processed image `plot_im`, 'total_tracks' (total number of tracked objects) and
|
@@ -35,7 +35,6 @@
|
|
35
35
|
align-items: center;
|
36
36
|
gap: 1rem;
|
37
37
|
margin-bottom: 3rem;
|
38
|
-
animation: fadeIn 1s ease-in-out;
|
39
38
|
}
|
40
39
|
|
41
40
|
input[type="text"] {
|
@@ -78,7 +77,6 @@
|
|
78
77
|
gap: 1.5rem;
|
79
78
|
max-width: 1600px;
|
80
79
|
margin: auto;
|
81
|
-
animation: fadeInUp 1s ease-in-out;
|
82
80
|
}
|
83
81
|
|
84
82
|
.card {
|
@@ -102,28 +100,6 @@
|
|
102
100
|
object-fit: cover;
|
103
101
|
display: block;
|
104
102
|
}
|
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
103
|
</style>
|
128
104
|
</head>
|
129
105
|
<script>
|
@@ -42,7 +42,7 @@ class VisionEye(BaseSolution):
|
|
42
42
|
Perform object detection, vision mapping, and annotation on the input image.
|
43
43
|
|
44
44
|
Args:
|
45
|
-
im0 (
|
45
|
+
im0 (np.ndarray): The input image for detection and annotation.
|
46
46
|
|
47
47
|
Returns:
|
48
48
|
(SolutionResults): Object containing the annotated image and tracking statistics.
|
ultralytics/utils/benchmarks.py
CHANGED
@@ -520,12 +520,12 @@ class ProfileModels:
|
|
520
520
|
Apply iterative sigma clipping to data to remove outliers.
|
521
521
|
|
522
522
|
Args:
|
523
|
-
data (
|
523
|
+
data (np.ndarray): Input data array.
|
524
524
|
sigma (float): Number of standard deviations to use for clipping.
|
525
525
|
max_iters (int): Maximum number of iterations for the clipping process.
|
526
526
|
|
527
527
|
Returns:
|
528
|
-
(
|
528
|
+
(np.ndarray): Clipped data array with outliers removed.
|
529
529
|
"""
|
530
530
|
data = np.array(data)
|
531
531
|
for _ in range(max_iters):
|
ultralytics/utils/export.py
CHANGED
@@ -135,8 +135,6 @@ def export_engine(
|
|
135
135
|
LOGGER.info(f'{prefix} output "{out.name}" with shape{out.shape} {out.dtype}')
|
136
136
|
|
137
137
|
if dynamic:
|
138
|
-
if shape[0] <= 1:
|
139
|
-
LOGGER.warning(f"{prefix} 'dynamic=True' model requires max batch size, i.e. 'batch=16'")
|
140
138
|
profile = builder.create_optimization_profile()
|
141
139
|
min_shape = (1, shape[1], 32, 32) # minimum input shape
|
142
140
|
max_shape = (*shape[:2], *(int(max(2, workspace or 2) * d) for d in shape[2:])) # max input shape
|