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
@@ -4,8 +4,8 @@ from time import time
|
|
4
4
|
|
5
5
|
import numpy as np
|
6
6
|
|
7
|
-
from ultralytics.solutions.solutions import BaseSolution
|
8
|
-
from ultralytics.utils.plotting import
|
7
|
+
from ultralytics.solutions.solutions import BaseSolution, SolutionAnnotator, SolutionResults
|
8
|
+
from ultralytics.utils.plotting import colors
|
9
9
|
|
10
10
|
|
11
11
|
class SpeedEstimator(BaseSolution):
|
@@ -20,14 +20,13 @@ class SpeedEstimator(BaseSolution):
|
|
20
20
|
trkd_ids (List[int]): List of tracked object IDs that have already been speed-estimated.
|
21
21
|
trk_pt (Dict[int, float]): Dictionary storing previous timestamps for tracked objects.
|
22
22
|
trk_pp (Dict[int, Tuple[float, float]]): Dictionary storing previous positions for tracked objects.
|
23
|
-
annotator (Annotator): Annotator object for drawing on images.
|
24
23
|
region (List[Tuple[int, int]]): List of points defining the speed estimation region.
|
25
24
|
track_line (List[Tuple[float, float]]): List of points representing the object's track.
|
26
25
|
r_s (LineString): LineString object representing the speed estimation region.
|
27
26
|
|
28
27
|
Methods:
|
29
28
|
initialize_region: Initializes the speed estimation region.
|
30
|
-
|
29
|
+
process: Processes input frames to estimate object speeds.
|
31
30
|
store_tracking_history: Stores the tracking history for an object.
|
32
31
|
extract_tracks: Extracts tracks from the current frame.
|
33
32
|
display_output: Displays the output with annotations.
|
@@ -35,76 +34,80 @@ class SpeedEstimator(BaseSolution):
|
|
35
34
|
Examples:
|
36
35
|
>>> estimator = SpeedEstimator()
|
37
36
|
>>> frame = cv2.imread("frame.jpg")
|
38
|
-
>>>
|
39
|
-
>>> cv2.imshow("Speed Estimation",
|
37
|
+
>>> results = estimator.process(frame)
|
38
|
+
>>> cv2.imshow("Speed Estimation", results.plot_im)
|
40
39
|
"""
|
41
40
|
|
42
41
|
def __init__(self, **kwargs):
|
43
|
-
"""
|
42
|
+
"""
|
43
|
+
Initializes the SpeedEstimator object with speed estimation parameters and data structures.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
**kwargs (Any): Additional keyword arguments passed to the parent class.
|
47
|
+
"""
|
44
48
|
super().__init__(**kwargs)
|
45
49
|
|
46
50
|
self.initialize_region() # Initialize speed region
|
47
51
|
|
48
|
-
self.spd = {} #
|
49
|
-
self.trkd_ids = [] #
|
50
|
-
self.trk_pt = {} #
|
51
|
-
self.trk_pp = {} #
|
52
|
+
self.spd = {} # Dictionary for speed data
|
53
|
+
self.trkd_ids = [] # List for already speed-estimated and tracked IDs
|
54
|
+
self.trk_pt = {} # Dictionary for tracks' previous timestamps
|
55
|
+
self.trk_pp = {} # Dictionary for tracks' previous positions
|
52
56
|
|
53
|
-
def
|
57
|
+
def process(self, im0):
|
54
58
|
"""
|
55
|
-
|
59
|
+
Processes an input frame to estimate object speeds based on tracking data.
|
56
60
|
|
57
61
|
Args:
|
58
|
-
im0 (np.ndarray): Input image for processing
|
62
|
+
im0 (np.ndarray): Input image for processing with shape (H, W, C) for RGB images.
|
59
63
|
|
60
64
|
Returns:
|
61
|
-
(
|
65
|
+
(SolutionResults): Contains processed image `plot_im` and `total_tracks` (number of tracked objects).
|
62
66
|
|
63
67
|
Examples:
|
64
68
|
>>> estimator = SpeedEstimator()
|
65
69
|
>>> image = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)
|
66
|
-
>>>
|
70
|
+
>>> results = estimator.process(image)
|
67
71
|
"""
|
68
|
-
self.annotator = Annotator(im0, line_width=self.line_width) # Initialize annotator
|
69
72
|
self.extract_tracks(im0) # Extract tracks
|
73
|
+
annotator = SolutionAnnotator(im0, line_width=self.line_width) # Initialize annotator
|
70
74
|
|
71
|
-
|
72
|
-
|
73
|
-
) # Draw region
|
75
|
+
# Draw speed estimation region
|
76
|
+
annotator.draw_region(reg_pts=self.region, color=(104, 0, 123), thickness=self.line_width * 2)
|
74
77
|
|
75
78
|
for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
|
76
79
|
self.store_tracking_history(track_id, box) # Store track history
|
77
80
|
|
78
|
-
#
|
81
|
+
# Initialize tracking data for new objects
|
79
82
|
if track_id not in self.trk_pt:
|
80
83
|
self.trk_pt[track_id] = 0
|
81
84
|
if track_id not in self.trk_pp:
|
82
85
|
self.trk_pp[track_id] = self.track_line[-1]
|
83
86
|
|
87
|
+
# Prepare label with speed if available, otherwise use class name
|
84
88
|
speed_label = f"{int(self.spd[track_id])} km/h" if track_id in self.spd else self.names[int(cls)]
|
85
|
-
|
86
|
-
|
87
|
-
# Draw tracks of objects
|
88
|
-
self.annotator.draw_centroid_and_tracks(
|
89
|
-
self.track_line, color=colors(int(track_id), True), track_thickness=self.line_width
|
90
|
-
)
|
89
|
+
annotator.box_label(box, label=speed_label, color=colors(track_id, True)) # Draw bounding box
|
91
90
|
|
92
|
-
#
|
91
|
+
# Determine if object is crossing the speed estimation region
|
93
92
|
if self.LineString([self.trk_pp[track_id], self.track_line[-1]]).intersects(self.r_s):
|
94
93
|
direction = "known"
|
95
94
|
else:
|
96
95
|
direction = "unknown"
|
97
96
|
|
98
|
-
#
|
97
|
+
# Calculate speed for objects crossing the region for the first time
|
99
98
|
if direction == "known" and track_id not in self.trkd_ids:
|
100
99
|
self.trkd_ids.append(track_id)
|
101
100
|
time_difference = time() - self.trk_pt[track_id]
|
102
101
|
if time_difference > 0:
|
102
|
+
# Calculate speed based on vertical displacement and time
|
103
103
|
self.spd[track_id] = np.abs(self.track_line[-1][1] - self.trk_pp[track_id][1]) / time_difference
|
104
104
|
|
105
|
+
# Update tracking data for next frame
|
105
106
|
self.trk_pt[track_id] = time()
|
106
107
|
self.trk_pp[track_id] = self.track_line[-1]
|
107
108
|
|
108
|
-
|
109
|
+
plot_im = annotator.result()
|
110
|
+
self.display_output(plot_im) # Display output with base class function
|
109
111
|
|
110
|
-
|
112
|
+
# Return results with processed image and tracking summary
|
113
|
+
return SolutionResults(plot_im=plot_im, total_tracks=len(self.track_ids))
|
@@ -13,21 +13,24 @@ from ultralytics.utils.downloads import GITHUB_ASSETS_STEMS
|
|
13
13
|
|
14
14
|
class Inference:
|
15
15
|
"""
|
16
|
-
A class to perform object detection, image classification, image segmentation and pose estimation inference
|
17
|
-
|
18
|
-
uploading video files, and performing
|
16
|
+
A class to perform object detection, image classification, image segmentation and pose estimation inference.
|
17
|
+
|
18
|
+
This class provides functionalities for loading models, configuring settings, uploading video files, and performing
|
19
|
+
real-time inference using Streamlit and Ultralytics YOLO models.
|
19
20
|
|
20
21
|
Attributes:
|
21
22
|
st (module): Streamlit module for UI creation.
|
22
|
-
temp_dict (
|
23
|
+
temp_dict (Dict): Temporary dictionary to store the model path and other configuration.
|
23
24
|
model_path (str): Path to the loaded model.
|
24
25
|
model (YOLO): The YOLO model instance.
|
25
|
-
source (str): Selected video source.
|
26
|
-
enable_trk (str): Enable tracking option.
|
27
|
-
conf (float): Confidence threshold.
|
28
|
-
iou (float): IoU threshold for non-
|
29
|
-
|
30
|
-
|
26
|
+
source (str): Selected video source (webcam or video file).
|
27
|
+
enable_trk (str): Enable tracking option ("Yes" or "No").
|
28
|
+
conf (float): Confidence threshold for detection.
|
29
|
+
iou (float): IoU threshold for non-maximum suppression.
|
30
|
+
org_frame (Any): Container for the original frame to be displayed.
|
31
|
+
ann_frame (Any): Container for the annotated frame to be displayed.
|
32
|
+
vid_file_name (Union[str, int]): Name of the uploaded video file or webcam index.
|
33
|
+
selected_ind (List[int]): List of selected class indices for detection.
|
31
34
|
|
32
35
|
Methods:
|
33
36
|
web_ui: Sets up the Streamlit web interface with custom HTML elements.
|
@@ -37,7 +40,7 @@ class Inference:
|
|
37
40
|
inference: Performs real-time object detection inference.
|
38
41
|
|
39
42
|
Examples:
|
40
|
-
>>> inf =
|
43
|
+
>>> inf = Inference(model="path/to/model.pt") # Model is an optional argument
|
41
44
|
>>> inf.inference()
|
42
45
|
"""
|
43
46
|
|
@@ -51,19 +54,19 @@ class Inference:
|
|
51
54
|
check_requirements("streamlit>=1.29.0") # scope imports for faster ultralytics package load speeds
|
52
55
|
import streamlit as st
|
53
56
|
|
54
|
-
self.st = st # Reference to the Streamlit
|
55
|
-
self.source = None #
|
57
|
+
self.st = st # Reference to the Streamlit module
|
58
|
+
self.source = None # Video source selection (webcam or video file)
|
56
59
|
self.enable_trk = False # Flag to toggle object tracking
|
57
60
|
self.conf = 0.25 # Confidence threshold for detection
|
58
61
|
self.iou = 0.45 # Intersection-over-Union (IoU) threshold for non-maximum suppression
|
59
|
-
self.org_frame = None # Container for the original frame
|
60
|
-
self.ann_frame = None # Container for the annotated frame
|
61
|
-
self.vid_file_name = None #
|
62
|
-
self.selected_ind = [] # List of selected
|
63
|
-
self.model = None #
|
62
|
+
self.org_frame = None # Container for the original frame display
|
63
|
+
self.ann_frame = None # Container for the annotated frame display
|
64
|
+
self.vid_file_name = None # Video file name or webcam index
|
65
|
+
self.selected_ind = [] # List of selected class indices for detection
|
66
|
+
self.model = None # YOLO model instance
|
64
67
|
|
65
68
|
self.temp_dict = {"model": None, **kwargs}
|
66
|
-
self.model_path = None #
|
69
|
+
self.model_path = None # Model file path
|
67
70
|
if self.temp_dict["model"] is not None:
|
68
71
|
self.model_path = self.temp_dict["model"]
|
69
72
|
|
@@ -105,9 +108,9 @@ class Inference:
|
|
105
108
|
) # Slider for confidence
|
106
109
|
self.iou = float(self.st.sidebar.slider("IoU Threshold", 0.0, 1.0, self.iou, 0.01)) # Slider for NMS threshold
|
107
110
|
|
108
|
-
col1, col2 = self.st.columns(2)
|
109
|
-
self.org_frame = col1.empty()
|
110
|
-
self.ann_frame = col2.empty()
|
111
|
+
col1, col2 = self.st.columns(2) # Create two columns for displaying frames
|
112
|
+
self.org_frame = col1.empty() # Container for original frame
|
113
|
+
self.ann_frame = col2.empty() # Container for annotated frame
|
111
114
|
|
112
115
|
def source_upload(self):
|
113
116
|
"""Handles video file uploads through the Streamlit interface."""
|
@@ -120,7 +123,7 @@ class Inference:
|
|
120
123
|
out.write(g.read()) # Read bytes into file
|
121
124
|
self.vid_file_name = "ultralytics.mp4"
|
122
125
|
elif self.source == "webcam":
|
123
|
-
self.vid_file_name = 0
|
126
|
+
self.vid_file_name = 0 # Use webcam index 0
|
124
127
|
|
125
128
|
def configure(self):
|
126
129
|
"""Configures the model and loads selected classes for inference."""
|
@@ -143,7 +146,7 @@ class Inference:
|
|
143
146
|
self.selected_ind = list(self.selected_ind)
|
144
147
|
|
145
148
|
def inference(self):
|
146
|
-
"""Performs real-time object detection inference."""
|
149
|
+
"""Performs real-time object detection inference on video or webcam feed."""
|
147
150
|
self.web_ui() # Initialize the web interface
|
148
151
|
self.sidebar() # Create the sidebar
|
149
152
|
self.source_upload() # Upload the video source
|
@@ -153,20 +156,23 @@ class Inference:
|
|
153
156
|
stop_button = self.st.button("Stop") # Button to stop the inference
|
154
157
|
cap = cv2.VideoCapture(self.vid_file_name) # Capture the video
|
155
158
|
if not cap.isOpened():
|
156
|
-
self.st.error("Could not open webcam.")
|
159
|
+
self.st.error("Could not open webcam or video source.")
|
160
|
+
return
|
161
|
+
|
157
162
|
while cap.isOpened():
|
158
163
|
success, frame = cap.read()
|
159
164
|
if not success:
|
160
165
|
self.st.warning("Failed to read frame from webcam. Please verify the webcam is connected properly.")
|
161
166
|
break
|
162
167
|
|
163
|
-
#
|
168
|
+
# Process frame with model
|
164
169
|
if self.enable_trk == "Yes":
|
165
170
|
results = self.model.track(
|
166
171
|
frame, conf=self.conf, iou=self.iou, classes=self.selected_ind, persist=True
|
167
172
|
)
|
168
173
|
else:
|
169
174
|
results = self.model(frame, conf=self.conf, iou=self.iou, classes=self.selected_ind)
|
175
|
+
|
170
176
|
annotated_frame = results[0].plot() # Add annotations on frame
|
171
177
|
|
172
178
|
if stop_button:
|
@@ -177,7 +183,7 @@ class Inference:
|
|
177
183
|
self.ann_frame.image(annotated_frame, channels="BGR") # Display processed frame
|
178
184
|
|
179
185
|
cap.release() # Release the capture
|
180
|
-
cv2.destroyAllWindows() # Destroy
|
186
|
+
cv2.destroyAllWindows() # Destroy all OpenCV windows
|
181
187
|
|
182
188
|
|
183
189
|
if __name__ == "__main__":
|
@@ -185,6 +191,6 @@ if __name__ == "__main__":
|
|
185
191
|
|
186
192
|
# Check if a model name is provided as a command-line argument
|
187
193
|
args = len(sys.argv)
|
188
|
-
model = sys.argv[1] if args > 1 else None #
|
194
|
+
model = sys.argv[1] if args > 1 else None # Assign first argument as the model name if provided
|
189
195
|
# Create an instance of the Inference class and run inference
|
190
196
|
Inference(model=model).inference()
|
@@ -3,8 +3,8 @@
|
|
3
3
|
import cv2
|
4
4
|
import numpy as np
|
5
5
|
|
6
|
-
from ultralytics.solutions.solutions import BaseSolution
|
7
|
-
from ultralytics.utils.plotting import
|
6
|
+
from ultralytics.solutions.solutions import BaseSolution, SolutionAnnotator, SolutionResults
|
7
|
+
from ultralytics.utils.plotting import colors
|
8
8
|
|
9
9
|
|
10
10
|
class TrackZone(BaseSolution):
|
@@ -12,29 +12,33 @@ class TrackZone(BaseSolution):
|
|
12
12
|
A class to manage region-based object tracking in a video stream.
|
13
13
|
|
14
14
|
This class extends the BaseSolution class and provides functionality for tracking objects within a specific region
|
15
|
-
defined by a polygonal area. Objects outside the region are excluded from tracking.
|
16
|
-
of the region, allowing either a default region or a user-specified polygon.
|
15
|
+
defined by a polygonal area. Objects outside the region are excluded from tracking.
|
17
16
|
|
18
17
|
Attributes:
|
19
|
-
region (ndarray): The polygonal region for tracking, represented as a convex hull.
|
18
|
+
region (np.ndarray): The polygonal region for tracking, represented as a convex hull of points.
|
20
19
|
|
21
20
|
Methods:
|
22
|
-
|
21
|
+
process: Processes each frame of the video, applying region-based tracking.
|
23
22
|
|
24
23
|
Examples:
|
25
24
|
>>> tracker = TrackZone()
|
26
25
|
>>> frame = cv2.imread("frame.jpg")
|
27
|
-
>>>
|
28
|
-
>>> cv2.imshow("Tracked Frame",
|
26
|
+
>>> results = tracker.process(frame)
|
27
|
+
>>> cv2.imshow("Tracked Frame", results.plot_im)
|
29
28
|
"""
|
30
29
|
|
31
30
|
def __init__(self, **kwargs):
|
32
|
-
"""
|
31
|
+
"""
|
32
|
+
Initializes the TrackZone class for tracking objects within a defined region in video streams.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
**kwargs (Any): Additional keyword arguments passed to the parent class.
|
36
|
+
"""
|
33
37
|
super().__init__(**kwargs)
|
34
38
|
default_region = [(150, 150), (1130, 150), (1130, 570), (150, 570)]
|
35
39
|
self.region = cv2.convexHull(np.array(self.region or default_region, dtype=np.int32))
|
36
40
|
|
37
|
-
def
|
41
|
+
def process(self, im0):
|
38
42
|
"""
|
39
43
|
Processes the input frame to track objects within a defined region.
|
40
44
|
|
@@ -42,27 +46,34 @@ class TrackZone(BaseSolution):
|
|
42
46
|
only from the masked area, and updates tracking information. Objects outside the region are ignored.
|
43
47
|
|
44
48
|
Args:
|
45
|
-
im0 (
|
49
|
+
im0 (np.ndarray): The input image or frame to be processed.
|
46
50
|
|
47
51
|
Returns:
|
48
|
-
(
|
52
|
+
(SolutionResults): Contains processed image `plot_im` and `total_tracks` (int) representing the
|
53
|
+
total number of tracked objects within the defined region.
|
49
54
|
|
50
55
|
Examples:
|
51
56
|
>>> tracker = TrackZone()
|
52
57
|
>>> frame = cv2.imread("path/to/image.jpg")
|
53
|
-
>>> tracker.
|
58
|
+
>>> results = tracker.process(frame)
|
54
59
|
"""
|
55
|
-
|
60
|
+
annotator = SolutionAnnotator(im0, line_width=self.line_width) # Initialize annotator
|
61
|
+
|
56
62
|
# Create a mask for the region and extract tracks from the masked image
|
57
|
-
|
63
|
+
mask = np.zeros_like(im0[:, :, 0])
|
64
|
+
mask = cv2.fillPoly(mask, [self.region], 255)
|
65
|
+
masked_frame = cv2.bitwise_and(im0, im0, mask=mask)
|
58
66
|
self.extract_tracks(masked_frame)
|
59
67
|
|
68
|
+
# Draw the region boundary
|
60
69
|
cv2.polylines(im0, [self.region], isClosed=True, color=(255, 255, 255), thickness=self.line_width * 2)
|
61
70
|
|
62
71
|
# Iterate over boxes, track ids, classes indexes list and draw bounding boxes
|
63
72
|
for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
|
64
|
-
|
73
|
+
annotator.box_label(box, label=f"{self.names[cls]}:{track_id}", color=colors(track_id, True))
|
65
74
|
|
66
|
-
|
75
|
+
plot_im = annotator.result()
|
76
|
+
self.display_output(plot_im) # display output with base class function
|
67
77
|
|
68
|
-
|
78
|
+
# Return a SolutionResults
|
79
|
+
return SolutionResults(plot_im=plot_im, total_tracks=len(self.track_ids))
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
|
+
|
3
|
+
|
4
|
+
from ultralytics.solutions.solutions import BaseSolution, SolutionAnnotator, SolutionResults
|
5
|
+
from ultralytics.utils.plotting import colors
|
6
|
+
|
7
|
+
|
8
|
+
class VisionEye(BaseSolution):
|
9
|
+
"""
|
10
|
+
A class to manage object detection and vision mapping in images or video streams.
|
11
|
+
|
12
|
+
This class extends the BaseSolution class and provides functionality for detecting objects,
|
13
|
+
mapping vision points, and annotating results with bounding boxes and labels.
|
14
|
+
|
15
|
+
Attributes:
|
16
|
+
vision_point (Tuple[int, int]): Coordinates where vision will view objects and draw tracks, default is (30, 30).
|
17
|
+
|
18
|
+
Methods:
|
19
|
+
process: Processes the input image to detect objects, annotate them, and apply vision mapping.
|
20
|
+
|
21
|
+
Examples:
|
22
|
+
>>> vision_eye = VisionEye()
|
23
|
+
>>> frame = cv2.imread("frame.jpg")
|
24
|
+
>>> results = vision_eye.process(frame)
|
25
|
+
>>> print(f"Total detected instances: {results.total_tracks}")
|
26
|
+
"""
|
27
|
+
|
28
|
+
def __init__(self, **kwargs):
|
29
|
+
"""
|
30
|
+
Initializes the VisionEye class for detecting objects and applying vision mapping.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
**kwargs (Any): Keyword arguments passed to the parent class and for configuring vision_point.
|
34
|
+
"""
|
35
|
+
super().__init__(**kwargs)
|
36
|
+
# Set the vision point where the system will view objects and draw tracks
|
37
|
+
self.vision_point = kwargs.get("vision_point", (30, 30))
|
38
|
+
|
39
|
+
def process(self, im0):
|
40
|
+
"""
|
41
|
+
Performs object detection, vision mapping, and annotation on the input image.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
im0 (numpy.ndarray): The input image for detection and annotation.
|
45
|
+
|
46
|
+
Returns:
|
47
|
+
(SolutionResults): Object containing the annotated image and tracking statistics.
|
48
|
+
- plot_im: Annotated output image with bounding boxes and vision mapping
|
49
|
+
- total_tracks: Number of tracked objects in the frame
|
50
|
+
|
51
|
+
Examples:
|
52
|
+
>>> vision_eye = VisionEye()
|
53
|
+
>>> frame = cv2.imread("image.jpg")
|
54
|
+
>>> results = vision_eye.process(frame)
|
55
|
+
>>> print(f"Detected {results.total_tracks} objects")
|
56
|
+
"""
|
57
|
+
self.extract_tracks(im0) # Extract tracks (bounding boxes, classes, and masks)
|
58
|
+
annotator = SolutionAnnotator(im0, self.line_width)
|
59
|
+
|
60
|
+
for cls, t_id, box in zip(self.clss, self.track_ids, self.boxes):
|
61
|
+
# Annotate the image with bounding boxes, labels, and vision mapping
|
62
|
+
annotator.box_label(box, label=self.names[cls], color=colors(int(t_id), True))
|
63
|
+
annotator.visioneye(box, self.vision_point)
|
64
|
+
|
65
|
+
plot_im = annotator.result()
|
66
|
+
self.display_output(plot_im) # Display the annotated output using the base class function
|
67
|
+
|
68
|
+
# Return a SolutionResults object with the annotated image and tracking statistics
|
69
|
+
return SolutionResults(plot_im=plot_im, total_tracks=len(self.track_ids))
|
@@ -67,7 +67,7 @@ class KalmanFilterXYAH:
|
|
67
67
|
Create a track from an unassociated measurement.
|
68
68
|
|
69
69
|
Args:
|
70
|
-
measurement (ndarray): Bounding box coordinates (x, y, a, h) with center position (x, y), aspect ratio a,
|
70
|
+
measurement (np.ndarray): Bounding box coordinates (x, y, a, h) with center position (x, y), aspect ratio a,
|
71
71
|
and height h.
|
72
72
|
|
73
73
|
Returns:
|
@@ -101,8 +101,8 @@ class KalmanFilterXYAH:
|
|
101
101
|
Run Kalman filter prediction step.
|
102
102
|
|
103
103
|
Args:
|
104
|
-
mean (ndarray): The 8-dimensional mean vector of the object state at the previous time step.
|
105
|
-
covariance (ndarray): The 8x8-dimensional covariance matrix of the object state at the previous time step.
|
104
|
+
mean (np.ndarray): The 8-dimensional mean vector of the object state at the previous time step.
|
105
|
+
covariance (np.ndarray): The 8x8-dimensional covariance matrix of the object state at the previous time step.
|
106
106
|
|
107
107
|
Returns:
|
108
108
|
(tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
|
@@ -138,8 +138,8 @@ class KalmanFilterXYAH:
|
|
138
138
|
Project state distribution to measurement space.
|
139
139
|
|
140
140
|
Args:
|
141
|
-
mean (ndarray): The state's mean vector (8 dimensional array).
|
142
|
-
covariance (ndarray): The state's covariance matrix (8x8 dimensional).
|
141
|
+
mean (np.ndarray): The state's mean vector (8 dimensional array).
|
142
|
+
covariance (np.ndarray): The state's covariance matrix (8x8 dimensional).
|
143
143
|
|
144
144
|
Returns:
|
145
145
|
(tuple[ndarray, ndarray]): Returns the projected mean and covariance matrix of the given state estimate.
|
@@ -167,8 +167,8 @@ class KalmanFilterXYAH:
|
|
167
167
|
Run Kalman filter prediction step for multiple object states (Vectorized version).
|
168
168
|
|
169
169
|
Args:
|
170
|
-
mean (ndarray): The Nx8 dimensional mean matrix of the object states at the previous time step.
|
171
|
-
covariance (ndarray): The Nx8x8 covariance matrix of the object states at the previous time step.
|
170
|
+
mean (np.ndarray): The Nx8 dimensional mean matrix of the object states at the previous time step.
|
171
|
+
covariance (np.ndarray): The Nx8x8 covariance matrix of the object states at the previous time step.
|
172
172
|
|
173
173
|
Returns:
|
174
174
|
(tuple[ndarray, ndarray]): Returns the mean matrix and covariance matrix of the predicted states.
|
@@ -208,9 +208,9 @@ class KalmanFilterXYAH:
|
|
208
208
|
Run Kalman filter correction step.
|
209
209
|
|
210
210
|
Args:
|
211
|
-
mean (ndarray): The predicted state's mean vector (8 dimensional).
|
212
|
-
covariance (ndarray): The state's covariance matrix (8x8 dimensional).
|
213
|
-
measurement (ndarray): The 4 dimensional measurement vector (x, y, a, h), where (x, y) is the center
|
211
|
+
mean (np.ndarray): The predicted state's mean vector (8 dimensional).
|
212
|
+
covariance (np.ndarray): The state's covariance matrix (8x8 dimensional).
|
213
|
+
measurement (np.ndarray): The 4 dimensional measurement vector (x, y, a, h), where (x, y) is the center
|
214
214
|
position, a the aspect ratio, and h the height of the bounding box.
|
215
215
|
|
216
216
|
Returns:
|
@@ -250,9 +250,9 @@ class KalmanFilterXYAH:
|
|
250
250
|
distribution has 4 degrees of freedom, otherwise 2.
|
251
251
|
|
252
252
|
Args:
|
253
|
-
mean (ndarray): Mean vector over the state distribution (8 dimensional).
|
254
|
-
covariance (ndarray): Covariance of the state distribution (8x8 dimensional).
|
255
|
-
measurements (ndarray): An (N, 4) matrix of N measurements, each in format (x, y, a, h) where (x, y) is the
|
253
|
+
mean (np.ndarray): Mean vector over the state distribution (8 dimensional).
|
254
|
+
covariance (np.ndarray): Covariance of the state distribution (8x8 dimensional).
|
255
|
+
measurements (np.ndarray): An (N, 4) matrix of N measurements, each in format (x, y, a, h) where (x, y) is the
|
256
256
|
bounding box center position, a the aspect ratio, and h the height.
|
257
257
|
only_position (bool): If True, distance computation is done with respect to box center position only.
|
258
258
|
metric (str): The metric to use for calculating the distance. Options are 'gaussian' for the squared
|
@@ -322,7 +322,7 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
322
322
|
Create track from unassociated measurement.
|
323
323
|
|
324
324
|
Args:
|
325
|
-
measurement (ndarray): Bounding box coordinates (x, y, w, h) with center position (x, y), width, and height.
|
325
|
+
measurement (np.ndarray): Bounding box coordinates (x, y, w, h) with center position (x, y), width, and height.
|
326
326
|
|
327
327
|
Returns:
|
328
328
|
(tuple[ndarray, ndarray]): Returns the mean vector (8 dimensional) and covariance matrix (8x8 dimensional)
|
@@ -366,8 +366,8 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
366
366
|
Run Kalman filter prediction step.
|
367
367
|
|
368
368
|
Args:
|
369
|
-
mean (ndarray): The 8-dimensional mean vector of the object state at the previous time step.
|
370
|
-
covariance (ndarray): The 8x8-dimensional covariance matrix of the object state at the previous time step.
|
369
|
+
mean (np.ndarray): The 8-dimensional mean vector of the object state at the previous time step.
|
370
|
+
covariance (np.ndarray): The 8x8-dimensional covariance matrix of the object state at the previous time step.
|
371
371
|
|
372
372
|
Returns:
|
373
373
|
(tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
|
@@ -403,8 +403,8 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
403
403
|
Project state distribution to measurement space.
|
404
404
|
|
405
405
|
Args:
|
406
|
-
mean (ndarray): The state's mean vector (8 dimensional array).
|
407
|
-
covariance (ndarray): The state's covariance matrix (8x8 dimensional).
|
406
|
+
mean (np.ndarray): The state's mean vector (8 dimensional array).
|
407
|
+
covariance (np.ndarray): The state's covariance matrix (8x8 dimensional).
|
408
408
|
|
409
409
|
Returns:
|
410
410
|
(tuple[ndarray, ndarray]): Returns the projected mean and covariance matrix of the given state estimate.
|
@@ -432,8 +432,8 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
432
432
|
Run Kalman filter prediction step (Vectorized version).
|
433
433
|
|
434
434
|
Args:
|
435
|
-
mean (ndarray): The Nx8 dimensional mean matrix of the object states at the previous time step.
|
436
|
-
covariance (ndarray): The Nx8x8 covariance matrix of the object states at the previous time step.
|
435
|
+
mean (np.ndarray): The Nx8 dimensional mean matrix of the object states at the previous time step.
|
436
|
+
covariance (np.ndarray): The Nx8x8 covariance matrix of the object states at the previous time step.
|
437
437
|
|
438
438
|
Returns:
|
439
439
|
(tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
|
@@ -473,9 +473,9 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
473
473
|
Run Kalman filter correction step.
|
474
474
|
|
475
475
|
Args:
|
476
|
-
mean (ndarray): The predicted state's mean vector (8 dimensional).
|
477
|
-
covariance (ndarray): The state's covariance matrix (8x8 dimensional).
|
478
|
-
measurement (ndarray): The 4 dimensional measurement vector (x, y, w, h), where (x, y) is the center
|
476
|
+
mean (np.ndarray): The predicted state's mean vector (8 dimensional).
|
477
|
+
covariance (np.ndarray): The state's covariance matrix (8x8 dimensional).
|
478
|
+
measurement (np.ndarray): The 4 dimensional measurement vector (x, y, w, h), where (x, y) is the center
|
479
479
|
position, w the width, and h the height of the bounding box.
|
480
480
|
|
481
481
|
Returns:
|
ultralytics/utils/__init__.py
CHANGED
@@ -427,14 +427,11 @@ class ThreadingLocked:
|
|
427
427
|
Attributes:
|
428
428
|
lock (threading.Lock): A lock object used to manage access to the decorated function.
|
429
429
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
def my_function():
|
436
|
-
# Your code here
|
437
|
-
```
|
430
|
+
Examples:
|
431
|
+
>>> from ultralytics.utils import ThreadingLocked
|
432
|
+
>>> @ThreadingLocked()
|
433
|
+
>>> def my_function():
|
434
|
+
... # Your code here
|
438
435
|
"""
|
439
436
|
|
440
437
|
def __init__(self):
|