ultralytics 8.0.237__py3-none-any.whl → 8.0.239__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.
Potentially problematic release.
This version of ultralytics might be problematic. Click here for more details.
- ultralytics/__init__.py +2 -2
- ultralytics/cfg/__init__.py +241 -138
- ultralytics/cfg/datasets/DOTAv1.5.yaml +1 -1
- ultralytics/cfg/datasets/DOTAv1.yaml +1 -1
- ultralytics/cfg/datasets/dota8.yaml +34 -0
- ultralytics/data/__init__.py +9 -2
- ultralytics/data/annotator.py +4 -4
- ultralytics/data/augment.py +186 -169
- ultralytics/data/base.py +54 -48
- ultralytics/data/build.py +34 -23
- ultralytics/data/converter.py +242 -70
- ultralytics/data/dataset.py +117 -95
- ultralytics/data/explorer/__init__.py +5 -0
- ultralytics/data/explorer/explorer.py +170 -97
- ultralytics/data/explorer/gui/__init__.py +1 -0
- ultralytics/data/explorer/gui/dash.py +146 -76
- ultralytics/data/explorer/utils.py +87 -25
- ultralytics/data/loaders.py +75 -62
- ultralytics/data/split_dota.py +44 -36
- ultralytics/data/utils.py +160 -142
- ultralytics/engine/exporter.py +348 -292
- ultralytics/engine/model.py +102 -66
- ultralytics/engine/predictor.py +74 -55
- ultralytics/engine/results.py +63 -40
- ultralytics/engine/trainer.py +192 -144
- ultralytics/engine/tuner.py +66 -59
- ultralytics/engine/validator.py +31 -26
- ultralytics/hub/__init__.py +54 -31
- ultralytics/hub/auth.py +28 -25
- ultralytics/hub/session.py +282 -133
- ultralytics/hub/utils.py +64 -42
- ultralytics/models/__init__.py +1 -1
- ultralytics/models/fastsam/__init__.py +1 -1
- ultralytics/models/fastsam/model.py +6 -6
- ultralytics/models/fastsam/predict.py +3 -2
- ultralytics/models/fastsam/prompt.py +55 -48
- ultralytics/models/fastsam/val.py +1 -1
- ultralytics/models/nas/__init__.py +1 -1
- ultralytics/models/nas/model.py +9 -8
- ultralytics/models/nas/predict.py +8 -6
- ultralytics/models/nas/val.py +11 -9
- ultralytics/models/rtdetr/__init__.py +1 -1
- ultralytics/models/rtdetr/model.py +11 -9
- ultralytics/models/rtdetr/train.py +18 -16
- ultralytics/models/rtdetr/val.py +25 -19
- ultralytics/models/sam/__init__.py +1 -1
- ultralytics/models/sam/amg.py +13 -14
- ultralytics/models/sam/build.py +44 -42
- ultralytics/models/sam/model.py +6 -6
- ultralytics/models/sam/modules/decoders.py +6 -4
- ultralytics/models/sam/modules/encoders.py +37 -35
- ultralytics/models/sam/modules/sam.py +5 -4
- ultralytics/models/sam/modules/tiny_encoder.py +95 -73
- ultralytics/models/sam/modules/transformer.py +3 -2
- ultralytics/models/sam/predict.py +39 -27
- ultralytics/models/utils/loss.py +99 -95
- ultralytics/models/utils/ops.py +34 -31
- ultralytics/models/yolo/__init__.py +1 -1
- ultralytics/models/yolo/classify/__init__.py +1 -1
- ultralytics/models/yolo/classify/predict.py +8 -6
- ultralytics/models/yolo/classify/train.py +37 -31
- ultralytics/models/yolo/classify/val.py +26 -24
- ultralytics/models/yolo/detect/__init__.py +1 -1
- ultralytics/models/yolo/detect/predict.py +8 -6
- ultralytics/models/yolo/detect/train.py +47 -37
- ultralytics/models/yolo/detect/val.py +100 -82
- ultralytics/models/yolo/model.py +31 -25
- ultralytics/models/yolo/obb/__init__.py +1 -1
- ultralytics/models/yolo/obb/predict.py +13 -12
- ultralytics/models/yolo/obb/train.py +3 -3
- ultralytics/models/yolo/obb/val.py +80 -58
- ultralytics/models/yolo/pose/__init__.py +1 -1
- ultralytics/models/yolo/pose/predict.py +17 -12
- ultralytics/models/yolo/pose/train.py +28 -25
- ultralytics/models/yolo/pose/val.py +91 -64
- ultralytics/models/yolo/segment/__init__.py +1 -1
- ultralytics/models/yolo/segment/predict.py +10 -8
- ultralytics/models/yolo/segment/train.py +16 -15
- ultralytics/models/yolo/segment/val.py +90 -68
- ultralytics/nn/__init__.py +26 -6
- ultralytics/nn/autobackend.py +144 -112
- ultralytics/nn/modules/__init__.py +96 -13
- ultralytics/nn/modules/block.py +28 -7
- ultralytics/nn/modules/conv.py +41 -23
- ultralytics/nn/modules/head.py +67 -59
- ultralytics/nn/modules/transformer.py +49 -32
- ultralytics/nn/modules/utils.py +20 -15
- ultralytics/nn/tasks.py +215 -141
- ultralytics/solutions/ai_gym.py +59 -47
- ultralytics/solutions/distance_calculation.py +22 -15
- ultralytics/solutions/heatmap.py +76 -54
- ultralytics/solutions/object_counter.py +46 -39
- ultralytics/solutions/speed_estimation.py +13 -16
- ultralytics/trackers/__init__.py +1 -1
- ultralytics/trackers/basetrack.py +1 -0
- ultralytics/trackers/bot_sort.py +2 -1
- ultralytics/trackers/byte_tracker.py +10 -7
- ultralytics/trackers/track.py +7 -7
- ultralytics/trackers/utils/gmc.py +25 -25
- ultralytics/trackers/utils/kalman_filter.py +85 -42
- ultralytics/trackers/utils/matching.py +8 -7
- ultralytics/utils/__init__.py +173 -151
- ultralytics/utils/autobatch.py +10 -10
- ultralytics/utils/benchmarks.py +76 -86
- ultralytics/utils/callbacks/__init__.py +1 -1
- ultralytics/utils/callbacks/base.py +29 -29
- ultralytics/utils/callbacks/clearml.py +51 -43
- ultralytics/utils/callbacks/comet.py +81 -66
- ultralytics/utils/callbacks/dvc.py +33 -26
- ultralytics/utils/callbacks/hub.py +44 -26
- ultralytics/utils/callbacks/mlflow.py +31 -24
- ultralytics/utils/callbacks/neptune.py +35 -25
- ultralytics/utils/callbacks/raytune.py +9 -4
- ultralytics/utils/callbacks/tensorboard.py +16 -11
- ultralytics/utils/callbacks/wb.py +39 -33
- ultralytics/utils/checks.py +189 -141
- ultralytics/utils/dist.py +15 -12
- ultralytics/utils/downloads.py +112 -96
- ultralytics/utils/errors.py +1 -1
- ultralytics/utils/files.py +11 -11
- ultralytics/utils/instance.py +22 -22
- ultralytics/utils/loss.py +117 -67
- ultralytics/utils/metrics.py +224 -158
- ultralytics/utils/ops.py +39 -29
- ultralytics/utils/patches.py +3 -3
- ultralytics/utils/plotting.py +217 -120
- ultralytics/utils/tal.py +19 -13
- ultralytics/utils/torch_utils.py +138 -109
- ultralytics/utils/triton.py +12 -10
- ultralytics/utils/tuner.py +49 -47
- {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/METADATA +5 -4
- ultralytics-8.0.239.dist-info/RECORD +188 -0
- ultralytics-8.0.237.dist-info/RECORD +0 -187
- {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/LICENSE +0 -0
- {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/WHEEL +0 -0
- {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/entry_points.txt +0 -0
- {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/top_level.txt +0 -0
|
@@ -66,7 +66,7 @@ class SpeedEstimator:
|
|
|
66
66
|
spdl_dist_thresh (int): Euclidean distance threshold for speed line
|
|
67
67
|
"""
|
|
68
68
|
if reg_pts is None:
|
|
69
|
-
print(
|
|
69
|
+
print("Region points not provided, using default values")
|
|
70
70
|
else:
|
|
71
71
|
self.reg_pts = reg_pts
|
|
72
72
|
self.names = names
|
|
@@ -114,8 +114,9 @@ class SpeedEstimator:
|
|
|
114
114
|
cls (str): object class name
|
|
115
115
|
track (list): tracking history for tracks path drawing
|
|
116
116
|
"""
|
|
117
|
-
speed_label =
|
|
118
|
-
self.dist_data[track_id])) +
|
|
117
|
+
speed_label = (
|
|
118
|
+
str(int(self.dist_data[track_id])) + "km/ph" if track_id in self.dist_data else self.names[int(cls)]
|
|
119
|
+
)
|
|
119
120
|
bbox_color = colors(int(track_id)) if track_id in self.dist_data else (255, 0, 255)
|
|
120
121
|
|
|
121
122
|
self.annotator.box_label(box, speed_label, bbox_color)
|
|
@@ -132,19 +133,16 @@ class SpeedEstimator:
|
|
|
132
133
|
"""
|
|
133
134
|
|
|
134
135
|
if self.reg_pts[0][0] < track[-1][0] < self.reg_pts[1][0]:
|
|
136
|
+
if self.reg_pts[1][1] - self.spdl_dist_thresh < track[-1][1] < self.reg_pts[1][1] + self.spdl_dist_thresh:
|
|
137
|
+
direction = "known"
|
|
135
138
|
|
|
136
|
-
|
|
137
|
-
direction =
|
|
138
|
-
|
|
139
|
-
elif (self.reg_pts[0][1] - self.spdl_dist_thresh < track[-1][1] <
|
|
140
|
-
self.reg_pts[0][1] + self.spdl_dist_thresh):
|
|
141
|
-
direction = 'known'
|
|
139
|
+
elif self.reg_pts[0][1] - self.spdl_dist_thresh < track[-1][1] < self.reg_pts[0][1] + self.spdl_dist_thresh:
|
|
140
|
+
direction = "known"
|
|
142
141
|
|
|
143
142
|
else:
|
|
144
|
-
direction =
|
|
145
|
-
|
|
146
|
-
if self.trk_previous_times[trk_id] != 0 and direction != 'unknown':
|
|
143
|
+
direction = "unknown"
|
|
147
144
|
|
|
145
|
+
if self.trk_previous_times[trk_id] != 0 and direction != "unknown":
|
|
148
146
|
if trk_id not in self.trk_idslist:
|
|
149
147
|
self.trk_idslist.append(trk_id)
|
|
150
148
|
|
|
@@ -178,7 +176,6 @@ class SpeedEstimator:
|
|
|
178
176
|
self.annotator.draw_region(reg_pts=self.reg_pts, color=(255, 0, 0), thickness=self.region_thickness)
|
|
179
177
|
|
|
180
178
|
for box, trk_id, cls in zip(self.boxes, self.trk_ids, self.clss):
|
|
181
|
-
|
|
182
179
|
track = self.store_track_info(trk_id, box)
|
|
183
180
|
|
|
184
181
|
if trk_id not in self.trk_previous_times:
|
|
@@ -194,10 +191,10 @@ class SpeedEstimator:
|
|
|
194
191
|
|
|
195
192
|
def display_frames(self):
|
|
196
193
|
"""Display frame."""
|
|
197
|
-
cv2.imshow(
|
|
198
|
-
if cv2.waitKey(1) & 0xFF == ord(
|
|
194
|
+
cv2.imshow("Ultralytics Speed Estimation", self.im0)
|
|
195
|
+
if cv2.waitKey(1) & 0xFF == ord("q"):
|
|
199
196
|
return
|
|
200
197
|
|
|
201
198
|
|
|
202
|
-
if __name__ ==
|
|
199
|
+
if __name__ == "__main__":
|
|
203
200
|
SpeedEstimator()
|
ultralytics/trackers/__init__.py
CHANGED
ultralytics/trackers/bot_sort.py
CHANGED
|
@@ -39,6 +39,7 @@ class BOTrack(STrack):
|
|
|
39
39
|
bo_track.predict()
|
|
40
40
|
bo_track.update(new_track, frame_id)
|
|
41
41
|
"""
|
|
42
|
+
|
|
42
43
|
shared_kalman = KalmanFilterXYWH()
|
|
43
44
|
|
|
44
45
|
def __init__(self, tlwh, score, cls, feat=None, feat_history=50):
|
|
@@ -176,7 +177,7 @@ class BOTSORT(BYTETracker):
|
|
|
176
177
|
def get_dists(self, tracks, detections):
|
|
177
178
|
"""Get distances between tracks and detections using IoU and (optionally) ReID embeddings."""
|
|
178
179
|
dists = matching.iou_distance(tracks, detections)
|
|
179
|
-
dists_mask =
|
|
180
|
+
dists_mask = dists > self.proximity_thresh
|
|
180
181
|
|
|
181
182
|
# TODO: mot20
|
|
182
183
|
# if not self.args.mot20:
|
|
@@ -112,8 +112,9 @@ class STrack(BaseTrack):
|
|
|
112
112
|
|
|
113
113
|
def re_activate(self, new_track, frame_id, new_id=False):
|
|
114
114
|
"""Reactivates a previously lost track with a new detection."""
|
|
115
|
-
self.mean, self.covariance = self.kalman_filter.update(
|
|
116
|
-
|
|
115
|
+
self.mean, self.covariance = self.kalman_filter.update(
|
|
116
|
+
self.mean, self.covariance, self.convert_coords(new_track.tlwh)
|
|
117
|
+
)
|
|
117
118
|
self.tracklet_len = 0
|
|
118
119
|
self.state = TrackState.Tracked
|
|
119
120
|
self.is_activated = True
|
|
@@ -136,8 +137,9 @@ class STrack(BaseTrack):
|
|
|
136
137
|
self.tracklet_len += 1
|
|
137
138
|
|
|
138
139
|
new_tlwh = new_track.tlwh
|
|
139
|
-
self.mean, self.covariance = self.kalman_filter.update(
|
|
140
|
-
|
|
140
|
+
self.mean, self.covariance = self.kalman_filter.update(
|
|
141
|
+
self.mean, self.covariance, self.convert_coords(new_tlwh)
|
|
142
|
+
)
|
|
141
143
|
self.state = TrackState.Tracked
|
|
142
144
|
self.is_activated = True
|
|
143
145
|
|
|
@@ -192,7 +194,7 @@ class STrack(BaseTrack):
|
|
|
192
194
|
|
|
193
195
|
def __repr__(self):
|
|
194
196
|
"""Return a string representation of the BYTETracker object with start and end frames and track ID."""
|
|
195
|
-
return f
|
|
197
|
+
return f"OT_{self.track_id}_({self.start_frame}-{self.end_frame})"
|
|
196
198
|
|
|
197
199
|
|
|
198
200
|
class BYTETracker:
|
|
@@ -275,7 +277,7 @@ class BYTETracker:
|
|
|
275
277
|
strack_pool = self.joint_stracks(tracked_stracks, self.lost_stracks)
|
|
276
278
|
# Predict the current location with KF
|
|
277
279
|
self.multi_predict(strack_pool)
|
|
278
|
-
if hasattr(self,
|
|
280
|
+
if hasattr(self, "gmc") and img is not None:
|
|
279
281
|
warp = self.gmc.apply(img, dets)
|
|
280
282
|
STrack.multi_gmc(strack_pool, warp)
|
|
281
283
|
STrack.multi_gmc(unconfirmed, warp)
|
|
@@ -349,7 +351,8 @@ class BYTETracker:
|
|
|
349
351
|
self.removed_stracks = self.removed_stracks[-999:] # clip remove stracks to 1000 maximum
|
|
350
352
|
return np.asarray(
|
|
351
353
|
[x.tlbr.tolist() + [x.track_id, x.score, x.cls, x.idx] for x in self.tracked_stracks if x.is_activated],
|
|
352
|
-
dtype=np.float32
|
|
354
|
+
dtype=np.float32,
|
|
355
|
+
)
|
|
353
356
|
|
|
354
357
|
def get_kalmanfilter(self):
|
|
355
358
|
"""Returns a Kalman filter object for tracking bounding boxes."""
|
ultralytics/trackers/track.py
CHANGED
|
@@ -10,7 +10,7 @@ from .bot_sort import BOTSORT
|
|
|
10
10
|
from .byte_tracker import BYTETracker
|
|
11
11
|
|
|
12
12
|
# A mapping of tracker types to corresponding tracker classes
|
|
13
|
-
TRACKER_MAP = {
|
|
13
|
+
TRACKER_MAP = {"bytetrack": BYTETracker, "botsort": BOTSORT}
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def on_predict_start(predictor: object, persist: bool = False) -> None:
|
|
@@ -24,15 +24,15 @@ def on_predict_start(predictor: object, persist: bool = False) -> None:
|
|
|
24
24
|
Raises:
|
|
25
25
|
AssertionError: If the tracker_type is not 'bytetrack' or 'botsort'.
|
|
26
26
|
"""
|
|
27
|
-
if predictor.args.task ==
|
|
28
|
-
raise NotImplementedError(
|
|
29
|
-
if hasattr(predictor,
|
|
27
|
+
if predictor.args.task == "obb":
|
|
28
|
+
raise NotImplementedError("ERROR ❌ OBB task does not support track mode!")
|
|
29
|
+
if hasattr(predictor, "trackers") and persist:
|
|
30
30
|
return
|
|
31
31
|
|
|
32
32
|
tracker = check_yaml(predictor.args.tracker)
|
|
33
33
|
cfg = IterableSimpleNamespace(**yaml_load(tracker))
|
|
34
34
|
|
|
35
|
-
if cfg.tracker_type not in [
|
|
35
|
+
if cfg.tracker_type not in ["bytetrack", "botsort"]:
|
|
36
36
|
raise AssertionError(f"Only 'bytetrack' and 'botsort' are supported for now, but got '{cfg.tracker_type}'")
|
|
37
37
|
|
|
38
38
|
trackers = []
|
|
@@ -76,5 +76,5 @@ def register_tracker(model: object, persist: bool) -> None:
|
|
|
76
76
|
model (object): The model object to register tracking callbacks for.
|
|
77
77
|
persist (bool): Whether to persist the trackers if they already exist.
|
|
78
78
|
"""
|
|
79
|
-
model.add_callback(
|
|
80
|
-
model.add_callback(
|
|
79
|
+
model.add_callback("on_predict_start", partial(on_predict_start, persist=persist))
|
|
80
|
+
model.add_callback("on_predict_postprocess_end", partial(on_predict_postprocess_end, persist=persist))
|
|
@@ -33,7 +33,7 @@ class GMC:
|
|
|
33
33
|
applySparseOptFlow(self, raw_frame, detections=None): Applies the Sparse Optical Flow method to a raw frame.
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
-
def __init__(self, method: str =
|
|
36
|
+
def __init__(self, method: str = "sparseOptFlow", downscale: int = 2) -> None:
|
|
37
37
|
"""
|
|
38
38
|
Initialize a video tracker with specified parameters.
|
|
39
39
|
|
|
@@ -46,34 +46,31 @@ class GMC:
|
|
|
46
46
|
self.method = method
|
|
47
47
|
self.downscale = max(1, int(downscale))
|
|
48
48
|
|
|
49
|
-
if self.method ==
|
|
49
|
+
if self.method == "orb":
|
|
50
50
|
self.detector = cv2.FastFeatureDetector_create(20)
|
|
51
51
|
self.extractor = cv2.ORB_create()
|
|
52
52
|
self.matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
|
|
53
53
|
|
|
54
|
-
elif self.method ==
|
|
54
|
+
elif self.method == "sift":
|
|
55
55
|
self.detector = cv2.SIFT_create(nOctaveLayers=3, contrastThreshold=0.02, edgeThreshold=20)
|
|
56
56
|
self.extractor = cv2.SIFT_create(nOctaveLayers=3, contrastThreshold=0.02, edgeThreshold=20)
|
|
57
57
|
self.matcher = cv2.BFMatcher(cv2.NORM_L2)
|
|
58
58
|
|
|
59
|
-
elif self.method ==
|
|
59
|
+
elif self.method == "ecc":
|
|
60
60
|
number_of_iterations = 5000
|
|
61
61
|
termination_eps = 1e-6
|
|
62
62
|
self.warp_mode = cv2.MOTION_EUCLIDEAN
|
|
63
63
|
self.criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, number_of_iterations, termination_eps)
|
|
64
64
|
|
|
65
|
-
elif self.method ==
|
|
66
|
-
self.feature_params = dict(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
blockSize=3,
|
|
70
|
-
useHarrisDetector=False,
|
|
71
|
-
k=0.04)
|
|
65
|
+
elif self.method == "sparseOptFlow":
|
|
66
|
+
self.feature_params = dict(
|
|
67
|
+
maxCorners=1000, qualityLevel=0.01, minDistance=1, blockSize=3, useHarrisDetector=False, k=0.04
|
|
68
|
+
)
|
|
72
69
|
|
|
73
|
-
elif self.method in [
|
|
70
|
+
elif self.method in ["none", "None", None]:
|
|
74
71
|
self.method = None
|
|
75
72
|
else:
|
|
76
|
-
raise ValueError(f
|
|
73
|
+
raise ValueError(f"Error: Unknown GMC method:{method}")
|
|
77
74
|
|
|
78
75
|
self.prevFrame = None
|
|
79
76
|
self.prevKeyPoints = None
|
|
@@ -97,11 +94,11 @@ class GMC:
|
|
|
97
94
|
array([[1, 2, 3],
|
|
98
95
|
[4, 5, 6]])
|
|
99
96
|
"""
|
|
100
|
-
if self.method in [
|
|
97
|
+
if self.method in ["orb", "sift"]:
|
|
101
98
|
return self.applyFeatures(raw_frame, detections)
|
|
102
|
-
elif self.method ==
|
|
99
|
+
elif self.method == "ecc":
|
|
103
100
|
return self.applyEcc(raw_frame, detections)
|
|
104
|
-
elif self.method ==
|
|
101
|
+
elif self.method == "sparseOptFlow":
|
|
105
102
|
return self.applySparseOptFlow(raw_frame, detections)
|
|
106
103
|
else:
|
|
107
104
|
return np.eye(2, 3)
|
|
@@ -149,7 +146,7 @@ class GMC:
|
|
|
149
146
|
try:
|
|
150
147
|
(cc, H) = cv2.findTransformECC(self.prevFrame, frame, H, self.warp_mode, self.criteria, None, 1)
|
|
151
148
|
except Exception as e:
|
|
152
|
-
LOGGER.warning(f
|
|
149
|
+
LOGGER.warning(f"WARNING: find transform failed. Set warp as identity {e}")
|
|
153
150
|
|
|
154
151
|
return H
|
|
155
152
|
|
|
@@ -182,11 +179,11 @@ class GMC:
|
|
|
182
179
|
|
|
183
180
|
# Find the keypoints
|
|
184
181
|
mask = np.zeros_like(frame)
|
|
185
|
-
mask[int(0.02 * height):int(0.98 * height), int(0.02 * width):int(0.98 * width)] = 255
|
|
182
|
+
mask[int(0.02 * height) : int(0.98 * height), int(0.02 * width) : int(0.98 * width)] = 255
|
|
186
183
|
if detections is not None:
|
|
187
184
|
for det in detections:
|
|
188
185
|
tlbr = (det[:4] / self.downscale).astype(np.int_)
|
|
189
|
-
mask[tlbr[1]:tlbr[3], tlbr[0]:tlbr[2]] = 0
|
|
186
|
+
mask[tlbr[1] : tlbr[3], tlbr[0] : tlbr[2]] = 0
|
|
190
187
|
|
|
191
188
|
keypoints = self.detector.detect(frame, mask)
|
|
192
189
|
|
|
@@ -228,11 +225,14 @@ class GMC:
|
|
|
228
225
|
prevKeyPointLocation = self.prevKeyPoints[m.queryIdx].pt
|
|
229
226
|
currKeyPointLocation = keypoints[m.trainIdx].pt
|
|
230
227
|
|
|
231
|
-
spatialDistance = (
|
|
232
|
-
|
|
228
|
+
spatialDistance = (
|
|
229
|
+
prevKeyPointLocation[0] - currKeyPointLocation[0],
|
|
230
|
+
prevKeyPointLocation[1] - currKeyPointLocation[1],
|
|
231
|
+
)
|
|
233
232
|
|
|
234
|
-
if (np.abs(spatialDistance[0]) < maxSpatialDistance[0]) and
|
|
235
|
-
|
|
233
|
+
if (np.abs(spatialDistance[0]) < maxSpatialDistance[0]) and (
|
|
234
|
+
np.abs(spatialDistance[1]) < maxSpatialDistance[1]
|
|
235
|
+
):
|
|
236
236
|
spatialDistances.append(spatialDistance)
|
|
237
237
|
matches.append(m)
|
|
238
238
|
|
|
@@ -283,7 +283,7 @@ class GMC:
|
|
|
283
283
|
H[0, 2] *= self.downscale
|
|
284
284
|
H[1, 2] *= self.downscale
|
|
285
285
|
else:
|
|
286
|
-
LOGGER.warning(
|
|
286
|
+
LOGGER.warning("WARNING: not enough matching points")
|
|
287
287
|
|
|
288
288
|
# Store to next iteration
|
|
289
289
|
self.prevFrame = frame.copy()
|
|
@@ -350,7 +350,7 @@ class GMC:
|
|
|
350
350
|
H[0, 2] *= self.downscale
|
|
351
351
|
H[1, 2] *= self.downscale
|
|
352
352
|
else:
|
|
353
|
-
LOGGER.warning(
|
|
353
|
+
LOGGER.warning("WARNING: not enough matching points")
|
|
354
354
|
|
|
355
355
|
self.prevFrame = frame.copy()
|
|
356
356
|
self.prevKeyPoints = copy.copy(keypoints)
|
|
@@ -17,7 +17,7 @@ class KalmanFilterXYAH:
|
|
|
17
17
|
|
|
18
18
|
def __init__(self):
|
|
19
19
|
"""Initialize Kalman filter model matrices with motion and observation uncertainty weights."""
|
|
20
|
-
ndim, dt = 4, 1.
|
|
20
|
+
ndim, dt = 4, 1.0
|
|
21
21
|
|
|
22
22
|
# Create Kalman filter model matrices
|
|
23
23
|
self._motion_mat = np.eye(2 * ndim, 2 * ndim)
|
|
@@ -27,8 +27,8 @@ class KalmanFilterXYAH:
|
|
|
27
27
|
|
|
28
28
|
# Motion and observation uncertainty are chosen relative to the current state estimate. These weights control
|
|
29
29
|
# the amount of uncertainty in the model.
|
|
30
|
-
self._std_weight_position = 1. / 20
|
|
31
|
-
self._std_weight_velocity = 1. / 160
|
|
30
|
+
self._std_weight_position = 1.0 / 20
|
|
31
|
+
self._std_weight_velocity = 1.0 / 160
|
|
32
32
|
|
|
33
33
|
def initiate(self, measurement: np.ndarray) -> tuple:
|
|
34
34
|
"""
|
|
@@ -47,9 +47,15 @@ class KalmanFilterXYAH:
|
|
|
47
47
|
mean = np.r_[mean_pos, mean_vel]
|
|
48
48
|
|
|
49
49
|
std = [
|
|
50
|
-
2 * self._std_weight_position * measurement[3],
|
|
51
|
-
2 * self._std_weight_position * measurement[3],
|
|
52
|
-
|
|
50
|
+
2 * self._std_weight_position * measurement[3],
|
|
51
|
+
2 * self._std_weight_position * measurement[3],
|
|
52
|
+
1e-2,
|
|
53
|
+
2 * self._std_weight_position * measurement[3],
|
|
54
|
+
10 * self._std_weight_velocity * measurement[3],
|
|
55
|
+
10 * self._std_weight_velocity * measurement[3],
|
|
56
|
+
1e-5,
|
|
57
|
+
10 * self._std_weight_velocity * measurement[3],
|
|
58
|
+
]
|
|
53
59
|
covariance = np.diag(np.square(std))
|
|
54
60
|
return mean, covariance
|
|
55
61
|
|
|
@@ -66,11 +72,17 @@ class KalmanFilterXYAH:
|
|
|
66
72
|
velocities are initialized to 0 mean.
|
|
67
73
|
"""
|
|
68
74
|
std_pos = [
|
|
69
|
-
self._std_weight_position * mean[3],
|
|
70
|
-
self._std_weight_position * mean[3]
|
|
75
|
+
self._std_weight_position * mean[3],
|
|
76
|
+
self._std_weight_position * mean[3],
|
|
77
|
+
1e-2,
|
|
78
|
+
self._std_weight_position * mean[3],
|
|
79
|
+
]
|
|
71
80
|
std_vel = [
|
|
72
|
-
self._std_weight_velocity * mean[3],
|
|
73
|
-
self._std_weight_velocity * mean[3]
|
|
81
|
+
self._std_weight_velocity * mean[3],
|
|
82
|
+
self._std_weight_velocity * mean[3],
|
|
83
|
+
1e-5,
|
|
84
|
+
self._std_weight_velocity * mean[3],
|
|
85
|
+
]
|
|
74
86
|
motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))
|
|
75
87
|
|
|
76
88
|
mean = np.dot(mean, self._motion_mat.T)
|
|
@@ -90,8 +102,11 @@ class KalmanFilterXYAH:
|
|
|
90
102
|
(tuple[ndarray, ndarray]): Returns the projected mean and covariance matrix of the given state estimate.
|
|
91
103
|
"""
|
|
92
104
|
std = [
|
|
93
|
-
self._std_weight_position * mean[3],
|
|
94
|
-
self._std_weight_position * mean[3]
|
|
105
|
+
self._std_weight_position * mean[3],
|
|
106
|
+
self._std_weight_position * mean[3],
|
|
107
|
+
1e-1,
|
|
108
|
+
self._std_weight_position * mean[3],
|
|
109
|
+
]
|
|
95
110
|
innovation_cov = np.diag(np.square(std))
|
|
96
111
|
|
|
97
112
|
mean = np.dot(self._update_mat, mean)
|
|
@@ -111,11 +126,17 @@ class KalmanFilterXYAH:
|
|
|
111
126
|
velocities are initialized to 0 mean.
|
|
112
127
|
"""
|
|
113
128
|
std_pos = [
|
|
114
|
-
self._std_weight_position * mean[:, 3],
|
|
115
|
-
|
|
129
|
+
self._std_weight_position * mean[:, 3],
|
|
130
|
+
self._std_weight_position * mean[:, 3],
|
|
131
|
+
1e-2 * np.ones_like(mean[:, 3]),
|
|
132
|
+
self._std_weight_position * mean[:, 3],
|
|
133
|
+
]
|
|
116
134
|
std_vel = [
|
|
117
|
-
self._std_weight_velocity * mean[:, 3],
|
|
118
|
-
|
|
135
|
+
self._std_weight_velocity * mean[:, 3],
|
|
136
|
+
self._std_weight_velocity * mean[:, 3],
|
|
137
|
+
1e-5 * np.ones_like(mean[:, 3]),
|
|
138
|
+
self._std_weight_velocity * mean[:, 3],
|
|
139
|
+
]
|
|
119
140
|
sqr = np.square(np.r_[std_pos, std_vel]).T
|
|
120
141
|
|
|
121
142
|
motion_cov = [np.diag(sqr[i]) for i in range(len(mean))]
|
|
@@ -143,21 +164,23 @@ class KalmanFilterXYAH:
|
|
|
143
164
|
projected_mean, projected_cov = self.project(mean, covariance)
|
|
144
165
|
|
|
145
166
|
chol_factor, lower = scipy.linalg.cho_factor(projected_cov, lower=True, check_finite=False)
|
|
146
|
-
kalman_gain = scipy.linalg.cho_solve(
|
|
147
|
-
|
|
148
|
-
|
|
167
|
+
kalman_gain = scipy.linalg.cho_solve(
|
|
168
|
+
(chol_factor, lower), np.dot(covariance, self._update_mat.T).T, check_finite=False
|
|
169
|
+
).T
|
|
149
170
|
innovation = measurement - projected_mean
|
|
150
171
|
|
|
151
172
|
new_mean = mean + np.dot(innovation, kalman_gain.T)
|
|
152
173
|
new_covariance = covariance - np.linalg.multi_dot((kalman_gain, projected_cov, kalman_gain.T))
|
|
153
174
|
return new_mean, new_covariance
|
|
154
175
|
|
|
155
|
-
def gating_distance(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
176
|
+
def gating_distance(
|
|
177
|
+
self,
|
|
178
|
+
mean: np.ndarray,
|
|
179
|
+
covariance: np.ndarray,
|
|
180
|
+
measurements: np.ndarray,
|
|
181
|
+
only_position: bool = False,
|
|
182
|
+
metric: str = "maha",
|
|
183
|
+
) -> np.ndarray:
|
|
161
184
|
"""
|
|
162
185
|
Compute gating distance between state distribution and measurements. A suitable distance threshold can be
|
|
163
186
|
obtained from `chi2inv95`. If `only_position` is False, the chi-square distribution has 4 degrees of freedom,
|
|
@@ -183,14 +206,14 @@ class KalmanFilterXYAH:
|
|
|
183
206
|
measurements = measurements[:, :2]
|
|
184
207
|
|
|
185
208
|
d = measurements - mean
|
|
186
|
-
if metric ==
|
|
209
|
+
if metric == "gaussian":
|
|
187
210
|
return np.sum(d * d, axis=1)
|
|
188
|
-
elif metric ==
|
|
211
|
+
elif metric == "maha":
|
|
189
212
|
cholesky_factor = np.linalg.cholesky(covariance)
|
|
190
213
|
z = scipy.linalg.solve_triangular(cholesky_factor, d.T, lower=True, check_finite=False, overwrite_b=True)
|
|
191
214
|
return np.sum(z * z, axis=0) # square maha
|
|
192
215
|
else:
|
|
193
|
-
raise ValueError(
|
|
216
|
+
raise ValueError("Invalid distance metric")
|
|
194
217
|
|
|
195
218
|
|
|
196
219
|
class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
@@ -220,10 +243,15 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
|
220
243
|
mean = np.r_[mean_pos, mean_vel]
|
|
221
244
|
|
|
222
245
|
std = [
|
|
223
|
-
2 * self._std_weight_position * measurement[2],
|
|
224
|
-
2 * self._std_weight_position * measurement[
|
|
225
|
-
|
|
226
|
-
|
|
246
|
+
2 * self._std_weight_position * measurement[2],
|
|
247
|
+
2 * self._std_weight_position * measurement[3],
|
|
248
|
+
2 * self._std_weight_position * measurement[2],
|
|
249
|
+
2 * self._std_weight_position * measurement[3],
|
|
250
|
+
10 * self._std_weight_velocity * measurement[2],
|
|
251
|
+
10 * self._std_weight_velocity * measurement[3],
|
|
252
|
+
10 * self._std_weight_velocity * measurement[2],
|
|
253
|
+
10 * self._std_weight_velocity * measurement[3],
|
|
254
|
+
]
|
|
227
255
|
covariance = np.diag(np.square(std))
|
|
228
256
|
return mean, covariance
|
|
229
257
|
|
|
@@ -240,11 +268,17 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
|
240
268
|
velocities are initialized to 0 mean.
|
|
241
269
|
"""
|
|
242
270
|
std_pos = [
|
|
243
|
-
self._std_weight_position * mean[2],
|
|
244
|
-
self._std_weight_position * mean[
|
|
271
|
+
self._std_weight_position * mean[2],
|
|
272
|
+
self._std_weight_position * mean[3],
|
|
273
|
+
self._std_weight_position * mean[2],
|
|
274
|
+
self._std_weight_position * mean[3],
|
|
275
|
+
]
|
|
245
276
|
std_vel = [
|
|
246
|
-
self._std_weight_velocity * mean[2],
|
|
247
|
-
self._std_weight_velocity * mean[
|
|
277
|
+
self._std_weight_velocity * mean[2],
|
|
278
|
+
self._std_weight_velocity * mean[3],
|
|
279
|
+
self._std_weight_velocity * mean[2],
|
|
280
|
+
self._std_weight_velocity * mean[3],
|
|
281
|
+
]
|
|
248
282
|
motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))
|
|
249
283
|
|
|
250
284
|
mean = np.dot(mean, self._motion_mat.T)
|
|
@@ -264,8 +298,11 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
|
264
298
|
(tuple[ndarray, ndarray]): Returns the projected mean and covariance matrix of the given state estimate.
|
|
265
299
|
"""
|
|
266
300
|
std = [
|
|
267
|
-
self._std_weight_position * mean[2],
|
|
268
|
-
self._std_weight_position * mean[
|
|
301
|
+
self._std_weight_position * mean[2],
|
|
302
|
+
self._std_weight_position * mean[3],
|
|
303
|
+
self._std_weight_position * mean[2],
|
|
304
|
+
self._std_weight_position * mean[3],
|
|
305
|
+
]
|
|
269
306
|
innovation_cov = np.diag(np.square(std))
|
|
270
307
|
|
|
271
308
|
mean = np.dot(self._update_mat, mean)
|
|
@@ -285,11 +322,17 @@ class KalmanFilterXYWH(KalmanFilterXYAH):
|
|
|
285
322
|
velocities are initialized to 0 mean.
|
|
286
323
|
"""
|
|
287
324
|
std_pos = [
|
|
288
|
-
self._std_weight_position * mean[:, 2],
|
|
289
|
-
self._std_weight_position * mean[:,
|
|
325
|
+
self._std_weight_position * mean[:, 2],
|
|
326
|
+
self._std_weight_position * mean[:, 3],
|
|
327
|
+
self._std_weight_position * mean[:, 2],
|
|
328
|
+
self._std_weight_position * mean[:, 3],
|
|
329
|
+
]
|
|
290
330
|
std_vel = [
|
|
291
|
-
self._std_weight_velocity * mean[:, 2],
|
|
292
|
-
self._std_weight_velocity * mean[:,
|
|
331
|
+
self._std_weight_velocity * mean[:, 2],
|
|
332
|
+
self._std_weight_velocity * mean[:, 3],
|
|
333
|
+
self._std_weight_velocity * mean[:, 2],
|
|
334
|
+
self._std_weight_velocity * mean[:, 3],
|
|
335
|
+
]
|
|
293
336
|
sqr = np.square(np.r_[std_pos, std_vel]).T
|
|
294
337
|
|
|
295
338
|
motion_cov = [np.diag(sqr[i]) for i in range(len(mean))]
|
|
@@ -13,7 +13,7 @@ try:
|
|
|
13
13
|
except (ImportError, AssertionError, AttributeError):
|
|
14
14
|
from ultralytics.utils.checks import check_requirements
|
|
15
15
|
|
|
16
|
-
check_requirements(
|
|
16
|
+
check_requirements("lapx>=0.5.2") # update to lap package from https://github.com/rathaROG/lapx
|
|
17
17
|
import lap
|
|
18
18
|
|
|
19
19
|
|
|
@@ -70,8 +70,9 @@ def iou_distance(atracks: list, btracks: list) -> np.ndarray:
|
|
|
70
70
|
(np.ndarray): Cost matrix computed based on IoU.
|
|
71
71
|
"""
|
|
72
72
|
|
|
73
|
-
if (len(atracks) > 0 and isinstance(atracks[0], np.ndarray))
|
|
74
|
-
|
|
73
|
+
if (len(atracks) > 0 and isinstance(atracks[0], np.ndarray)) or (
|
|
74
|
+
len(btracks) > 0 and isinstance(btracks[0], np.ndarray)
|
|
75
|
+
):
|
|
75
76
|
atlbrs = atracks
|
|
76
77
|
btlbrs = btracks
|
|
77
78
|
else:
|
|
@@ -80,13 +81,13 @@ def iou_distance(atracks: list, btracks: list) -> np.ndarray:
|
|
|
80
81
|
|
|
81
82
|
ious = np.zeros((len(atlbrs), len(btlbrs)), dtype=np.float32)
|
|
82
83
|
if len(atlbrs) and len(btlbrs):
|
|
83
|
-
ious = bbox_ioa(
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
ious = bbox_ioa(
|
|
85
|
+
np.ascontiguousarray(atlbrs, dtype=np.float32), np.ascontiguousarray(btlbrs, dtype=np.float32), iou=True
|
|
86
|
+
)
|
|
86
87
|
return 1 - ious # cost matrix
|
|
87
88
|
|
|
88
89
|
|
|
89
|
-
def embedding_distance(tracks: list, detections: list, metric: str =
|
|
90
|
+
def embedding_distance(tracks: list, detections: list, metric: str = "cosine") -> np.ndarray:
|
|
90
91
|
"""
|
|
91
92
|
Compute distance between tracks and detections based on embeddings.
|
|
92
93
|
|