dgenerate-ultralytics-headless 8.3.134__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.
Files changed (272) hide show
  1. dgenerate_ultralytics_headless-8.3.134.dist-info/METADATA +400 -0
  2. dgenerate_ultralytics_headless-8.3.134.dist-info/RECORD +272 -0
  3. dgenerate_ultralytics_headless-8.3.134.dist-info/WHEEL +5 -0
  4. dgenerate_ultralytics_headless-8.3.134.dist-info/entry_points.txt +3 -0
  5. dgenerate_ultralytics_headless-8.3.134.dist-info/licenses/LICENSE +661 -0
  6. dgenerate_ultralytics_headless-8.3.134.dist-info/top_level.txt +1 -0
  7. tests/__init__.py +22 -0
  8. tests/conftest.py +83 -0
  9. tests/test_cli.py +138 -0
  10. tests/test_cuda.py +215 -0
  11. tests/test_engine.py +131 -0
  12. tests/test_exports.py +236 -0
  13. tests/test_integrations.py +154 -0
  14. tests/test_python.py +694 -0
  15. tests/test_solutions.py +187 -0
  16. ultralytics/__init__.py +30 -0
  17. ultralytics/assets/bus.jpg +0 -0
  18. ultralytics/assets/zidane.jpg +0 -0
  19. ultralytics/cfg/__init__.py +1023 -0
  20. ultralytics/cfg/datasets/Argoverse.yaml +77 -0
  21. ultralytics/cfg/datasets/DOTAv1.5.yaml +37 -0
  22. ultralytics/cfg/datasets/DOTAv1.yaml +36 -0
  23. ultralytics/cfg/datasets/GlobalWheat2020.yaml +68 -0
  24. ultralytics/cfg/datasets/HomeObjects-3K.yaml +33 -0
  25. ultralytics/cfg/datasets/ImageNet.yaml +2025 -0
  26. ultralytics/cfg/datasets/Objects365.yaml +443 -0
  27. ultralytics/cfg/datasets/SKU-110K.yaml +58 -0
  28. ultralytics/cfg/datasets/VOC.yaml +106 -0
  29. ultralytics/cfg/datasets/VisDrone.yaml +77 -0
  30. ultralytics/cfg/datasets/african-wildlife.yaml +25 -0
  31. ultralytics/cfg/datasets/brain-tumor.yaml +23 -0
  32. ultralytics/cfg/datasets/carparts-seg.yaml +44 -0
  33. ultralytics/cfg/datasets/coco-pose.yaml +42 -0
  34. ultralytics/cfg/datasets/coco.yaml +118 -0
  35. ultralytics/cfg/datasets/coco128-seg.yaml +101 -0
  36. ultralytics/cfg/datasets/coco128.yaml +101 -0
  37. ultralytics/cfg/datasets/coco8-multispectral.yaml +104 -0
  38. ultralytics/cfg/datasets/coco8-pose.yaml +26 -0
  39. ultralytics/cfg/datasets/coco8-seg.yaml +101 -0
  40. ultralytics/cfg/datasets/coco8.yaml +101 -0
  41. ultralytics/cfg/datasets/crack-seg.yaml +22 -0
  42. ultralytics/cfg/datasets/dog-pose.yaml +24 -0
  43. ultralytics/cfg/datasets/dota8-multispectral.yaml +38 -0
  44. ultralytics/cfg/datasets/dota8.yaml +35 -0
  45. ultralytics/cfg/datasets/hand-keypoints.yaml +26 -0
  46. ultralytics/cfg/datasets/lvis.yaml +1240 -0
  47. ultralytics/cfg/datasets/medical-pills.yaml +22 -0
  48. ultralytics/cfg/datasets/open-images-v7.yaml +666 -0
  49. ultralytics/cfg/datasets/package-seg.yaml +22 -0
  50. ultralytics/cfg/datasets/signature.yaml +21 -0
  51. ultralytics/cfg/datasets/tiger-pose.yaml +25 -0
  52. ultralytics/cfg/datasets/xView.yaml +155 -0
  53. ultralytics/cfg/default.yaml +127 -0
  54. ultralytics/cfg/models/11/yolo11-cls-resnet18.yaml +17 -0
  55. ultralytics/cfg/models/11/yolo11-cls.yaml +33 -0
  56. ultralytics/cfg/models/11/yolo11-obb.yaml +50 -0
  57. ultralytics/cfg/models/11/yolo11-pose.yaml +51 -0
  58. ultralytics/cfg/models/11/yolo11-seg.yaml +50 -0
  59. ultralytics/cfg/models/11/yolo11.yaml +50 -0
  60. ultralytics/cfg/models/11/yoloe-11-seg.yaml +48 -0
  61. ultralytics/cfg/models/11/yoloe-11.yaml +48 -0
  62. ultralytics/cfg/models/12/yolo12-cls.yaml +32 -0
  63. ultralytics/cfg/models/12/yolo12-obb.yaml +48 -0
  64. ultralytics/cfg/models/12/yolo12-pose.yaml +49 -0
  65. ultralytics/cfg/models/12/yolo12-seg.yaml +48 -0
  66. ultralytics/cfg/models/12/yolo12.yaml +48 -0
  67. ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +53 -0
  68. ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +45 -0
  69. ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +45 -0
  70. ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +57 -0
  71. ultralytics/cfg/models/v10/yolov10b.yaml +45 -0
  72. ultralytics/cfg/models/v10/yolov10l.yaml +45 -0
  73. ultralytics/cfg/models/v10/yolov10m.yaml +45 -0
  74. ultralytics/cfg/models/v10/yolov10n.yaml +45 -0
  75. ultralytics/cfg/models/v10/yolov10s.yaml +45 -0
  76. ultralytics/cfg/models/v10/yolov10x.yaml +45 -0
  77. ultralytics/cfg/models/v3/yolov3-spp.yaml +49 -0
  78. ultralytics/cfg/models/v3/yolov3-tiny.yaml +40 -0
  79. ultralytics/cfg/models/v3/yolov3.yaml +49 -0
  80. ultralytics/cfg/models/v5/yolov5-p6.yaml +62 -0
  81. ultralytics/cfg/models/v5/yolov5.yaml +51 -0
  82. ultralytics/cfg/models/v6/yolov6.yaml +56 -0
  83. ultralytics/cfg/models/v8/yoloe-v8-seg.yaml +45 -0
  84. ultralytics/cfg/models/v8/yoloe-v8.yaml +45 -0
  85. ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +28 -0
  86. ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +28 -0
  87. ultralytics/cfg/models/v8/yolov8-cls.yaml +32 -0
  88. ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +58 -0
  89. ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +60 -0
  90. ultralytics/cfg/models/v8/yolov8-ghost.yaml +50 -0
  91. ultralytics/cfg/models/v8/yolov8-obb.yaml +49 -0
  92. ultralytics/cfg/models/v8/yolov8-p2.yaml +57 -0
  93. ultralytics/cfg/models/v8/yolov8-p6.yaml +59 -0
  94. ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +60 -0
  95. ultralytics/cfg/models/v8/yolov8-pose.yaml +50 -0
  96. ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +49 -0
  97. ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +59 -0
  98. ultralytics/cfg/models/v8/yolov8-seg.yaml +49 -0
  99. ultralytics/cfg/models/v8/yolov8-world.yaml +51 -0
  100. ultralytics/cfg/models/v8/yolov8-worldv2.yaml +49 -0
  101. ultralytics/cfg/models/v8/yolov8.yaml +49 -0
  102. ultralytics/cfg/models/v9/yolov9c-seg.yaml +41 -0
  103. ultralytics/cfg/models/v9/yolov9c.yaml +41 -0
  104. ultralytics/cfg/models/v9/yolov9e-seg.yaml +64 -0
  105. ultralytics/cfg/models/v9/yolov9e.yaml +64 -0
  106. ultralytics/cfg/models/v9/yolov9m.yaml +41 -0
  107. ultralytics/cfg/models/v9/yolov9s.yaml +41 -0
  108. ultralytics/cfg/models/v9/yolov9t.yaml +41 -0
  109. ultralytics/cfg/trackers/botsort.yaml +22 -0
  110. ultralytics/cfg/trackers/bytetrack.yaml +14 -0
  111. ultralytics/data/__init__.py +26 -0
  112. ultralytics/data/annotator.py +66 -0
  113. ultralytics/data/augment.py +2945 -0
  114. ultralytics/data/base.py +438 -0
  115. ultralytics/data/build.py +258 -0
  116. ultralytics/data/converter.py +754 -0
  117. ultralytics/data/dataset.py +834 -0
  118. ultralytics/data/loaders.py +676 -0
  119. ultralytics/data/scripts/download_weights.sh +18 -0
  120. ultralytics/data/scripts/get_coco.sh +61 -0
  121. ultralytics/data/scripts/get_coco128.sh +18 -0
  122. ultralytics/data/scripts/get_imagenet.sh +52 -0
  123. ultralytics/data/split.py +125 -0
  124. ultralytics/data/split_dota.py +325 -0
  125. ultralytics/data/utils.py +777 -0
  126. ultralytics/engine/__init__.py +1 -0
  127. ultralytics/engine/exporter.py +1519 -0
  128. ultralytics/engine/model.py +1156 -0
  129. ultralytics/engine/predictor.py +502 -0
  130. ultralytics/engine/results.py +1840 -0
  131. ultralytics/engine/trainer.py +853 -0
  132. ultralytics/engine/tuner.py +243 -0
  133. ultralytics/engine/validator.py +377 -0
  134. ultralytics/hub/__init__.py +168 -0
  135. ultralytics/hub/auth.py +137 -0
  136. ultralytics/hub/google/__init__.py +176 -0
  137. ultralytics/hub/session.py +446 -0
  138. ultralytics/hub/utils.py +248 -0
  139. ultralytics/models/__init__.py +9 -0
  140. ultralytics/models/fastsam/__init__.py +7 -0
  141. ultralytics/models/fastsam/model.py +61 -0
  142. ultralytics/models/fastsam/predict.py +181 -0
  143. ultralytics/models/fastsam/utils.py +24 -0
  144. ultralytics/models/fastsam/val.py +40 -0
  145. ultralytics/models/nas/__init__.py +7 -0
  146. ultralytics/models/nas/model.py +102 -0
  147. ultralytics/models/nas/predict.py +58 -0
  148. ultralytics/models/nas/val.py +39 -0
  149. ultralytics/models/rtdetr/__init__.py +7 -0
  150. ultralytics/models/rtdetr/model.py +63 -0
  151. ultralytics/models/rtdetr/predict.py +84 -0
  152. ultralytics/models/rtdetr/train.py +85 -0
  153. ultralytics/models/rtdetr/val.py +191 -0
  154. ultralytics/models/sam/__init__.py +6 -0
  155. ultralytics/models/sam/amg.py +260 -0
  156. ultralytics/models/sam/build.py +358 -0
  157. ultralytics/models/sam/model.py +170 -0
  158. ultralytics/models/sam/modules/__init__.py +1 -0
  159. ultralytics/models/sam/modules/blocks.py +1129 -0
  160. ultralytics/models/sam/modules/decoders.py +515 -0
  161. ultralytics/models/sam/modules/encoders.py +854 -0
  162. ultralytics/models/sam/modules/memory_attention.py +299 -0
  163. ultralytics/models/sam/modules/sam.py +1006 -0
  164. ultralytics/models/sam/modules/tiny_encoder.py +1002 -0
  165. ultralytics/models/sam/modules/transformer.py +351 -0
  166. ultralytics/models/sam/modules/utils.py +394 -0
  167. ultralytics/models/sam/predict.py +1605 -0
  168. ultralytics/models/utils/__init__.py +1 -0
  169. ultralytics/models/utils/loss.py +455 -0
  170. ultralytics/models/utils/ops.py +268 -0
  171. ultralytics/models/yolo/__init__.py +7 -0
  172. ultralytics/models/yolo/classify/__init__.py +7 -0
  173. ultralytics/models/yolo/classify/predict.py +88 -0
  174. ultralytics/models/yolo/classify/train.py +233 -0
  175. ultralytics/models/yolo/classify/val.py +215 -0
  176. ultralytics/models/yolo/detect/__init__.py +7 -0
  177. ultralytics/models/yolo/detect/predict.py +124 -0
  178. ultralytics/models/yolo/detect/train.py +217 -0
  179. ultralytics/models/yolo/detect/val.py +451 -0
  180. ultralytics/models/yolo/model.py +354 -0
  181. ultralytics/models/yolo/obb/__init__.py +7 -0
  182. ultralytics/models/yolo/obb/predict.py +66 -0
  183. ultralytics/models/yolo/obb/train.py +81 -0
  184. ultralytics/models/yolo/obb/val.py +283 -0
  185. ultralytics/models/yolo/pose/__init__.py +7 -0
  186. ultralytics/models/yolo/pose/predict.py +79 -0
  187. ultralytics/models/yolo/pose/train.py +154 -0
  188. ultralytics/models/yolo/pose/val.py +394 -0
  189. ultralytics/models/yolo/segment/__init__.py +7 -0
  190. ultralytics/models/yolo/segment/predict.py +113 -0
  191. ultralytics/models/yolo/segment/train.py +123 -0
  192. ultralytics/models/yolo/segment/val.py +428 -0
  193. ultralytics/models/yolo/world/__init__.py +5 -0
  194. ultralytics/models/yolo/world/train.py +119 -0
  195. ultralytics/models/yolo/world/train_world.py +176 -0
  196. ultralytics/models/yolo/yoloe/__init__.py +22 -0
  197. ultralytics/models/yolo/yoloe/predict.py +169 -0
  198. ultralytics/models/yolo/yoloe/train.py +298 -0
  199. ultralytics/models/yolo/yoloe/train_seg.py +124 -0
  200. ultralytics/models/yolo/yoloe/val.py +191 -0
  201. ultralytics/nn/__init__.py +29 -0
  202. ultralytics/nn/autobackend.py +842 -0
  203. ultralytics/nn/modules/__init__.py +182 -0
  204. ultralytics/nn/modules/activation.py +53 -0
  205. ultralytics/nn/modules/block.py +1966 -0
  206. ultralytics/nn/modules/conv.py +712 -0
  207. ultralytics/nn/modules/head.py +880 -0
  208. ultralytics/nn/modules/transformer.py +713 -0
  209. ultralytics/nn/modules/utils.py +164 -0
  210. ultralytics/nn/tasks.py +1627 -0
  211. ultralytics/nn/text_model.py +351 -0
  212. ultralytics/solutions/__init__.py +41 -0
  213. ultralytics/solutions/ai_gym.py +116 -0
  214. ultralytics/solutions/analytics.py +252 -0
  215. ultralytics/solutions/config.py +106 -0
  216. ultralytics/solutions/distance_calculation.py +124 -0
  217. ultralytics/solutions/heatmap.py +127 -0
  218. ultralytics/solutions/instance_segmentation.py +84 -0
  219. ultralytics/solutions/object_blurrer.py +90 -0
  220. ultralytics/solutions/object_counter.py +195 -0
  221. ultralytics/solutions/object_cropper.py +84 -0
  222. ultralytics/solutions/parking_management.py +273 -0
  223. ultralytics/solutions/queue_management.py +93 -0
  224. ultralytics/solutions/region_counter.py +120 -0
  225. ultralytics/solutions/security_alarm.py +154 -0
  226. ultralytics/solutions/similarity_search.py +172 -0
  227. ultralytics/solutions/solutions.py +724 -0
  228. ultralytics/solutions/speed_estimation.py +110 -0
  229. ultralytics/solutions/streamlit_inference.py +196 -0
  230. ultralytics/solutions/templates/similarity-search.html +160 -0
  231. ultralytics/solutions/trackzone.py +88 -0
  232. ultralytics/solutions/vision_eye.py +68 -0
  233. ultralytics/trackers/__init__.py +7 -0
  234. ultralytics/trackers/basetrack.py +124 -0
  235. ultralytics/trackers/bot_sort.py +260 -0
  236. ultralytics/trackers/byte_tracker.py +480 -0
  237. ultralytics/trackers/track.py +125 -0
  238. ultralytics/trackers/utils/__init__.py +1 -0
  239. ultralytics/trackers/utils/gmc.py +376 -0
  240. ultralytics/trackers/utils/kalman_filter.py +493 -0
  241. ultralytics/trackers/utils/matching.py +157 -0
  242. ultralytics/utils/__init__.py +1435 -0
  243. ultralytics/utils/autobatch.py +106 -0
  244. ultralytics/utils/autodevice.py +174 -0
  245. ultralytics/utils/benchmarks.py +695 -0
  246. ultralytics/utils/callbacks/__init__.py +5 -0
  247. ultralytics/utils/callbacks/base.py +234 -0
  248. ultralytics/utils/callbacks/clearml.py +153 -0
  249. ultralytics/utils/callbacks/comet.py +552 -0
  250. ultralytics/utils/callbacks/dvc.py +205 -0
  251. ultralytics/utils/callbacks/hub.py +108 -0
  252. ultralytics/utils/callbacks/mlflow.py +138 -0
  253. ultralytics/utils/callbacks/neptune.py +140 -0
  254. ultralytics/utils/callbacks/raytune.py +43 -0
  255. ultralytics/utils/callbacks/tensorboard.py +132 -0
  256. ultralytics/utils/callbacks/wb.py +185 -0
  257. ultralytics/utils/checks.py +897 -0
  258. ultralytics/utils/dist.py +119 -0
  259. ultralytics/utils/downloads.py +499 -0
  260. ultralytics/utils/errors.py +43 -0
  261. ultralytics/utils/export.py +219 -0
  262. ultralytics/utils/files.py +221 -0
  263. ultralytics/utils/instance.py +499 -0
  264. ultralytics/utils/loss.py +813 -0
  265. ultralytics/utils/metrics.py +1356 -0
  266. ultralytics/utils/ops.py +885 -0
  267. ultralytics/utils/patches.py +143 -0
  268. ultralytics/utils/plotting.py +1011 -0
  269. ultralytics/utils/tal.py +416 -0
  270. ultralytics/utils/torch_utils.py +990 -0
  271. ultralytics/utils/triton.py +116 -0
  272. ultralytics/utils/tuner.py +159 -0
