1
1
import cv2
2
+ import logging
2
3
3
4
font = cv2 .FONT_HERSHEY_SIMPLEX
4
5
5
6
6
- def draw_rectangle (img ,
7
- bbox ,
8
- bbox_color = (255 , 255 , 255 ),
9
- thickness = 3 ,
10
- is_opaque = False ,
11
- alpha = 0.5 ):
7
+ def check_and_modify_bbox (bbox , img_size , margin = 0 ):
8
+ """
9
+ Checks if the bounding box is inside the given image.
10
+ If not, the coordinates are trimmed inorder to fit inside the image.
11
+
12
+ Trimming criteria:
13
+ - for xmin and ymin:
14
+ - xmin and ymin are trimmed to 0, if their value is negative i.e. out of the
15
+ scope of image.
16
+ - for xmax and ymax:
17
+ - xmax and ymax are trimmed to image_width and image_height respectivel
18
+
19
+
20
+ Parameters
21
+ ----------
22
+ bbox : list
23
+ a list containing x_min, y_min, x_max and y_max of the rectangle positions
24
+ img_size: tuple
25
+ a tuple containing image width, image height and color channel.
26
+ margin: integer (default = 0)
27
+ space between edge of the image and bounding box incase the box is trimmed such that
28
+ it's size is exactly as the image.
29
+
30
+ Returns
31
+ -------
32
+ list
33
+ bounding box coordinates (xmin, ymin, xmax, ymax)
34
+ """
35
+ bbox = [value if value > 0 else margin for value in bbox ]
36
+ bbox [2 ] = bbox [2 ] if bbox [2 ] < img_size [1 ] else img_size [1 ] - margin
37
+ bbox [3 ] = bbox [3 ] if bbox [3 ] < img_size [0 ] else img_size [0 ] - margin
38
+ return bbox
39
+
40
+
41
+ def draw_rectangle (
42
+ img , bbox , bbox_color = (255 , 255 , 255 ), thickness = 3 , is_opaque = False , alpha = 0.5
43
+ ):
12
44
"""Draws the rectangle around the object
13
45
14
46
Parameters
@@ -31,30 +63,37 @@ def draw_rectangle(img,
31
63
ndarray
32
64
the image with the bounding box drawn
33
65
"""
66
+ bbox = check_and_modify_bbox (bbox , img .shape )
67
+
34
68
output = img .copy ()
35
69
if not is_opaque :
36
- cv2 .rectangle (output , (bbox [0 ], bbox [1 ]), (bbox [2 ], bbox [3 ]),
37
- bbox_color , thickness )
70
+ cv2 .rectangle (
71
+ output , (bbox [0 ], bbox [1 ]), (bbox [2 ], bbox [3 ]), bbox_color , thickness
72
+ )
38
73
else :
39
74
overlay = img .copy ()
40
75
41
- cv2 .rectangle (overlay , (bbox [0 ], bbox [1 ]), (bbox [2 ], bbox [3 ]),
42
- bbox_color , - 1 )
76
+ cv2 .rectangle (overlay , (bbox [0 ], bbox [1 ]), (bbox [2 ], bbox [3 ]), bbox_color , - 1 )
43
77
cv2 .addWeighted (overlay , alpha , output , 1 - alpha , 0 , output )
44
78
45
79
return output
46
80
47
81
48
- def add_label (img ,
49
- label ,
50
- bbox ,
51
- size = 1 ,
52
- thickness = 2 ,
53
- draw_bg = True ,
54
- text_bg_color = (255 , 255 , 255 ),
55
- text_color = (0 , 0 , 0 ),
56
- top = True ):
57
- """adds label, inside or outside the rectangle
82
+ def add_label (
83
+ img ,
84
+ label ,
85
+ bbox ,
86
+ size = 1 ,
87
+ thickness = 2 ,
88
+ draw_bg = True ,
89
+ text_bg_color = (255 , 255 , 255 ),
90
+ text_color = (0 , 0 , 0 ),
91
+ top = True ,
92
+ ):
93
+ """
94
+ adds label, inside or outside the rectangle.
95
+ if label cannot be drawn on outside of the box, it puts label inside the box.
96
+
58
97
59
98
Parameters
60
99
----------
@@ -83,24 +122,25 @@ def add_label(img,
83
122
the image with the label written
84
123
"""
85
124
86
- (label_width , label_height ), baseline = cv2 .getTextSize (label , font , size , thickness )
87
125
88
- if top :
89
- label_bg = [bbox [0 ], bbox [1 ], bbox [0 ] + label_width , bbox [1 ] - label_height - (15 * size )]
126
+ (text_width , text_height ), baseline = cv2 .getTextSize (label , font , size , thickness )
127
+
128
+ if top and bbox [1 ] - text_height > text_height :
129
+ label_bg = [bbox [0 ], bbox [1 ], bbox [0 ] + text_width , bbox [1 ] - text_height - (15 * size )]
90
130
if draw_bg :
91
131
cv2 .rectangle (img , (label_bg [0 ], label_bg [1 ]),
92
132
(label_bg [2 ] + 5 , label_bg [3 ]), text_bg_color , - 1 )
93
-
133
+
94
134
cv2 .putText (img , label , (bbox [0 ] + 5 , bbox [1 ] - (15 * size )), font , size , text_color , thickness )
95
135
else :
96
136
label_bg = [bbox [0 ], bbox [1 ], bbox [0 ] + label_width , bbox [1 ] + label_height + (15 * size )]
97
137
if draw_bg :
138
+
98
139
cv2 .rectangle (img , (label_bg [0 ], label_bg [1 ]),
99
140
(label_bg [2 ] + 5 , label_bg [3 ]), text_bg_color , - 1 )
100
141
cv2 .putText (img , label , (bbox [0 ] + 5 , bbox [1 ] + (16 * size ) + (4 * thickness )), font , size , text_color , thickness )
101
142
return img
102
143
103
-
104
144
def add_T_label (img ,
105
145
label ,
106
146
bbox ,
@@ -109,6 +149,7 @@ def add_T_label(img,
109
149
draw_bg = True ,
110
150
text_bg_color = (255 , 255 , 255 ),
111
151
text_color = (0 , 0 , 0 )):
152
+
112
153
"""adds a T label to the rectangle, originating from the top of the rectangle
113
154
114
155
Parameters
@@ -139,19 +180,28 @@ def add_T_label(img,
139
180
(label_width , label_height ), baseline = cv2 .getTextSize (label , font , size , thickness )
140
181
# draw vertical line
141
182
x_center = (bbox [0 ] + bbox [2 ]) // 2
142
- y_top = bbox [1 ] - 50
143
- cv2 .line (img , (x_center , bbox [1 ]), (x_center , y_top ), text_bg_color , 3 )
183
+ line_top = y_top = bbox [1 ] - 50
144
184
145
185
# draw rectangle with label
146
186
y_bottom = y_top
147
- y_top = y_bottom - label_height - 5
148
- x_left = x_center - (label_width // 2 ) - 5
149
- x_right = x_center + (label_width // 2 ) + 5
187
+ y_top = y_bottom - text_height - 5
188
+
189
+ if y_top < 0 :
190
+ logging .warning (
191
+ "Labelling style 'T' going out of frame. Falling back to normal labeling."
192
+ )
193
+ return add_label (img , label , bbox )
194
+
195
+ cv2 .line (img , (x_center , bbox [1 ]), (x_center , line_top ), text_bg_color , 3 )
196
+ x_left = x_center - (text_width // 2 ) - 5
197
+ x_right = x_center + (text_width // 2 ) + 5
150
198
if draw_bg :
151
199
cv2 .rectangle (img , (x_left , y_top - 30 ), (x_right , y_bottom ),
152
200
text_bg_color , - 1 )
153
201
cv2 .putText (img , label , (x_left + 5 , y_bottom - (8 * size )),
154
202
font , size , text_color , thickness )
203
+ )
204
+
155
205
156
206
return img
157
207
@@ -166,6 +216,7 @@ def draw_flag_with_label(img,
166
216
text_bg_color = (255 , 255 , 255 ),
167
217
text_color = (0 , 0 , 0 ),
168
218
):
219
+
169
220
"""draws a pole from the middle of the object that is to be labeled and adds the label to the flag
170
221
171
222
Parameters
@@ -199,8 +250,14 @@ def draw_flag_with_label(img,
199
250
(label_width , label_height ), baseline = cv2 .getTextSize (label , font , size , thickness )
200
251
201
252
x_center = (bbox [0 ] + bbox [2 ]) // 2
202
- y_bottom = int ((bbox [1 ] * .75 + bbox [3 ] * .25 ))
253
+ y_bottom = int ((bbox [1 ] * 0 .75 + bbox [3 ] * 0 .25 ))
203
254
y_top = bbox [1 ] - (y_bottom - bbox [1 ])
255
+ if y_top < 0 :
256
+ logging .warning (
257
+ "Labelling style 'Flag' going out of frame. Falling back to normal labeling."
258
+ )
259
+ img = draw_rectangle (img , bbox , bbox_color = line_color )
260
+ return add_label (img , label , bbox )
204
261
205
262
start_point = (x_center , y_top )
206
263
end_point = (x_center , y_bottom )
@@ -210,14 +267,28 @@ def draw_flag_with_label(img,
210
267
# write label
211
268
212
269
if write_label :
270
+
271
+ text_width = cv2 .getTextSize (label , cv2 .FONT_HERSHEY_SIMPLEX , 1 , 2 )[0 ][0 ]
213
272
label_bg = [
214
- start_point [0 ], start_point [1 ], start_point [0 ] + label_width ,
215
- start_point [1 ] - label_height - (10 * size )
273
+ start_point [0 ],
274
+ start_point [1 ],
275
+ start_point [0 ] + text_width ,
276
+ start_point [1 ] + 30 ,
216
277
]
217
- cv2 .rectangle (img , (label_bg [0 ], label_bg [1 ]),
218
- (label_bg [2 ] + 5 , label_bg [3 ]), text_bg_color , - 1 )
219
- cv2 .putText (img , label , (start_point [0 ] + 7 , start_point [1 ] - (13 * size ) + 20 ),
220
- font , size , text_color , thickness )
278
+ cv2 .rectangle (
279
+ img ,
280
+ (label_bg [0 ], label_bg [1 ]),
281
+ (label_bg [2 ] + 5 , label_bg [3 ]),
282
+ text_bg_color ,
283
+ - 1 ,
284
+ )
285
+ cv2 .putText (
286
+ img ,
287
+ label ,
288
+ (start_point [0 ] + 5 , start_point [1 ] - 5 + 30 ),
289
+ font , size , text_color , thickness
290
+ )
291
+
221
292
return img
222
293
223
294
@@ -226,12 +297,9 @@ def draw_flag_with_label(img,
226
297
# INSTEAD OF THE FUNCTIONS BELOW
227
298
228
299
229
- def draw_multiple_rectangles (img ,
230
- bboxes ,
231
- bbox_color = (255 , 255 , 255 ),
232
- thickness = 3 ,
233
- is_opaque = False ,
234
- alpha = 0.5 ):
300
+ def draw_multiple_rectangles (
301
+ img , bboxes , bbox_color = (255 , 255 , 255 ), thickness = 3 , is_opaque = False , alpha = 0.5
302
+ ):
235
303
"""draws multiple rectangles
236
304
237
305
img : ndarray
@@ -252,10 +320,8 @@ def draw_multiple_rectangles(img,
252
320
ndarray
253
321
the image with the bounding boxes drawn
254
322
"""
255
-
256
323
for bbox in bboxes :
257
- img = draw_rectangle (img , bbox , bbox_color , thickness , is_opaque ,
258
- alpha )
324
+ img = draw_rectangle (img , bbox , bbox_color , thickness , is_opaque , alpha )
259
325
return img
260
326
261
327
@@ -268,6 +334,7 @@ def add_multiple_labels(img,
268
334
text_bg_color = (255 , 255 , 255 ),
269
335
text_color = (0 , 0 , 0 ),
270
336
top = True ):
337
+
271
338
"""add labels, inside or outside the rectangles
272
339
273
340
Parameters
@@ -295,16 +362,17 @@ def add_multiple_labels(img,
295
362
for label , bbox in zip (labels , bboxes ):
296
363
img = add_label (img , label , bbox , size , thickness , draw_bg , text_bg_color , text_color ,
297
364
top )
298
-
299
365
return img
300
366
301
367
302
- def add_multiple_T_labels (img ,
303
- labels ,
304
- bboxes ,
305
- draw_bg = True ,
306
- text_bg_color = (255 , 255 , 255 ),
307
- text_color = (0 , 0 , 0 )):
368
+ def add_multiple_T_labels (
369
+ img ,
370
+ labels ,
371
+ bboxes ,
372
+ draw_bg = True ,
373
+ text_bg_color = (255 , 255 , 255 ),
374
+ text_color = (0 , 0 , 0 ),
375
+ ):
308
376
"""adds T labels to the rectangles, each originating from the top of the rectangle
309
377
310
378
Parameters
@@ -336,13 +404,15 @@ def add_multiple_T_labels(img,
336
404
return img
337
405
338
406
339
- def draw_multiple_flags_with_labels (img ,
340
- labels ,
341
- bboxes ,
342
- write_label = True ,
343
- line_color = (255 , 255 , 255 ),
344
- text_bg_color = (255 , 255 , 255 ),
345
- text_color = (0 , 0 , 0 )):
407
+ def draw_multiple_flags_with_labels (
408
+ img ,
409
+ labels ,
410
+ bboxes ,
411
+ write_label = True ,
412
+ line_color = (255 , 255 , 255 ),
413
+ text_bg_color = (255 , 255 , 255 ),
414
+ text_color = (0 , 0 , 0 ),
415
+ ):
346
416
"""draws poles from the middle of the objects that are to be labeled and adds the labels to the flags
347
417
348
418
Parameters
@@ -369,6 +439,7 @@ def draw_multiple_flags_with_labels(img,
369
439
"""
370
440
371
441
for label , bbox in zip (labels , bboxes ):
442
+
372
443
img = draw_flag_with_label (img , label , bbox , size = 1 , thickness = 2 ,
373
444
write_label = write_label , line_color = line_color ,
374
445
text_bg_color = text_bg_color ,
0 commit comments