Skip to content

Commit 43041c2

Browse files
authored
Merge pull request #1385 from roboflow/add-backgroundcolor-annotator
Add BackgroundColorAnnotator
2 parents ca2902c + b9cc02e commit 43041c2

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

docs/detection/annotators.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,27 @@ status: new
433433

434434
</div>
435435

436+
=== "Background Color"
437+
438+
```python
439+
import supervision as sv
440+
441+
image = ...
442+
detections = sv.Detections(...)
443+
444+
background_overlay_annotator = sv.BackgroundOverlayAnnotator()
445+
annotated_frame = background_overlay_annotator.annotate(
446+
scene=image.copy(),
447+
detections=detections
448+
)
449+
```
450+
451+
<div class="result" markdown>
452+
453+
![background-overlay-annotator-example](https://media.roboflow.com/supervision-annotator-examples/background-color-annotator-example-purple.png)
454+
455+
</div>
456+
436457
<div class="md-typeset">
437458
<h2><a href="#supervision.annotators.core.BoxAnnotator">BoxAnnotator</a></h2>
438459
</div>
@@ -553,6 +574,12 @@ status: new
553574

554575
:::supervision.annotators.core.CropAnnotator
555576

577+
<div class="md-typeset">
578+
<h2><a href="#supervision.annotators.core.BackgroundOverlayAnnotator">BackgroundOverlayAnnotator</a></h2>
579+
</div>
580+
581+
:::supervision.annotators.core.BackgroundOverlayAnnotator
582+
556583
<div class="md-typeset">
557584
<h2><a href="#supervision.annotators.core.ColorLookup">ColorLookup</a></h2>
558585
</div>

supervision/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
__version__ = "development"
88

99
from supervision.annotators.core import (
10+
BackgroundOverlayAnnotator,
1011
BlurAnnotator,
1112
BoundingBoxAnnotator,
1213
BoxAnnotator,

supervision/annotators/core.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,3 +2283,84 @@ def calculate_crop_coordinates(
22832283
)
22842284
elif position == Position.BOTTOM_RIGHT:
22852285
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+
![background-overlay-annotator-example](https://media.roboflow.com/
2350+
supervision-annotator-examples/background-color-annotator-example-purple.png)
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

Comments
 (0)