opsci-toolbox 0.0.5__py3-none-any.whl → 0.0.6__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.
- opsci_toolbox/apis/rapidapi_helpers.py +1 -0
- opsci_toolbox/helpers/common.py +557 -207
- opsci_toolbox/helpers/cv.py +298 -123
- opsci_toolbox/helpers/dataviz.py +875 -191
- opsci_toolbox/helpers/dates.py +55 -8
- opsci_toolbox/helpers/nlp.py +746 -97
- opsci_toolbox/helpers/nlp_cuml.py +166 -57
- opsci_toolbox/helpers/sna.py +101 -10
- opsci_toolbox/helpers/surreaction.py +58 -16
- {opsci_toolbox-0.0.5.dist-info → opsci_toolbox-0.0.6.dist-info}/METADATA +2 -1
- opsci_toolbox-0.0.6.dist-info/RECORD +21 -0
- opsci_toolbox-0.0.5.dist-info/RECORD +0 -21
- {opsci_toolbox-0.0.5.dist-info → opsci_toolbox-0.0.6.dist-info}/WHEEL +0 -0
- {opsci_toolbox-0.0.5.dist-info → opsci_toolbox-0.0.6.dist-info}/top_level.txt +0 -0
opsci_toolbox/helpers/cv.py
CHANGED
@@ -4,7 +4,7 @@ import supervision as sv
|
|
4
4
|
import cv2
|
5
5
|
import numpy as np
|
6
6
|
|
7
|
-
def open_image(image_path):
|
7
|
+
def open_image(image_path: str) -> Image:
|
8
8
|
"""
|
9
9
|
Open and return an image.
|
10
10
|
|
@@ -22,32 +22,42 @@ def open_image(image_path):
|
|
22
22
|
print(f"Error opening image: {e}")
|
23
23
|
return None
|
24
24
|
|
25
|
-
def save_image(image, output_path, name):
|
25
|
+
def save_image(image: Image, output_path: str, name: str) -> str:
|
26
26
|
"""
|
27
27
|
Save an image to the local disk.
|
28
28
|
|
29
29
|
Parameters:
|
30
30
|
- image (Image object): The image to be saved.
|
31
31
|
- output_path (str): The path to save the image.
|
32
|
+
- name (str): The name of the saved image file.
|
32
33
|
|
33
34
|
Returns:
|
34
|
-
-
|
35
|
+
- str: The file path where the image is saved, or an error message if saving fails.
|
35
36
|
"""
|
36
37
|
try:
|
37
38
|
# Save the image to the specified path
|
38
|
-
file_path=os.path.join(output_path, name)
|
39
|
+
file_path = os.path.join(output_path, name)
|
39
40
|
image.save(file_path)
|
40
41
|
return file_path
|
41
42
|
except Exception as e:
|
42
43
|
print(f"Error saving image: {e}")
|
43
|
-
return
|
44
|
+
return str(e)
|
44
45
|
|
45
|
-
def convert_image_format(input_path, output_path, output_filename, output_format="JPEG"):
|
46
|
+
def convert_image_format(input_path: str, output_path: str, output_filename: str, output_format: str = "JPEG") -> str:
|
46
47
|
"""
|
47
|
-
Convert an image to another image format (
|
48
|
+
Convert an image to another image format (e.g., from PNG to JPEG).
|
49
|
+
|
50
|
+
Parameters:
|
51
|
+
- input_path (str): The path to the input image file.
|
52
|
+
- output_path (str): The path to save the converted image.
|
53
|
+
- output_filename (str): The name of the converted image file.
|
54
|
+
- output_format (str): The format to which the image should be converted. Default is "JPEG".
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
- str: The file path where the converted image is saved, or an error message if conversion fails.
|
48
58
|
"""
|
49
59
|
try:
|
50
|
-
file_path=os.path.join(output_path, output_filename+"."+output_format)
|
60
|
+
file_path = os.path.join(output_path, output_filename + "." + output_format)
|
51
61
|
# Open the input image
|
52
62
|
with Image.open(input_path) as img:
|
53
63
|
# Convert and save the image to the desired format
|
@@ -55,67 +65,64 @@ def convert_image_format(input_path, output_path, output_filename, output_format
|
|
55
65
|
print(f"Image converted successfully: {file_path}")
|
56
66
|
except Exception as e:
|
57
67
|
print(f"Error converting image: {e}")
|
68
|
+
return str(e)
|
58
69
|
|
59
70
|
return file_path
|
60
71
|
|
61
|
-
def resize_image(image, new_width, new_height):
|
72
|
+
def resize_image(image: Image, new_width: int, new_height: int) -> Image:
|
62
73
|
"""
|
63
74
|
Resize an image to the specified width and height.
|
64
75
|
|
65
76
|
Parameters:
|
66
|
-
- image : PIL image
|
77
|
+
- image (PIL.Image.Image): The PIL image object to be resized.
|
67
78
|
- new_width (int): The desired width of the resized image.
|
68
79
|
- new_height (int): The desired height of the resized image.
|
69
80
|
|
70
81
|
Returns:
|
71
|
-
- Image
|
82
|
+
- PIL.Image.Image: The resized image.
|
72
83
|
"""
|
73
84
|
try:
|
74
|
-
#
|
75
|
-
|
85
|
+
# Resize the image
|
76
86
|
resized_img = image.resize((new_width, new_height))
|
77
|
-
|
78
87
|
return resized_img
|
79
88
|
except Exception as e:
|
80
89
|
print(f"Error resizing image: {e}")
|
81
90
|
return None
|
82
91
|
|
83
|
-
def crop_image(image, x, y, width, height):
|
92
|
+
def crop_image(image: Image, x: int, y: int, width: int, height: int) -> Image:
|
84
93
|
"""
|
85
94
|
Crop an image based on the specified coordinates and dimensions.
|
86
95
|
|
87
96
|
Parameters:
|
88
|
-
- image : PIL image
|
97
|
+
- image (PIL.Image.Image): The PIL image object to be cropped.
|
89
98
|
- x (int): The x-coordinate of the top-left corner of the cropping region.
|
90
99
|
- y (int): The y-coordinate of the top-left corner of the cropping region.
|
91
100
|
- width (int): The width of the cropping region.
|
92
101
|
- height (int): The height of the cropping region.
|
93
102
|
|
94
103
|
Returns:
|
95
|
-
- Image
|
104
|
+
- PIL.Image.Image: The cropped image.
|
96
105
|
"""
|
97
106
|
try:
|
98
107
|
# Crop the image
|
99
108
|
cropped_img = image.crop((x, y, x + width, y + height))
|
100
|
-
|
101
109
|
return cropped_img
|
102
110
|
except Exception as e:
|
103
111
|
print(f"Error cropping image: {e}")
|
104
112
|
return None
|
105
113
|
|
106
|
-
def flip_image(image, direction='horizontal'):
|
114
|
+
def flip_image(image: Image, direction: str = 'horizontal') -> Image:
|
107
115
|
"""
|
108
116
|
Flip an image horizontally or vertically.
|
109
117
|
|
110
118
|
Parameters:
|
111
|
-
- image : PIL image
|
112
|
-
- direction (str): The direction of the flip ('horizontal' or 'vertical').
|
119
|
+
- image (PIL.Image.Image): The PIL image object to be flipped.
|
120
|
+
- direction (str): The direction of the flip ('horizontal' or 'vertical'). Default is 'horizontal'.
|
113
121
|
|
114
122
|
Returns:
|
115
|
-
- Image
|
123
|
+
- PIL.Image.Image: The flipped image.
|
116
124
|
"""
|
117
125
|
try:
|
118
|
-
|
119
126
|
# Flip the image
|
120
127
|
if direction == 'horizontal':
|
121
128
|
flipped_img = image.transpose(Image.FLIP_LEFT_RIGHT)
|
@@ -130,145 +137,214 @@ def flip_image(image, direction='horizontal'):
|
|
130
137
|
print(f"Error flipping image: {e}")
|
131
138
|
return None
|
132
139
|
|
133
|
-
|
134
|
-
def rotate_image(image, angle):
|
140
|
+
def rotate_image(image: Image, angle: float) -> Image:
|
135
141
|
"""
|
136
142
|
Rotate an image by the given angle (in degrees).
|
137
143
|
|
138
144
|
Parameters:
|
139
|
-
- image : PIL image
|
145
|
+
- image (PIL.Image.Image): The PIL image object to be rotated.
|
140
146
|
- angle (float): The angle by which to rotate the image (in degrees).
|
141
147
|
|
142
148
|
Returns:
|
143
|
-
- Image
|
149
|
+
- PIL.Image.Image: The rotated image.
|
144
150
|
"""
|
145
151
|
try:
|
146
|
-
|
147
152
|
# Rotate the image
|
148
153
|
rotated_img = image.rotate(angle)
|
149
|
-
|
150
154
|
return rotated_img
|
151
155
|
except Exception as e:
|
152
156
|
print(f"Error rotating image: {e}")
|
153
157
|
return None
|
154
158
|
|
155
|
-
def convert_to_grayscale(image):
|
159
|
+
def convert_to_grayscale(image: Image) -> Image:
|
156
160
|
"""
|
157
161
|
Convert a color image to grayscale.
|
158
162
|
|
159
163
|
Parameters:
|
160
|
-
- image : PIL image
|
164
|
+
- image (PIL.Image.Image): The PIL image object to be converted.
|
161
165
|
|
162
166
|
Returns:
|
163
|
-
- Image
|
167
|
+
- PIL.Image.Image: The grayscale image.
|
164
168
|
"""
|
165
169
|
try:
|
166
|
-
|
167
170
|
# Convert the image to grayscale
|
168
171
|
grayscale_img = image.convert("L")
|
169
|
-
|
170
172
|
return grayscale_img
|
171
173
|
except Exception as e:
|
172
174
|
print(f"Error converting image to grayscale: {e}")
|
173
175
|
return None
|
174
|
-
|
175
|
-
def PIL_get_image_size(image):
|
176
|
+
|
177
|
+
def PIL_get_image_size(image: Image) -> tuple:
|
176
178
|
"""
|
177
|
-
Get PILLOW image size
|
179
|
+
Get PILLOW image size.
|
180
|
+
|
181
|
+
Parameters:
|
182
|
+
- image (PIL.Image.Image): The PIL image object.
|
183
|
+
|
184
|
+
Returns:
|
185
|
+
- tuple: A tuple containing the width and height of the image.
|
178
186
|
"""
|
179
187
|
width, height = image.size
|
180
|
-
return
|
188
|
+
return width, height
|
181
189
|
|
182
|
-
def cv_get_image_size(image):
|
190
|
+
def cv_get_image_size(image) -> tuple:
|
183
191
|
"""
|
184
|
-
Get cv2 image size
|
192
|
+
Get cv2 image size.
|
193
|
+
|
194
|
+
Parameters:
|
195
|
+
- image: The cv2 image array.
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
- tuple: A tuple containing the width and height of the image.
|
185
199
|
"""
|
186
200
|
height, width, _ = image.shape
|
187
201
|
return width, height
|
188
202
|
|
189
|
-
def convert_PIL_to_cv(image):
|
203
|
+
def convert_PIL_to_cv(image: Image) -> np.ndarray:
|
190
204
|
"""
|
191
|
-
Convert an image from Pillow to CV2
|
205
|
+
Convert an image from Pillow to CV2.
|
206
|
+
|
207
|
+
Parameters:
|
208
|
+
- image (PIL.Image.Image): The PIL image object.
|
209
|
+
|
210
|
+
Returns:
|
211
|
+
- numpy.ndarray: The converted cv2 image array.
|
192
212
|
"""
|
193
213
|
numpy_array = np.array(image)
|
194
214
|
cv2_image = cv2.cvtColor(numpy_array, cv2.COLOR_RGB2BGR)
|
195
215
|
return cv2_image
|
196
216
|
|
197
|
-
def convert_cv2_to_pil(cv2_image):
|
217
|
+
def convert_cv2_to_pil(cv2_image: np.ndarray) -> Image:
|
198
218
|
"""
|
199
|
-
Convert an image from
|
219
|
+
Convert an image from OpenCV format (BGR) to Pillow format (RGB).
|
220
|
+
|
221
|
+
Args:
|
222
|
+
cv2_image (np.ndarray): The input image in OpenCV format (BGR).
|
223
|
+
|
224
|
+
Returns:
|
225
|
+
Image.Image: The converted image in Pillow format (RGB).
|
200
226
|
"""
|
201
|
-
# Convert the
|
227
|
+
# Convert the OpenCV image from BGR to RGB format
|
202
228
|
rgb_image = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
|
203
229
|
|
204
|
-
# Create a
|
230
|
+
# Create a Pillow Image from the RGB image
|
205
231
|
pil_image = Image.fromarray(rgb_image)
|
206
232
|
|
207
233
|
return pil_image
|
208
234
|
|
209
|
-
def compress_image(image, output_path, name, quality):
|
235
|
+
def compress_image(image: Image, output_path: str, name: str, quality: int) -> str:
|
210
236
|
"""
|
211
237
|
Compress an image with a specified quality level.
|
212
238
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
239
|
+
Args:
|
240
|
+
image (Image.Image): The image object to be compressed.
|
241
|
+
output_path (str): The directory path where the compressed image will be saved.
|
242
|
+
name (str): The name of the compressed image file.
|
243
|
+
quality (int): The quality level for compression (0 to 100, higher is better).
|
218
244
|
|
219
245
|
Returns:
|
220
|
-
|
246
|
+
str: The file path of the compressed image, or an empty string if an error occurred.
|
221
247
|
"""
|
222
248
|
try:
|
223
|
-
#
|
224
|
-
file_path=os.path.join(output_path, name)
|
249
|
+
# Create the file path by joining the output path and file name
|
250
|
+
file_path = os.path.join(output_path, name)
|
251
|
+
|
252
|
+
# Save the image with the specified quality
|
225
253
|
image.save(file_path, quality=quality)
|
226
|
-
|
254
|
+
|
227
255
|
return file_path
|
228
256
|
except Exception as e:
|
229
257
|
print(f"Error compressing image: {e}")
|
230
|
-
return
|
258
|
+
return ""
|
231
259
|
|
232
260
|
|
233
|
-
def cv2_read_image(path):
|
261
|
+
def cv2_read_image(path: str) -> np.ndarray:
|
234
262
|
"""
|
235
|
-
Read an image file
|
263
|
+
Read an image file using OpenCV.
|
264
|
+
|
265
|
+
Args:
|
266
|
+
path (str): The file path to the image.
|
267
|
+
|
268
|
+
Returns:
|
269
|
+
np.ndarray: The image read by OpenCV as a NumPy array.
|
236
270
|
"""
|
271
|
+
# Read the image from the given path
|
237
272
|
image = cv2.imread(path)
|
238
273
|
return image
|
239
274
|
|
240
|
-
def cv2_write_image(image, path, name):
|
275
|
+
def cv2_write_image(image: np.ndarray, path: str, name: str) -> str:
|
241
276
|
"""
|
242
|
-
Write an image file
|
277
|
+
Write an image to a file using OpenCV.
|
278
|
+
|
279
|
+
Args:
|
280
|
+
image (np.ndarray): The image to be saved.
|
281
|
+
path (str): The directory path where the image will be saved.
|
282
|
+
name (str): The name of the image file.
|
283
|
+
|
284
|
+
Returns:
|
285
|
+
str: The file path of the saved image.
|
243
286
|
"""
|
244
|
-
|
287
|
+
# Create the file path by joining the directory path and file name
|
288
|
+
file_path = os.path.join(path, name)
|
289
|
+
|
290
|
+
# Write the image to the specified file path
|
245
291
|
cv2.imwrite(file_path, image)
|
292
|
+
|
246
293
|
return file_path
|
247
294
|
|
248
|
-
def cv2_crop_image(image, xmin, ymin, xmax, ymax):
|
295
|
+
def cv2_crop_image(image: np.ndarray, xmin: int, ymin: int, xmax: int, ymax: int) -> np.ndarray:
|
249
296
|
"""
|
250
|
-
Crop image by coordinates
|
297
|
+
Crop an image by specified coordinates.
|
298
|
+
|
299
|
+
Args:
|
300
|
+
image (np.ndarray): The input image to be cropped.
|
301
|
+
xmin (int): The minimum x-coordinate (left).
|
302
|
+
ymin (int): The minimum y-coordinate (top).
|
303
|
+
xmax (int): The maximum x-coordinate (right).
|
304
|
+
ymax (int): The maximum y-coordinate (bottom).
|
305
|
+
|
306
|
+
Returns:
|
307
|
+
np.ndarray: The cropped image.
|
251
308
|
"""
|
252
|
-
|
309
|
+
# Crop the image using the provided coordinates
|
310
|
+
cropped_img = image[ymin:ymax, xmin:xmax]
|
253
311
|
return cropped_img
|
254
312
|
|
255
|
-
def cv2_flip(image, direction='horizontal'):
|
313
|
+
def cv2_flip(image: np.ndarray, direction: str = 'horizontal') -> np.ndarray:
|
256
314
|
"""
|
257
|
-
Flip an image using
|
315
|
+
Flip an image either horizontally or vertically using OpenCV.
|
316
|
+
|
317
|
+
Args:
|
318
|
+
image (np.ndarray): The input image to be flipped.
|
319
|
+
direction (str): The direction to flip the image, either 'horizontal' or 'vertical'.
|
320
|
+
Default is 'horizontal'.
|
321
|
+
|
322
|
+
Returns:
|
323
|
+
np.ndarray: The flipped image.
|
324
|
+
|
325
|
+
Raises:
|
326
|
+
ValueError: If the direction is neither 'horizontal' nor 'vertical'.
|
258
327
|
"""
|
259
|
-
if direction=='horizontal':
|
328
|
+
if direction == 'horizontal':
|
260
329
|
flipped_image = cv2.flip(image, 1)
|
261
|
-
elif direction=='vertical':
|
330
|
+
elif direction == 'vertical':
|
262
331
|
flipped_image = cv2.flip(image, 0)
|
263
332
|
else:
|
264
|
-
|
333
|
+
raise ValueError("Direction should be 'horizontal' or 'vertical'")
|
334
|
+
|
265
335
|
return flipped_image
|
266
336
|
|
267
|
-
def cv2_rotate_image(image, angle):
|
268
|
-
"""
|
269
|
-
Rotate an image using CV2
|
337
|
+
def cv2_rotate_image(image: np.ndarray, angle: float) -> np.ndarray:
|
270
338
|
"""
|
339
|
+
Rotate an image by a specified angle using OpenCV.
|
340
|
+
|
341
|
+
Args:
|
342
|
+
image (np.ndarray): The input image to be rotated.
|
343
|
+
angle (float): The angle by which to rotate the image (in degrees).
|
271
344
|
|
345
|
+
Returns:
|
346
|
+
np.ndarray: The rotated image.
|
347
|
+
"""
|
272
348
|
# Get the height and width of the image
|
273
349
|
height, width = image.shape[:2]
|
274
350
|
|
@@ -280,28 +356,57 @@ def cv2_rotate_image(image, angle):
|
|
280
356
|
|
281
357
|
return rotated_image
|
282
358
|
|
283
|
-
def cv2_convert_to_grayscale(image):
|
284
|
-
"""
|
285
|
-
Convert an image to grayscale using CV2
|
359
|
+
def cv2_convert_to_grayscale(image: np.ndarray) -> np.ndarray:
|
286
360
|
"""
|
361
|
+
Convert an image to grayscale using OpenCV.
|
287
362
|
|
363
|
+
Args:
|
364
|
+
image (np.ndarray): The input image to be converted.
|
365
|
+
|
366
|
+
Returns:
|
367
|
+
np.ndarray: The grayscale image.
|
368
|
+
"""
|
288
369
|
# Convert the image to grayscale
|
289
370
|
grayscale_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
290
371
|
|
291
372
|
return grayscale_image
|
292
373
|
|
293
|
-
def draw_circle(image, x, y, size=5, color=(255, 0, 0)):
|
374
|
+
def draw_circle(image: np.ndarray, x: int, y: int, size: int = 5, color: tuple = (255, 0, 0)) -> np.ndarray:
|
294
375
|
"""
|
295
|
-
Draw a circle on
|
376
|
+
Draw a circle on an OpenCV image.
|
377
|
+
|
378
|
+
Args:
|
379
|
+
image (np.ndarray): The input image on which to draw the circle.
|
380
|
+
x (int): The x-coordinate of the center of the circle.
|
381
|
+
y (int): The y-coordinate of the center of the circle.
|
382
|
+
size (int, optional): The radius of the circle. Default is 5.
|
383
|
+
color (tuple, optional): The color of the circle in RGB format. Default is red (255, 0, 0).
|
384
|
+
|
385
|
+
Returns:
|
386
|
+
np.ndarray: The image with the circle drawn on it.
|
296
387
|
"""
|
388
|
+
# Convert the image from BGR to RGB color space
|
297
389
|
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
298
|
-
|
390
|
+
|
391
|
+
# Draw the circle on the RGB image
|
392
|
+
image_with_circle = cv2.circle(image_rgb, (x, y), size, color, -1)
|
393
|
+
|
299
394
|
return image_with_circle
|
300
395
|
|
301
396
|
|
302
|
-
def apply_mask(image, mask, color_mask=[255, 255, 255], reverse=True, transparency=1.0):
|
397
|
+
def apply_mask(image: np.ndarray, mask: np.ndarray, color_mask: list = [255, 255, 255], reverse: bool = True, transparency: float = 1.0) -> np.ndarray:
|
303
398
|
"""
|
304
|
-
Apply a transparent color mask on an image
|
399
|
+
Apply a transparent color mask on an image.
|
400
|
+
|
401
|
+
Args:
|
402
|
+
image (np.ndarray): The input image to which the mask will be applied.
|
403
|
+
mask (np.ndarray): The binary mask indicating where to apply the color mask.
|
404
|
+
color_mask (list, optional): The RGB color to use for the mask. Default is white [255, 255, 255].
|
405
|
+
reverse (bool, optional): If True, apply the color mask where the mask is False; otherwise, apply where True. Default is True.
|
406
|
+
transparency (float, optional): The transparency level of the color mask (0.0 to 1.0). Default is 1.0 (opaque).
|
407
|
+
|
408
|
+
Returns:
|
409
|
+
np.ndarray: The image with the color mask applied.
|
305
410
|
"""
|
306
411
|
# Validate transparency value
|
307
412
|
transparency = max(0.0, min(1.0, transparency))
|
@@ -315,53 +420,84 @@ def apply_mask(image, mask, color_mask=[255, 255, 255], reverse=True, transparen
|
|
315
420
|
# Set the alpha channel of the color_mask
|
316
421
|
color_mask_with_alpha = color_mask + [alpha]
|
317
422
|
|
318
|
-
#
|
319
|
-
|
423
|
+
# Ensure the mask is a binary mask with the same dimensions as the image
|
424
|
+
if mask.ndim == 2:
|
425
|
+
mask = mask[:, :, np.newaxis]
|
320
426
|
|
321
427
|
if reverse:
|
322
|
-
#
|
323
|
-
masked_image[
|
428
|
+
# Apply the color mask where the mask is False
|
429
|
+
masked_image[mask == 0] = color_mask_with_alpha
|
324
430
|
else:
|
325
|
-
#
|
326
|
-
masked_image[
|
431
|
+
# Apply the color mask where the mask is True
|
432
|
+
masked_image[mask != 0] = color_mask_with_alpha
|
327
433
|
|
328
434
|
return masked_image
|
329
435
|
|
330
|
-
|
331
|
-
def transform_coordinates_CV_to_YOLO(left, top, width, height):
|
436
|
+
def transform_coordinates_CV_to_YOLO(left: float, top: float, width: float, height: float) -> tuple:
|
332
437
|
"""
|
333
|
-
Transform MS Custom Vision annotation format to YOLO
|
438
|
+
Transform MS Custom Vision annotation format to YOLO format.
|
439
|
+
|
440
|
+
Args:
|
441
|
+
left (float): The x-coordinate of the top-left corner of the bounding box.
|
442
|
+
top (float): The y-coordinate of the top-left corner of the bounding box.
|
443
|
+
width (float): The width of the bounding box.
|
444
|
+
height (float): The height of the bounding box.
|
445
|
+
|
446
|
+
Returns:
|
447
|
+
tuple: A tuple containing the transformed coordinates in YOLO format (center_x, center_y, width, height).
|
334
448
|
"""
|
449
|
+
# Calculate the center coordinates
|
450
|
+
center_x = left + (width / 2)
|
451
|
+
center_y = top + (height / 2)
|
335
452
|
|
336
|
-
center_x = left + (width/2)
|
337
|
-
center_y = top + (height/2)
|
338
453
|
return (center_x, center_y, width, height)
|
339
454
|
|
340
455
|
|
341
|
-
def transform_coordinates_PascalVOC_to_YOLO(xmin, ymin, xmax, ymax, width, height):
|
456
|
+
def transform_coordinates_PascalVOC_to_YOLO(xmin: float, ymin: float, xmax: float, ymax: float, width: float, height: float) -> tuple:
|
342
457
|
"""
|
343
|
-
Transform PascalVOC coordinates to YOLO
|
458
|
+
Transform PascalVOC coordinates to YOLO format.
|
459
|
+
|
460
|
+
Args:
|
461
|
+
xmin (float): The minimum x-coordinate (left boundary) of the bounding box.
|
462
|
+
ymin (float): The minimum y-coordinate (top boundary) of the bounding box.
|
463
|
+
xmax (float): The maximum x-coordinate (right boundary) of the bounding box.
|
464
|
+
ymax (float): The maximum y-coordinate (bottom boundary) of the bounding box.
|
465
|
+
width (float): The width of the image.
|
466
|
+
height (float): The height of the image.
|
467
|
+
|
468
|
+
Returns:
|
469
|
+
tuple: A tuple containing the transformed coordinates in YOLO format (x_center, y_center, box_width, box_height).
|
344
470
|
"""
|
471
|
+
# Calculate the center x-coordinate of the bounding box in YOLO format
|
345
472
|
x_center = ((xmax + xmin) / 2) / width
|
473
|
+
|
474
|
+
# Calculate the center y-coordinate of the bounding box in YOLO format
|
346
475
|
y_center = ((ymax + ymin) / 2) / height
|
476
|
+
|
477
|
+
# Calculate the width of the bounding box in YOLO format
|
347
478
|
box_width = (xmax - xmin) / width
|
479
|
+
|
480
|
+
# Calculate the height of the bounding box in YOLO format
|
348
481
|
box_height = (ymax - ymin) / height
|
482
|
+
|
349
483
|
return (x_center, y_center, box_width, box_height)
|
350
484
|
|
351
485
|
|
352
|
-
def transform_coordinates_YOLO_to_PascalVOC(center_x, center_y, width, height, image_width, image_height):
|
486
|
+
def transform_coordinates_YOLO_to_PascalVOC(center_x: float, center_y: float, width: float, height: float, image_width: int, image_height: int) -> tuple:
|
353
487
|
"""
|
354
488
|
Convert YOLO coordinates to Pascal VOC format.
|
355
489
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
490
|
+
Args:
|
491
|
+
center_x (float): The x-coordinate of the center of the bounding box (YOLO format).
|
492
|
+
center_y (float): The y-coordinate of the center of the bounding box (YOLO format).
|
493
|
+
width (float): The width of the bounding box (YOLO format).
|
494
|
+
height (float): The height of the bounding box (YOLO format).
|
495
|
+
image_width (int): The width of the image.
|
496
|
+
image_height (int): The height of the image.
|
360
497
|
|
361
498
|
Returns:
|
362
|
-
|
499
|
+
tuple: Pascal VOC coordinates (xmin, ymin, xmax, ymax).
|
363
500
|
"""
|
364
|
-
|
365
501
|
# Convert YOLO coordinates to absolute coordinates
|
366
502
|
abs_x = int(center_x * image_width)
|
367
503
|
abs_y = int(center_y * image_height)
|
@@ -377,58 +513,97 @@ def transform_coordinates_YOLO_to_PascalVOC(center_x, center_y, width, height, i
|
|
377
513
|
return xmin, ymin, xmax, ymax
|
378
514
|
|
379
515
|
|
380
|
-
|
381
|
-
def sv_detections_ultralytics(results):
|
516
|
+
def sv_detections_ultralytics(results) -> sv.Detections:
|
382
517
|
"""
|
383
|
-
|
518
|
+
Load detections from Ultralytics results.
|
519
|
+
|
520
|
+
Args:
|
521
|
+
results: The results object from Ultralytics containing detection data.
|
522
|
+
|
523
|
+
Returns:
|
524
|
+
sv.Detections: An object containing the loaded detections.
|
384
525
|
"""
|
385
526
|
detections = sv.Detections.from_ultralytics(results)
|
386
527
|
return detections
|
387
528
|
|
388
|
-
def sv_convert_mask_to_box(masks):
|
529
|
+
def sv_convert_mask_to_box(masks) -> sv.Detections:
|
389
530
|
"""
|
390
|
-
Convert mask coordinates to boxes
|
531
|
+
Convert mask coordinates to bounding boxes.
|
532
|
+
|
533
|
+
Args:
|
534
|
+
masks: The mask data from which to derive bounding boxes.
|
535
|
+
|
536
|
+
Returns:
|
537
|
+
sv.Detections: An object containing the bounding boxes and original masks.
|
391
538
|
"""
|
392
539
|
detections = sv.Detections(
|
393
|
-
|
394
|
-
|
540
|
+
xyxy=sv.mask_to_xyxy(masks=masks),
|
541
|
+
mask=masks
|
395
542
|
)
|
396
543
|
return detections
|
397
544
|
|
398
|
-
|
399
|
-
def sv_annotate_image_bbox(image, detections):
|
545
|
+
def sv_annotate_image_bbox(image: np.ndarray, detections: sv.Detections) -> np.ndarray:
|
400
546
|
"""
|
401
|
-
Draw
|
547
|
+
Draw bounding boxes on an image.
|
548
|
+
|
549
|
+
Args:
|
550
|
+
image (np.ndarray): The input image on which to draw the bounding boxes.
|
551
|
+
detections (sv.Detections): The detections containing bounding box information.
|
552
|
+
|
553
|
+
Returns:
|
554
|
+
np.ndarray: The annotated image with bounding boxes drawn.
|
402
555
|
"""
|
403
556
|
bounding_box_annotator = sv.BoundingBoxAnnotator()
|
404
557
|
annotated_image = bounding_box_annotator.annotate(scene=image, detections=detections)
|
405
558
|
return annotated_image
|
406
559
|
|
407
|
-
|
408
|
-
def sv_annotate_image_mask(image, detections):
|
560
|
+
def sv_annotate_image_mask(image: np.ndarray, detections: sv.Detections) -> np.ndarray:
|
409
561
|
"""
|
410
|
-
Draw
|
562
|
+
Draw mask areas on an image.
|
563
|
+
|
564
|
+
Args:
|
565
|
+
image (np.ndarray): The input image on which to draw the mask areas.
|
566
|
+
detections (sv.Detections): The detections containing mask information.
|
567
|
+
|
568
|
+
Returns:
|
569
|
+
np.ndarray: The annotated image with mask areas drawn.
|
411
570
|
"""
|
412
571
|
mask_annotator = sv.MaskAnnotator()
|
413
572
|
annotated_image = mask_annotator.annotate(scene=image, detections=detections)
|
414
573
|
return annotated_image
|
415
574
|
|
416
|
-
def sv_annotate_image_label(
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
575
|
+
def sv_annotate_image_label(
|
576
|
+
image: np.ndarray,
|
577
|
+
detections: sv.Detections,
|
578
|
+
model,
|
579
|
+
color: sv.Color = sv.Color.ROBOFLOW,
|
580
|
+
text_color: sv.Color = sv.Color.WHITE,
|
581
|
+
text_position: sv.Position = sv.Position.TOP_CENTER
|
582
|
+
) -> np.ndarray:
|
583
|
+
"""
|
584
|
+
Draw label rectangles on detections.
|
585
|
+
|
586
|
+
Args:
|
587
|
+
image (np.ndarray): The input image on which to draw the labels.
|
588
|
+
detections (sv.Detections): The detections containing information about the detected objects.
|
589
|
+
model: The model object containing the class names.
|
590
|
+
color (sv.Color, optional): The color for the label rectangles. Defaults to sv.Color.ROBOFLOW.
|
591
|
+
text_color (sv.Color, optional): The color for the text. Defaults to sv.Color.WHITE.
|
592
|
+
text_position (sv.Position, optional): The position of the text relative to the detection. Defaults to sv.Position.TOP_CENTER.
|
423
593
|
|
594
|
+
Returns:
|
595
|
+
np.ndarray: The annotated image with label rectangles drawn.
|
596
|
+
"""
|
597
|
+
# Instantiate the LabelAnnotator with the specified colors and text position
|
424
598
|
label_annotator = sv.LabelAnnotator(color=color, text_color=text_color, text_position=text_position)
|
425
599
|
|
600
|
+
# Extract the class names for each detected object
|
426
601
|
labels = [
|
427
602
|
model.model.names[class_id]
|
428
|
-
for class_id
|
429
|
-
in detections.class_id
|
603
|
+
for class_id in detections.class_id
|
430
604
|
]
|
431
605
|
|
606
|
+
# Annotate the image with the labels
|
432
607
|
annotated_image = label_annotator.annotate(scene=image, detections=detections, labels=labels)
|
433
608
|
|
434
609
|
return annotated_image
|