This repository was archived by the owner on Nov 13, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathlanding_pad_tracking.py
More file actions
97 lines (81 loc) · 3.85 KB
/
landing_pad_tracking.py
File metadata and controls
97 lines (81 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""
Keeps track of detected and visited landing pads.
"""
from .. import object_in_world
class LandingPadTracking:
"""
Tracks the real world location of detected landing pads, labelling them as either confirmed
positive, unconfirmed positive, or false positive.
"""
def __init__(self, distance_squared_threshold: float) -> None:
self.__unconfirmed_positives: "list[object_in_world.ObjectInWorld]" = []
self.__false_positives: "list[object_in_world.ObjectInWorld]" = []
self.__confirmed_positives: "list[object_in_world.ObjectInWorld]" = []
# Landing pads within the square root of this distance are considered the same landing pad
self.__distance_squared_threshold = distance_squared_threshold
@staticmethod
def __is_similar(
detection_1: object_in_world.ObjectInWorld,
detection_2: object_in_world.ObjectInWorld,
distance_squared_threshold: float,
) -> bool:
"""
Returns whether detection_1 and detection_2 are close enough to be considered the same
landing pad.
"""
distance_squared = (detection_2.location_x - detection_1.location_x) ** 2 + (
detection_2.location_y - detection_1.location_y
) ** 2
return distance_squared < distance_squared_threshold
def mark_false_positive(self, detection: object_in_world.ObjectInWorld) -> None:
"""
Marks a detection as false positive and removes similar landing pads from the list of
unconfirmed positives.
"""
self.__false_positives.append(detection)
self.__unconfirmed_positives = [
landing_pad
for landing_pad in self.__unconfirmed_positives
if not self.__is_similar(landing_pad, detection, self.__distance_squared_threshold)
]
def mark_confirmed_positive(self, detection: object_in_world.ObjectInWorld) -> None:
"""
Marks a detection as a confimred positive for future use.
"""
self.__confirmed_positives.append(detection)
def run(
self, detections: "list[object_in_world.ObjectInWorld]"
) -> "tuple[bool, list[object_in_world.ObjectInWorld] | None]":
"""
Updates the list of unconfirmed positives and returns the a first confirmed positive if
one exists, else the unconfirmed positive with the lowest variance.
"""
for detection in detections:
match_found = False
# If detection matches a false positive, don't add it
for false_positive in self.__false_positives:
if self.__is_similar(detection, false_positive, self.__distance_squared_threshold):
match_found = True
break
if match_found:
continue
# If detection matches an unconfirmed positive, replace old detection
for i, landing_pad in enumerate(self.__unconfirmed_positives):
if self.__is_similar(detection, landing_pad, self.__distance_squared_threshold):
match_found = True
self.__unconfirmed_positives[i] = detection
break
if match_found:
continue
# If new landing pad, add to list of unconfirmed positives
self.__unconfirmed_positives.append(detection)
# If there are confirmed positives, return the entire list
if len(self.__confirmed_positives) > 0:
return True, self.__confirmed_positives
# If the list is empty, all landing pads have been visited, none are viable
if len(self.__unconfirmed_positives) == 0:
return False, None
# Sort list by variance in ascending order
self.__unconfirmed_positives.sort(key=lambda x: x.spherical_variance)
# Return all detections
return True, self.__unconfirmed_positives