ultralytics 8.3.87__py3-none-any.whl → 8.3.89__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_solutions.py +34 -45
- ultralytics/__init__.py +1 -1
- ultralytics/cfg/__init__.py +46 -39
- ultralytics/data/augment.py +2 -2
- ultralytics/data/base.py +7 -9
- ultralytics/data/converter.py +30 -29
- ultralytics/data/utils.py +20 -28
- ultralytics/engine/model.py +2 -2
- ultralytics/engine/tuner.py +11 -21
- ultralytics/hub/__init__.py +13 -17
- ultralytics/models/fastsam/model.py +4 -7
- ultralytics/models/nas/model.py +8 -14
- ultralytics/models/nas/predict.py +7 -9
- ultralytics/models/nas/val.py +7 -9
- ultralytics/models/rtdetr/predict.py +6 -9
- ultralytics/models/rtdetr/train.py +5 -8
- ultralytics/models/rtdetr/val.py +5 -8
- ultralytics/models/yolo/classify/predict.py +6 -9
- ultralytics/models/yolo/classify/train.py +5 -8
- ultralytics/models/yolo/classify/val.py +5 -8
- ultralytics/models/yolo/detect/predict.py +6 -9
- ultralytics/models/yolo/detect/train.py +5 -8
- ultralytics/models/yolo/detect/val.py +5 -8
- ultralytics/models/yolo/obb/predict.py +6 -9
- ultralytics/models/yolo/obb/train.py +5 -8
- ultralytics/models/yolo/obb/val.py +10 -15
- ultralytics/models/yolo/pose/predict.py +6 -9
- ultralytics/models/yolo/pose/train.py +5 -8
- ultralytics/models/yolo/pose/val.py +12 -17
- ultralytics/models/yolo/segment/predict.py +6 -9
- ultralytics/models/yolo/segment/train.py +5 -8
- ultralytics/models/yolo/segment/val.py +10 -15
- ultralytics/models/yolo/world/train.py +5 -8
- ultralytics/models/yolo/world/train_world.py +21 -25
- ultralytics/nn/modules/__init__.py +9 -12
- ultralytics/nn/tasks.py +7 -12
- ultralytics/solutions/__init__.py +14 -6
- ultralytics/solutions/ai_gym.py +39 -28
- ultralytics/solutions/analytics.py +22 -18
- ultralytics/solutions/distance_calculation.py +25 -25
- ultralytics/solutions/heatmap.py +40 -38
- ultralytics/solutions/instance_segmentation.py +69 -0
- ultralytics/solutions/object_blurrer.py +89 -0
- ultralytics/solutions/object_counter.py +35 -33
- ultralytics/solutions/object_cropper.py +84 -0
- ultralytics/solutions/parking_management.py +21 -9
- ultralytics/solutions/queue_management.py +20 -39
- ultralytics/solutions/region_counter.py +54 -51
- ultralytics/solutions/security_alarm.py +40 -30
- ultralytics/solutions/solutions.py +594 -16
- ultralytics/solutions/speed_estimation.py +34 -31
- ultralytics/solutions/streamlit_inference.py +34 -28
- ultralytics/solutions/trackzone.py +29 -18
- ultralytics/solutions/vision_eye.py +69 -0
- ultralytics/trackers/utils/kalman_filter.py +23 -23
- ultralytics/utils/__init__.py +5 -8
- ultralytics/utils/checks.py +25 -35
- ultralytics/utils/downloads.py +25 -48
- ultralytics/utils/instance.py +9 -11
- ultralytics/utils/ops.py +5 -9
- ultralytics/utils/plotting.py +8 -428
- ultralytics/utils/torch_utils.py +23 -33
- ultralytics/utils/tuner.py +5 -9
- {ultralytics-8.3.87.dist-info → ultralytics-8.3.89.dist-info}/METADATA +2 -2
- {ultralytics-8.3.87.dist-info → ultralytics-8.3.89.dist-info}/RECORD +69 -65
- {ultralytics-8.3.87.dist-info → ultralytics-8.3.89.dist-info}/LICENSE +0 -0
- {ultralytics-8.3.87.dist-info → ultralytics-8.3.89.dist-info}/WHEEL +0 -0
- {ultralytics-8.3.87.dist-info → ultralytics-8.3.89.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.3.87.dist-info → ultralytics-8.3.89.dist-info}/top_level.txt +0 -0
@@ -1,33 +1,33 @@
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
from ultralytics.
|
3
|
+
import numpy as np
|
4
|
+
|
5
|
+
from ultralytics.solutions.solutions import BaseSolution, SolutionAnnotator, SolutionResults
|
6
|
+
from ultralytics.utils.plotting import colors
|
6
7
|
|
7
8
|
|
8
9
|
class RegionCounter(BaseSolution):
|
9
10
|
"""
|
10
|
-
A class
|
11
|
+
A class for real-time counting of objects within user-defined regions in a video stream.
|
11
12
|
|
12
|
-
This class inherits from `BaseSolution` and
|
13
|
-
|
14
|
-
|
13
|
+
This class inherits from `BaseSolution` and provides functionality to define polygonal regions in a video frame,
|
14
|
+
track objects, and count those objects that pass through each defined region. Useful for applications requiring
|
15
|
+
counting in specified areas, such as monitoring zones or segmented sections.
|
15
16
|
|
16
17
|
Attributes:
|
17
|
-
region_template (
|
18
|
-
|
19
|
-
counting_regions (
|
20
|
-
|
18
|
+
region_template (Dict): Template for creating new counting regions with default attributes including name,
|
19
|
+
polygon coordinates, and display colors.
|
20
|
+
counting_regions (List): List storing all defined regions, where each entry is based on `region_template`
|
21
|
+
and includes specific region settings like name, coordinates, and color.
|
22
|
+
region_counts (Dict): Dictionary storing the count of objects for each named region.
|
21
23
|
|
22
24
|
Methods:
|
23
|
-
add_region: Adds a new counting region with specified attributes
|
24
|
-
|
25
|
-
count: Processes video frames to count objects in each region, drawing regions and displaying counts
|
26
|
-
on the frame. Handles object detection, region definition, and containment checks.
|
25
|
+
add_region: Adds a new counting region with specified attributes.
|
26
|
+
process: Processes video frames to count objects in each region.
|
27
27
|
"""
|
28
28
|
|
29
29
|
def __init__(self, **kwargs):
|
30
|
-
"""Initializes the RegionCounter class for real-time counting in different regions of
|
30
|
+
"""Initializes the RegionCounter class for real-time counting in different regions of video streams."""
|
31
31
|
super().__init__(**kwargs)
|
32
32
|
self.region_template = {
|
33
33
|
"name": "Default Region",
|
@@ -37,6 +37,7 @@ class RegionCounter(BaseSolution):
|
|
37
37
|
"region_color": (255, 255, 255),
|
38
38
|
"text_color": (0, 0, 0),
|
39
39
|
}
|
40
|
+
self.region_counts = {}
|
40
41
|
self.counting_regions = []
|
41
42
|
|
42
43
|
def add_region(self, name, polygon_points, region_color, text_color):
|
@@ -45,9 +46,9 @@ class RegionCounter(BaseSolution):
|
|
45
46
|
|
46
47
|
Args:
|
47
48
|
name (str): Name assigned to the new region.
|
48
|
-
polygon_points (
|
49
|
-
region_color (
|
50
|
-
text_color (
|
49
|
+
polygon_points (List[Tuple]): List of (x, y) coordinates defining the region's polygon.
|
50
|
+
region_color (Tuple): BGR color for region visualization.
|
51
|
+
text_color (Tuple): BGR color for the text within the region.
|
51
52
|
"""
|
52
53
|
region = self.region_template.copy()
|
53
54
|
region.update(
|
@@ -60,57 +61,59 @@ class RegionCounter(BaseSolution):
|
|
60
61
|
)
|
61
62
|
self.counting_regions.append(region)
|
62
63
|
|
63
|
-
def
|
64
|
+
def process(self, im0):
|
64
65
|
"""
|
65
66
|
Processes the input frame to detect and count objects within each defined region.
|
66
67
|
|
67
68
|
Args:
|
68
|
-
im0 (
|
69
|
+
im0 (np.ndarray): Input image frame where objects and regions are annotated.
|
69
70
|
|
70
71
|
Returns:
|
71
|
-
|
72
|
+
(SolutionResults): Contains processed image `plot_im`, 'total_tracks' (int, total number of tracked objects),
|
73
|
+
and 'region_counts' (Dict, counts of objects per region).
|
72
74
|
"""
|
73
|
-
self.annotator = Annotator(im0, line_width=self.line_width)
|
74
75
|
self.extract_tracks(im0)
|
76
|
+
annotator = SolutionAnnotator(im0, line_width=self.line_width)
|
77
|
+
|
78
|
+
# Ensure self.region is initialized and structured as a dictionary
|
79
|
+
if not isinstance(self.region, dict):
|
80
|
+
self.region = {"Region#01": self.region or self.initialize_region()}
|
75
81
|
|
76
|
-
#
|
77
|
-
|
78
|
-
self.initialize_region()
|
79
|
-
regions = {"Region#01": self.region}
|
80
|
-
else:
|
81
|
-
regions = self.region if isinstance(self.region, dict) else {"Region#01": self.region}
|
82
|
-
|
83
|
-
# Draw regions and process counts for each defined area
|
84
|
-
for idx, (region_name, reg_pts) in enumerate(regions.items(), start=1):
|
85
|
-
if not isinstance(reg_pts, list) or not all(isinstance(pt, tuple) for pt in reg_pts):
|
86
|
-
LOGGER.warning(f"Invalid region points for {region_name}: {reg_pts}")
|
87
|
-
continue # Skip invalid entries
|
82
|
+
# Draw only valid regions
|
83
|
+
for idx, (region_name, reg_pts) in enumerate(self.region.items(), start=1):
|
88
84
|
color = colors(idx, True)
|
89
|
-
|
90
|
-
self.add_region(region_name, reg_pts, color,
|
85
|
+
annotator.draw_region(reg_pts, color, self.line_width * 2)
|
86
|
+
self.add_region(region_name, reg_pts, color, annotator.get_txt_color())
|
91
87
|
|
92
|
-
# Prepare regions for containment check
|
88
|
+
# Prepare regions for containment check (only process valid ones)
|
93
89
|
for region in self.counting_regions:
|
94
|
-
|
90
|
+
if "prepared_polygon" not in region:
|
91
|
+
region["prepared_polygon"] = self.prep(region["polygon"])
|
92
|
+
|
93
|
+
# Convert bounding boxes to NumPy array for center points
|
94
|
+
boxes_np = np.array([((box[0] + box[2]) / 2, (box[1] + box[3]) / 2) for box in self.boxes], dtype=np.float32)
|
95
|
+
points = [self.Point(pt) for pt in boxes_np] # Convert centers to Point objects
|
95
96
|
|
96
|
-
# Process bounding boxes
|
97
|
-
|
98
|
-
|
99
|
-
|
97
|
+
# Process bounding boxes & check containment
|
98
|
+
if points:
|
99
|
+
for (point, cls), box in zip(zip(points, self.clss), self.boxes):
|
100
|
+
annotator.box_label(box, label=self.names[cls], color=colors(cls))
|
100
101
|
|
101
|
-
|
102
|
-
|
103
|
-
|
102
|
+
for region in self.counting_regions:
|
103
|
+
if region["prepared_polygon"].contains(point):
|
104
|
+
region["counts"] += 1
|
105
|
+
self.region_counts[region["name"]] = region["counts"]
|
104
106
|
|
105
|
-
# Display counts
|
107
|
+
# Display region counts
|
106
108
|
for region in self.counting_regions:
|
107
|
-
|
109
|
+
annotator.text_label(
|
108
110
|
region["polygon"].bounds,
|
109
111
|
label=str(region["counts"]),
|
110
112
|
color=region["region_color"],
|
111
113
|
txt_color=region["text_color"],
|
112
114
|
)
|
113
|
-
region["counts"] = 0 # Reset
|
115
|
+
region["counts"] = 0 # Reset for next frame
|
116
|
+
plot_im = annotator.result()
|
117
|
+
self.display_output(plot_im)
|
114
118
|
|
115
|
-
self.
|
116
|
-
return im0
|
119
|
+
return SolutionResults(plot_im=plot_im, total_tracks=len(self.track_ids), region_counts=self.region_counts)
|
@@ -1,36 +1,44 @@
|
|
1
1
|
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
2
|
|
3
|
-
from ultralytics.solutions.solutions import BaseSolution
|
3
|
+
from ultralytics.solutions.solutions import BaseSolution, SolutionAnnotator, SolutionResults
|
4
4
|
from ultralytics.utils import LOGGER
|
5
|
-
from ultralytics.utils.plotting import
|
5
|
+
from ultralytics.utils.plotting import colors
|
6
6
|
|
7
7
|
|
8
8
|
class SecurityAlarm(BaseSolution):
|
9
9
|
"""
|
10
10
|
A class to manage security alarm functionalities for real-time monitoring.
|
11
11
|
|
12
|
-
This class extends the BaseSolution class and provides features to monitor
|
13
|
-
|
14
|
-
|
12
|
+
This class extends the BaseSolution class and provides features to monitor objects in a frame, send email
|
13
|
+
notifications when specific thresholds are exceeded for total detections, and annotate the output frame for
|
14
|
+
visualization.
|
15
15
|
|
16
16
|
Attributes:
|
17
|
-
|
18
|
-
|
17
|
+
email_sent (bool): Flag to track if an email has already been sent for the current event.
|
18
|
+
records (int): Threshold for the number of detected objects to trigger an alert.
|
19
|
+
server (smtplib.SMTP): SMTP server connection for sending email alerts.
|
20
|
+
to_email (str): Recipient's email address for alerts.
|
21
|
+
from_email (str): Sender's email address for alerts.
|
19
22
|
|
20
23
|
Methods:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
authenticate: Sets up email server authentication for sending alerts.
|
25
|
+
send_email: Sends an email notification with details and an image attachment.
|
26
|
+
process: Monitors the frame, processes detections, and triggers alerts if thresholds are crossed.
|
24
27
|
|
25
28
|
Examples:
|
26
29
|
>>> security = SecurityAlarm()
|
27
30
|
>>> security.authenticate("abc@gmail.com", "1111222233334444", "xyz@gmail.com")
|
28
31
|
>>> frame = cv2.imread("frame.jpg")
|
29
|
-
>>>
|
32
|
+
>>> results = security.process(frame)
|
30
33
|
"""
|
31
34
|
|
32
35
|
def __init__(self, **kwargs):
|
33
|
-
"""
|
36
|
+
"""
|
37
|
+
Initializes the SecurityAlarm class with parameters for real-time object monitoring.
|
38
|
+
|
39
|
+
Args:
|
40
|
+
**kwargs (Any): Additional keyword arguments passed to the parent class.
|
41
|
+
"""
|
34
42
|
super().__init__(**kwargs)
|
35
43
|
self.email_sent = False
|
36
44
|
self.records = self.CFG["records"]
|
@@ -47,8 +55,7 @@ class SecurityAlarm(BaseSolution):
|
|
47
55
|
password (str): Password for the sender's email account.
|
48
56
|
to_email (str): Recipient's email address.
|
49
57
|
|
50
|
-
This method initializes a secure connection with the SMTP server
|
51
|
-
and logs in using the provided credentials.
|
58
|
+
This method initializes a secure connection with the SMTP server and logs in using the provided credentials.
|
52
59
|
|
53
60
|
Examples:
|
54
61
|
>>> alarm = SecurityAlarm()
|
@@ -70,8 +77,8 @@ class SecurityAlarm(BaseSolution):
|
|
70
77
|
im0 (numpy.ndarray): The input image or frame to be attached to the email.
|
71
78
|
records (int): The number of detected objects to be included in the email message.
|
72
79
|
|
73
|
-
This method encodes the input image, composes the email message with
|
74
|
-
|
80
|
+
This method encodes the input image, composes the email message with details about the detection, and sends it
|
81
|
+
to the specified recipient.
|
75
82
|
|
76
83
|
Examples:
|
77
84
|
>>> alarm = SecurityAlarm()
|
@@ -105,40 +112,43 @@ class SecurityAlarm(BaseSolution):
|
|
105
112
|
self.server.send_message(message)
|
106
113
|
LOGGER.info("✅ Email sent successfully!")
|
107
114
|
except Exception as e:
|
108
|
-
|
115
|
+
LOGGER.error(f"❌ Failed to send email: {e}")
|
109
116
|
|
110
|
-
def
|
117
|
+
def process(self, im0):
|
111
118
|
"""
|
112
119
|
Monitors the frame, processes object detections, and triggers alerts if thresholds are exceeded.
|
113
120
|
|
114
121
|
Args:
|
115
122
|
im0 (numpy.ndarray): The input image or frame to be processed and annotated.
|
116
123
|
|
117
|
-
This method processes the input frame, extracts detections, annotates the frame
|
118
|
-
with bounding boxes, and sends an email notification if the number of detected objects
|
119
|
-
surpasses the specified threshold and an alert has not already been sent.
|
120
|
-
|
121
124
|
Returns:
|
122
|
-
(
|
125
|
+
(SolutionResults): Contains processed image `plot_im`, 'total_tracks' (total number of tracked objects) and
|
126
|
+
'email_sent' (whether an email alert was triggered).
|
127
|
+
|
128
|
+
This method processes the input frame, extracts detections, annotates the frame with bounding boxes, and sends
|
129
|
+
an email notification if the number of detected objects surpasses the specified threshold and an alert has not
|
130
|
+
already been sent.
|
123
131
|
|
124
132
|
Examples:
|
125
133
|
>>> alarm = SecurityAlarm()
|
126
134
|
>>> frame = cv2.imread("path/to/image.jpg")
|
127
|
-
>>>
|
135
|
+
>>> results = alarm.process(frame)
|
128
136
|
"""
|
129
|
-
self.annotator = Annotator(im0, line_width=self.line_width) # Initialize annotator
|
130
137
|
self.extract_tracks(im0) # Extract tracks
|
138
|
+
annotator = SolutionAnnotator(im0, line_width=self.line_width) # Initialize annotator
|
131
139
|
|
132
|
-
# Iterate over bounding boxes
|
140
|
+
# Iterate over bounding boxes and classes index
|
133
141
|
for box, cls in zip(self.boxes, self.clss):
|
134
142
|
# Draw bounding box
|
135
|
-
|
143
|
+
annotator.box_label(box, label=self.names[cls], color=colors(cls, True))
|
136
144
|
|
137
145
|
total_det = len(self.clss)
|
138
|
-
if total_det > self.records and not self.email_sent: # Only send email
|
146
|
+
if total_det > self.records and not self.email_sent: # Only send email if not sent before
|
139
147
|
self.send_email(im0, total_det)
|
140
148
|
self.email_sent = True
|
141
149
|
|
142
|
-
|
150
|
+
plot_im = annotator.result()
|
151
|
+
self.display_output(plot_im) # Display output with base class function
|
143
152
|
|
144
|
-
|
153
|
+
# Return a SolutionResults
|
154
|
+
return SolutionResults(plot_im=plot_im, total_tracks=len(self.track_ids), email_sent=self.email_sent)
|