Skip to content
This repository was archived by the owner on Nov 13, 2025. It is now read-only.

Commit 8ce749c

Browse files
committed
Most changes made
1 parent 59c8d94 commit 8ce749c

4 files changed

Lines changed: 124 additions & 73 deletions

File tree

modules/detect_target/detect_target_contour.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515

1616
MIN_CONTOUR_AREA = 100
17+
MAX_CIRCULARITY = 1.3
18+
MIN_CIRCULARITY = 0.7
1719
UPPER_BLUE = np.array([130, 255, 255])
1820
LOWER_BLUE = np.array([100, 50, 50])
1921
CONFIDENCE = 1.0
@@ -29,7 +31,7 @@ def __init__(
2931
self, image_logger: logger.Logger, show_annotations: bool = False, save_name: str = ""
3032
) -> None:
3133
"""
32-
image_logger: Log annotated iamges.
34+
image_logger: Log annotated images.
3335
show_annotations: Display annotated images.
3436
save_name: filename prefix for logging detections and annotated images.
3537
"""
@@ -79,7 +81,7 @@ def detect_landing_pads_contours(
7981
enclosing_area = np.pi * (radius**2)
8082
circularity = contour_area / enclosing_area
8183

82-
if circularity < 0.7 or circularity > 1.3:
84+
if circularity < MIN_CIRCULARITY or circularity > MAX_CIRCULARITY:
8385
continue
8486

8587
x, y, w, h = cv2.boundingRect(contour)

modules/detect_target/detect_target_factory.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class DetectTargetOption(enum.Enum):
1818

1919
ML_ULTRALYTICS = 0
2020
CV_BRIGHTSPOT = 1
21-
C_CONTOUR = 2
21+
CV_CONTOUR = 2
2222

2323

2424
def create_detect_target(
@@ -49,8 +49,9 @@ def create_detect_target(
4949
show_annotations,
5050
save_name,
5151
)
52-
case DetectTargetOption.C_CONTOUR:
52+
case DetectTargetOption.CV_CONTOUR:
5353
return True, detect_target_contour.DetectTargetContour(
54+
local_logger,
5455
show_annotations,
5556
save_name,
5657
)

tests/unit/generate_detect_target_contour.py

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,42 @@
77
import math
88
import numpy as np
99

10-
11-
LANDING_PAD_COLOUR_BLUE = (100, 50, 50) # BGR
10+
from modules import detections_and_time
1211

1312

14-
# Test functions use test fixture signature names and access class privates
15-
# No enable
16-
# pylint: disable=protected-access,redefined-outer-name
13+
LANDING_PAD_COLOUR_BLUE = (100, 50, 50) # BGR
1714

1815

1916
class LandingPadImageConfig:
2017
"""
2118
Represents the data required to define and generate a landing pad.
2219
"""
20+
2321
def __init__(
2422
self,
25-
center: tuple[int, int],
23+
centre: tuple[int, int],
2624
axis: tuple[int, int],
2725
blur: bool,
2826
angle: float,
2927
):
3028
"""
31-
32-
center: The (x, y) coordinates representing the center of the landing pad.
33-
axis: The pixel lengths of the semi-major and semi-minor axes of the ellipse.
29+
centre: The pixel coordinates representing the centre of the landing pad.
30+
axis: The pixel lengths of the semi-major axes of the ellipse.
3431
blur: Indicates whether the landing pad should have a blur effect.
3532
angle: The rotation angle of the landing pad in degrees clockwise, where 0.0 degrees
3633
is where both semi major and minor are aligned with the x and y-axis respectively (0.0 <= angle <= 360.0).
3734
"""
38-
self.center = center
35+
self.centre = centre
3936
self.axis = axis
4037
self.blur = blur
4138
self.angle = angle
4239

4340

4441
class NumpyImage:
4542
"""
46-
Holds the Numpy Array which represents an image.
43+
Holds the numpy array which represents an image.
4744
"""
45+
4846
def __init__(self, image: np.ndarray):
4947
"""
5048
image: A numpy array that represents the image.
@@ -56,46 +54,78 @@ class BoundingBox:
5654
"""
5755
Holds the data that define the generated bounding boxes.
5856
"""
59-
def __init__(self, top_left: tuple[int, int], bottom_right: tuple[int, int]):
57+
58+
def __init__(self, top_left: tuple[float, float], bottom_right: tuple[float, float]):
6059
"""
61-
top_left: x, y coordinates representing the top left corner of the bounding box on an image.
62-
bottom_right: x, y coordinates representing the bottom right corner of the bounding box on an image.
60+
top_left: pixel coordinates representing the top left corner of the bounding box on an image.
61+
bottom_right: pixel coordinates representing the bottom right corner of the bounding box on an image.
6362
"""
6463
self.top_left = top_left
6564
self.bottom_right = bottom_right
6665

6766

6867
class InputImageAndExpectedBoundingBoxes:
69-
'''
68+
"""
7069
Struct to hold the data needed to perform the tests.
71-
'''
70+
"""
71+
7272
def __init__(self, image: np.ndarray, boxes_list: np.ndarray):
7373
"""
74-
image = A numpy array that represents the image needed to be tested.
74+
image: A numpy array that represents the image needed to be tested.
7575
bounding_box_list: A numpy array that holds a list of expected bounding box coordinates.
76+
77+
The bounding box coordinates are in the following format:
78+
top_left_x = boxes_list[0]
79+
top_left_y = boxes_list[1]
80+
81+
bottom_right_x = boxes_list[2]
82+
bottom_right_x = boxes_list[3]
7683
"""
7784
self.image = image
7885
self.bounding_box_list = boxes_list
7986

8087

88+
def create_detections(detections_from_file: np.ndarray) -> detections_and_time.DetectionsAndTime:
89+
"""
90+
Create DetectionsAndTime from expected.
91+
Format: [confidence, label, x_1, y_1, x_2, y_2] .
92+
"""
93+
assert detections_from_file.shape[1] == 6
94+
95+
result, detections = detections_and_time.DetectionsAndTime.create(0)
96+
assert result
97+
assert detections is not None
98+
99+
for i in range(0, detections_from_file.shape[0]):
100+
result, detection = detections_and_time.Detection.create(
101+
detections_from_file[i][2:],
102+
int(detections_from_file[i][1]),
103+
detections_from_file[i][0],
104+
)
105+
assert result
106+
assert detection is not None
107+
detections.append(detection)
108+
109+
return detections
110+
111+
81112
def add_blurred_landing_pad(
82113
background: np.ndarray, landing_data: LandingPadImageConfig
83114
) -> NumpyImage:
84115
"""
85-
Blurs an image and adds a singular lading pad to the background.
116+
Blurs an image and adds a singular landing pad to the background.
86117
87118
background: A numpy image.
88119
landing_data: Landing pad data for the landing pad to be blurred and added.
89120
90-
91121
Returns: Image with the landing pad.
92122
"""
93123
x, y = background.shape[:2]
94124

95125
mask = np.zeros((x, y), np.uint8)
96126
mask = cv2.ellipse(
97127
mask,
98-
landing_data.center,
128+
landing_data.centre,
99129
landing_data.axis,
100130
landing_data.angle,
101131
0,
@@ -125,16 +155,23 @@ def draw_landing_pad(
125155
126156
Returns: Image with landing pad and the bounding box for the drawn landing pad.
127157
"""
128-
(h, k), (a, b) = landing_data.center, landing_data.axis
158+
centre_x, centre_y = landing_data.centre
159+
axis_x, axis_y = landing_data.axis
129160
angle_in_rad = math.radians(landing_data.angle)
130-
ux, uy = a * math.cos(angle_in_rad), a * math.sin(angle_in_rad)
131-
vx, vy = b * math.sin(angle_in_rad), b * math.cos(angle_in_rad)
132-
width, height = 2 * math.sqrt(ux**2 + vx**2), 2 * math.sqrt(uy**2 + vy**2)
133161

134-
top_left = (int(max(h - (0.5) * width, 0)), int(max(k - (0.5) * height, 0)))
162+
ux = axis_x * math.cos(angle_in_rad)
163+
uy = axis_x * math.sin(angle_in_rad)
164+
165+
vx = axis_y * math.sin(angle_in_rad)
166+
vy = axis_y * math.cos(angle_in_rad)
167+
168+
width = 2 * math.sqrt(ux**2 + vx**2)
169+
height = 2 * math.sqrt(uy**2 + vy**2)
170+
171+
top_left = (int(max(centre_x - (0.5) * width, 0)), int(max(centre_y - (0.5) * height, 0)))
135172
bottom_right = (
136-
int(min(h + (0.5) * width, image.shape[1])),
137-
int(min(k + (0.5) * height, image.shape[0])),
173+
min(centre_x + (0.5) * width, image.shape[1]),
174+
min(centre_y + (0.5) * height, image.shape[0]),
138175
)
139176

140177
bounding_box = BoundingBox(top_left, bottom_right)
@@ -145,7 +182,7 @@ def draw_landing_pad(
145182

146183
image = cv2.ellipse(
147184
image,
148-
landing_data.center,
185+
landing_data.centre,
149186
landing_data.axis,
150187
landing_data.angle,
151188
0,
@@ -164,12 +201,11 @@ def create_test(landing_list: list[LandingPadImageConfig]) -> InputImageAndExpec
164201
165202
Returns: The image and expected bounding box.
166203
"""
167-
image = np.full(
168-
shape=(1000, 2000, 3), fill_value=255, dtype=np.int16
169-
)
204+
image = np.full(shape=(1000, 2000, 3), fill_value=255, dtype=np.int8)
170205
confidence_and_label = [1, 0]
171206

172207
# List to hold the bounding boxes.
208+
# boxes_list = [confidence, label, top_left_x, top_left_y, bottom_right_x, bottom_right_y]
173209
boxes_list = []
174210

175211
for landing_data in landing_list:
@@ -179,11 +215,9 @@ def create_test(landing_list: list[LandingPadImageConfig]) -> InputImageAndExpec
179215
confidence_and_label + list(bounding_box.top_left + bounding_box.bottom_right)
180216
)
181217

182-
# Calculates the area of the bounding box.
218+
# Sorts by the area of the bounding box
183219
boxes_list = sorted(
184-
boxes_list,
185-
reverse=True,
186-
key=lambda box: abs((box[4] - box[2]) * (box[5] - box[3])),
220+
boxes_list, reverse=True, key=lambda box: abs((box[4] - box[2]) * (box[5] - box[3]))
187221
)
188222

189223
boxes_list = np.array(boxes_list)

0 commit comments

Comments
 (0)