77import math
88import 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
1916class 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
4441class 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
6867class 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+
81112def 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