@@ -0,0 +1,376 @@
1
+ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
+
3
+ import copy
4
+
5
+ import cv2
6
+ import numpy as np
7
+
8
+ from ultralytics.utils import LOGGER
9
+
10
+
11
+ class GMC:
12
+ """
13
+ Generalized Motion Compensation (GMC) class for tracking and object detection in video frames.
14
+
15
+ This class provides methods for tracking and detecting objects based on several tracking algorithms including ORB,
16
+ SIFT, ECC, and Sparse Optical Flow. It also supports downscaling of frames for computational efficiency.
17
+
18
+ Attributes:
19
+ method (str): The tracking method to use. Options include 'orb', 'sift', 'ecc', 'sparseOptFlow', 'none'.
20
+ downscale (int): Factor by which to downscale the frames for processing.
21
+ prevFrame (np.ndarray): Previous frame for tracking.
22
+ prevKeyPoints (list): Keypoints from the previous frame.
23
+ prevDescriptors (np.ndarray): Descriptors from the previous frame.
24
+ initializedFirstFrame (bool): Flag indicating if the first frame has been processed.
25
+
26
+ Methods:
27
+ apply: Apply the chosen method to a raw frame and optionally use provided detections.
28
+ apply_ecc: Apply the ECC algorithm to a raw frame.
29
+ apply_features: Apply feature-based methods like ORB or SIFT to a raw frame.
30
+ apply_sparseoptflow: Apply the Sparse Optical Flow method to a raw frame.
31
+ reset_params: Reset the internal parameters of the GMC object.
32
+
33
+ Examples:
34
+ Create a GMC object and apply it to a frame
35
+ >>> gmc = GMC(method="sparseOptFlow", downscale=2)
36
+ >>> frame = np.array([[1, 2, 3], [4, 5, 6]])
37
+ >>> processed_frame = gmc.apply(frame)
38
+ >>> print(processed_frame)
39
+ array([[1, 2, 3],
40
+ [4, 5, 6]])
41
+ """
42
+
43
+ def __init__(self, method: str = "sparseOptFlow", downscale: int = 2) -> None:
44
+ """
45
+ Initialize a Generalized Motion Compensation (GMC) object with tracking method and downscale factor.
46
+
47
+ Args:
48
+ method (str): The tracking method to use. Options include 'orb', 'sift', 'ecc', 'sparseOptFlow', 'none'.
49
+ downscale (int): Downscale factor for processing frames.
50
+
51
+ Examples:
52
+ Initialize a GMC object with the 'sparseOptFlow' method and a downscale factor of 2
53
+ >>> gmc = GMC(method="sparseOptFlow", downscale=2)
54
+ """
55
+ super().__init__()
56
+
57
+ self.method = method
58
+ self.downscale = max(1, downscale)
59
+
60
+ if self.method == "orb":
61
+ self.detector = cv2.FastFeatureDetector_create(20)
62
+ self.extractor = cv2.ORB_create()
63
+ self.matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
64
+
65
+ elif self.method == "sift":
66
+ self.detector = cv2.SIFT_create(nOctaveLayers=3, contrastThreshold=0.02, edgeThreshold=20)
67
+ self.extractor = cv2.SIFT_create(nOctaveLayers=3, contrastThreshold=0.02, edgeThreshold=20)
68
+ self.matcher = cv2.BFMatcher(cv2.NORM_L2)
69
+
70
+ elif self.method == "ecc":
71
+ number_of_iterations = 5000
72
+ termination_eps = 1e-6
73
+ self.warp_mode = cv2.MOTION_EUCLIDEAN
74
+ self.criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, number_of_iterations, termination_eps)
75
+
76
+ elif self.method == "sparseOptFlow":
77
+ self.feature_params = dict(
78
+ maxCorners=1000, qualityLevel=0.01, minDistance=1, blockSize=3, useHarrisDetector=False, k=0.04
79
+ )
80
+
81
+ elif self.method in {"none", "None", None}:
82
+ self.method = None
83
+ else:
84
+ raise ValueError(f"Unknown GMC method: {method}")
85
+
86
+ self.prevFrame = None
87
+ self.prevKeyPoints = None
88
+ self.prevDescriptors = None
89
+ self.initializedFirstFrame = False
90
+
91
+ def apply(self, raw_frame: np.ndarray, detections: list = None) -> np.ndarray:
92
+ """
93
+ Apply object detection on a raw frame using the specified method.
94
+
95
+ Args:
96
+ raw_frame (np.ndarray): The raw frame to be processed, with shape (H, W, C).
97
+ detections (List | None): List of detections to be used in the processing.
98
+
99
+ Returns:
100
+ (np.ndarray): Transformation matrix with shape (2, 3).
101
+
102
+ Examples:
103
+ >>> gmc = GMC(method="sparseOptFlow")
104
+ >>> raw_frame = np.random.rand(480, 640, 3)
105
+ >>> transformation_matrix = gmc.apply(raw_frame)
106
+ >>> print(transformation_matrix.shape)
107
+ (2, 3)
108
+ """
109
+ if self.method in {"orb", "sift"}:
110
+ return self.apply_features(raw_frame, detections)
111
+ elif self.method == "ecc":
112
+ return self.apply_ecc(raw_frame)
113
+ elif self.method == "sparseOptFlow":
114
+ return self.apply_sparseoptflow(raw_frame)
115
+ else:
116
+ return np.eye(2, 3)
117
+
118
+ def apply_ecc(self, raw_frame: np.ndarray) -> np.ndarray:
119
+ """
120
+ Apply the ECC (Enhanced Correlation Coefficient) algorithm to a raw frame for motion compensation.
121
+
122
+ Args:
123
+ raw_frame (np.ndarray): The raw frame to be processed, with shape (H, W, C).
124
+
125
+ Returns:
126
+ (np.ndarray): Transformation matrix with shape (2, 3).
127
+
128
+ Examples:
129
+ >>> gmc = GMC(method="ecc")
130
+ >>> processed_frame = gmc.apply_ecc(np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]))
131
+ >>> print(processed_frame)
132
+ [[1. 0. 0.]
133
+ [0. 1. 0.]]
134
+ """
135
+ height, width, c = raw_frame.shape
136
+ frame = cv2.cvtColor(raw_frame, cv2.COLOR_BGR2GRAY) if c == 3 else raw_frame
137
+ H = np.eye(2, 3, dtype=np.float32)
138
+
139
+ # Downscale image
140
+ if self.downscale > 1.0:
141
+ frame = cv2.GaussianBlur(frame, (3, 3), 1.5)
142
+ frame = cv2.resize(frame, (width // self.downscale, height // self.downscale))
143
+
144
+ # Handle first frame
145
+ if not self.initializedFirstFrame:
146
+ # Initialize data
147
+ self.prevFrame = frame.copy()
148
+
149
+ # Initialization done
150
+ self.initializedFirstFrame = True
151
+
152
+ return H
153
+
154
+ # Run the ECC algorithm. The results are stored in warp_matrix.
155
+ # (cc, H) = cv2.findTransformECC(self.prevFrame, frame, H, self.warp_mode, self.criteria)
156
+ try:
157
+ (_, H) = cv2.findTransformECC(self.prevFrame, frame, H, self.warp_mode, self.criteria, None, 1)
158
+ except Exception as e:
159
+ LOGGER.warning(f"find transform failed. Set warp as identity {e}")
160
+
161
+ return H
162
+
163
+ def apply_features(self, raw_frame: np.ndarray, detections: list = None) -> np.ndarray:
164
+ """
165
+ Apply feature-based methods like ORB or SIFT to a raw frame.
166
+
167
+ Args:
168
+ raw_frame (np.ndarray): The raw frame to be processed, with shape (H, W, C).
169
+ detections (List | None): List of detections to be used in the processing.
170
+
171
+ Returns:
172
+ (np.ndarray): Transformation matrix with shape (2, 3).
173
+
174
+ Examples:
175
+ >>> gmc = GMC(method="orb")
176
+ >>> raw_frame = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)
177
+ >>> transformation_matrix = gmc.apply_features(raw_frame)
178
+ >>> print(transformation_matrix.shape)
179
+ (2, 3)
180
+ """
181
+ height, width, c = raw_frame.shape
182
+ frame = cv2.cvtColor(raw_frame, cv2.COLOR_BGR2GRAY) if c == 3 else raw_frame
183
+ H = np.eye(2, 3)
184
+
185
+ # Downscale image
186
+ if self.downscale > 1.0:
187
+ frame = cv2.resize(frame, (width // self.downscale, height // self.downscale))
188
+ width = width // self.downscale
189
+ height = height // self.downscale
190
+
191
+ # Find the keypoints
192
+ mask = np.zeros_like(frame)
193
+ mask[int(0.02 * height) : int(0.98 * height), int(0.02 * width) : int(0.98 * width)] = 255
194
+ if detections is not None:
195
+ for det in detections:
196
+ tlbr = (det[:4] / self.downscale).astype(np.int_)
197
+ mask[tlbr[1] : tlbr[3], tlbr[0] : tlbr[2]] = 0
198
+
199
+ keypoints = self.detector.detect(frame, mask)
200
+
201
+ # Compute the descriptors
202
+ keypoints, descriptors = self.extractor.compute(frame, keypoints)
203
+
204
+ # Handle first frame
205
+ if not self.initializedFirstFrame:
206
+ # Initialize data
207
+ self.prevFrame = frame.copy()
208
+ self.prevKeyPoints = copy.copy(keypoints)
209
+ self.prevDescriptors = copy.copy(descriptors)
210
+
211
+ # Initialization done
212
+ self.initializedFirstFrame = True
213
+
214
+ return H
215
+
216
+ # Match descriptors
217
+ knnMatches = self.matcher.knnMatch(self.prevDescriptors, descriptors, 2)
218
+
219
+ # Filter matches based on smallest spatial distance
220
+ matches = []
221
+ spatialDistances = []
222
+
223
+ maxSpatialDistance = 0.25 * np.array([width, height])
224
+
225
+ # Handle empty matches case
226
+ if len(knnMatches) == 0:
227
+ # Store to next iteration
228
+ self.prevFrame = frame.copy()
229
+ self.prevKeyPoints = copy.copy(keypoints)
230
+ self.prevDescriptors = copy.copy(descriptors)
231
+
232
+ return H
233
+
234
+ for m, n in knnMatches:
235
+ if m.distance < 0.9 * n.distance:
236
+ prevKeyPointLocation = self.prevKeyPoints[m.queryIdx].pt
237
+ currKeyPointLocation = keypoints[m.trainIdx].pt
238
+
239
+ spatialDistance = (
240
+ prevKeyPointLocation[0] - currKeyPointLocation[0],
241
+ prevKeyPointLocation[1] - currKeyPointLocation[1],
242
+ )
243
+
244
+ if (np.abs(spatialDistance[0]) < maxSpatialDistance[0]) and (
245
+ np.abs(spatialDistance[1]) < maxSpatialDistance[1]
246
+ ):
247
+ spatialDistances.append(spatialDistance)
248
+ matches.append(m)
249
+
250
+ meanSpatialDistances = np.mean(spatialDistances, 0)
251
+ stdSpatialDistances = np.std(spatialDistances, 0)
252
+
253
+ inliers = (spatialDistances - meanSpatialDistances) < 2.5 * stdSpatialDistances
254
+
255
+ goodMatches = []
256
+ prevPoints = []
257
+ currPoints = []
258
+ for i in range(len(matches)):
259
+ if inliers[i, 0] and inliers[i, 1]:
260
+ goodMatches.append(matches[i])
261
+ prevPoints.append(self.prevKeyPoints[matches[i].queryIdx].pt)
262
+ currPoints.append(keypoints[matches[i].trainIdx].pt)
263
+
264
+ prevPoints = np.array(prevPoints)
265
+ currPoints = np.array(currPoints)
266
+
267
+ # Draw the keypoint matches on the output image
268
+ # if False:
269
+ # import matplotlib.pyplot as plt
270
+ # matches_img = np.hstack((self.prevFrame, frame))
271
+ # matches_img = cv2.cvtColor(matches_img, cv2.COLOR_GRAY2BGR)
272
+ # W = self.prevFrame.shape[1]
273
+ # for m in goodMatches:
274
+ # prev_pt = np.array(self.prevKeyPoints[m.queryIdx].pt, dtype=np.int_)
275
+ # curr_pt = np.array(keypoints[m.trainIdx].pt, dtype=np.int_)
276
+ # curr_pt[0] += W
277
+ # color = np.random.randint(0, 255, 3)
278
+ # color = (int(color[0]), int(color[1]), int(color[2]))
279
+ #
280
+ # matches_img = cv2.line(matches_img, prev_pt, curr_pt, tuple(color), 1, cv2.LINE_AA)
281
+ # matches_img = cv2.circle(matches_img, prev_pt, 2, tuple(color), -1)
282
+ # matches_img = cv2.circle(matches_img, curr_pt, 2, tuple(color), -1)
283
+ #
284
+ # plt.figure()
285
+ # plt.imshow(matches_img)
286
+ # plt.show()
287
+
288
+ # Find rigid matrix
289
+ if prevPoints.shape[0] > 4:
290
+ H, inliers = cv2.estimateAffinePartial2D(prevPoints, currPoints, cv2.RANSAC)
291
+
292
+ # Handle downscale
293
+ if self.downscale > 1.0:
294
+ H[0, 2] *= self.downscale
295
+ H[1, 2] *= self.downscale
296
+ else:
297
+ LOGGER.warning("not enough matching points")
298
+
299
+ # Store to next iteration
300
+ self.prevFrame = frame.copy()
301
+ self.prevKeyPoints = copy.copy(keypoints)
302
+ self.prevDescriptors = copy.copy(descriptors)
303
+
304
+ return H
305
+
306
+ def apply_sparseoptflow(self, raw_frame: np.ndarray) -> np.ndarray:
307
+ """
308
+ Apply Sparse Optical Flow method to a raw frame.
309
+
310
+ Args:
311
+ raw_frame (np.ndarray): The raw frame to be processed, with shape (H, W, C).
312
+
313
+ Returns:
314
+ (np.ndarray): Transformation matrix with shape (2, 3).
315
+
316
+ Examples:
317
+ >>> gmc = GMC()
318
+ >>> result = gmc.apply_sparseoptflow(np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]))
319
+ >>> print(result)
320
+ [[1. 0. 0.]
321
+ [0. 1. 0.]]
322
+ """
323
+ height, width, c = raw_frame.shape
324
+ frame = cv2.cvtColor(raw_frame, cv2.COLOR_BGR2GRAY) if c == 3 else raw_frame
325
+ H = np.eye(2, 3)
326
+
327
+ # Downscale image
328
+ if self.downscale > 1.0:
329
+ frame = cv2.resize(frame, (width // self.downscale, height // self.downscale))
330
+
331
+ # Find the keypoints
332
+ keypoints = cv2.goodFeaturesToTrack(frame, mask=None, **self.feature_params)
333
+
334
+ # Handle first frame
335
+ if not self.initializedFirstFrame or self.prevKeyPoints is None:
336
+ self.prevFrame = frame.copy()
337
+ self.prevKeyPoints = copy.copy(keypoints)
338
+ self.initializedFirstFrame = True
339
+ return H
340
+
341
+ # Find correspondences
342
+ matchedKeypoints, status, _ = cv2.calcOpticalFlowPyrLK(self.prevFrame, frame, self.prevKeyPoints, None)
343
+
344
+ # Leave good correspondences only
345
+ prevPoints = []
346
+ currPoints = []
347
+
348
+ for i in range(len(status)):
349
+ if status[i]:
350
+ prevPoints.append(self.prevKeyPoints[i])
351
+ currPoints.append(matchedKeypoints[i])
352
+
353
+ prevPoints = np.array(prevPoints)
354
+ currPoints = np.array(currPoints)
355
+
356
+ # Find rigid matrix
357
+ if (prevPoints.shape[0] > 4) and (prevPoints.shape[0] == currPoints.shape[0]):
358
+ H, _ = cv2.estimateAffinePartial2D(prevPoints, currPoints, cv2.RANSAC)
359
+
360
+ if self.downscale > 1.0:
361
+ H[0, 2] *= self.downscale
362
+ H[1, 2] *= self.downscale
363
+ else:
364
+ LOGGER.warning("not enough matching points")
365
+
366
+ self.prevFrame = frame.copy()
367
+ self.prevKeyPoints = copy.copy(keypoints)
368
+
369
+ return H
370
+
371
+ def reset_params(self) -> None:
372
+ """Reset the internal parameters including previous frame, keypoints, and descriptors."""
373
+ self.prevFrame = None
374
+ self.prevKeyPoints = None
375
+ self.prevDescriptors = None
376
+ self.initializedFirstFrame = False