@@ -2283,3 +2283,84 @@ def calculate_crop_coordinates(
2283
2283
)
2284
2284
elif position == Position .BOTTOM_RIGHT :
2285
2285
return (anchor_x , anchor_y ), (anchor_x + width , anchor_y + height )
2286
+
2287
+
2288
+ class BackgroundOverlayAnnotator (BaseAnnotator ):
2289
+ """
2290
+ A class for drawing a colored overlay on the background of an image outside
2291
+ the region of detections.
2292
+
2293
+ If masks are provided, the background is colored outside the masks.
2294
+ If masks are not provided, the background is colored outside the bounding boxes.
2295
+
2296
+ You can use the `force_box` parameter to force the annotator to use bounding boxes.
2297
+
2298
+ !!! warning
2299
+
2300
+ This annotator uses `sv.Detections.mask`.
2301
+ """
2302
+
2303
+ def __init__ (
2304
+ self ,
2305
+ color : Color = Color .BLACK ,
2306
+ opacity : float = 0.5 ,
2307
+ force_box : bool = False ,
2308
+ ):
2309
+ """
2310
+ Args:
2311
+ color (Color): The color to use for annotating detections.
2312
+ opacity (float): Opacity of the overlay mask. Must be between `0` and `1`.
2313
+ force_box (bool): If `True`, forces the annotator to use bounding boxes when
2314
+ masks are provided in the supplied sv.Detections.
2315
+ """
2316
+ self .color : Color = color
2317
+ self .opacity = opacity
2318
+ self .force_box = force_box
2319
+
2320
+ @ensure_cv2_image_for_annotation
2321
+ def annotate (self , scene : ImageType , detections : Detections ) -> ImageType :
2322
+ """
2323
+ Applies a colored overlay to the scene outside of the detected regions.
2324
+
2325
+ Args:
2326
+ scene (ImageType): The image where masks will be drawn.
2327
+ `ImageType` is a flexible type, accepting either `numpy.ndarray`
2328
+ or `PIL.Image.Image`.
2329
+ detections (Detections): Object detections to annotate.
2330
+
2331
+ Returns:
2332
+ The annotated image, matching the type of `scene` (`numpy.ndarray`
2333
+ or `PIL.Image.Image`)
2334
+
2335
+ Example:
2336
+ ```python
2337
+ import supervision as sv
2338
+
2339
+ image = ...
2340
+ detections = sv.Detections(...)
2341
+
2342
+ background_overlay_annotator = sv.BackgroundOverlayAnnotator()
2343
+ annotated_frame = background_overlay_annotator.annotate(
2344
+ scene=image.copy(),
2345
+ detections=detections
2346
+ )
2347
+ ```
2348
+
2349
+ 
2351
+ """
2352
+ colored_mask = np .full_like (scene , self .color .as_bgr (), dtype = np .uint8 )
2353
+
2354
+ cv2 .addWeighted (
2355
+ scene , 1 - self .opacity , colored_mask , self .opacity , 0 , dst = colored_mask
2356
+ )
2357
+
2358
+ if detections .mask is None or self .force_box :
2359
+ for x1 , y1 , x2 , y2 in detections .xyxy .astype (int ):
2360
+ colored_mask [y1 :y2 , x1 :x2 ] = scene [y1 :y2 , x1 :x2 ]
2361
+ else :
2362
+ for mask in detections .mask :
2363
+ colored_mask [mask ] = scene [mask ]
2364
+
2365
+ np .copyto (scene , colored_mask )
2366
+ return scene
0 commit comments