diff --git a/depthai_sdk/src/depthai_sdk/visualize/configs.py b/depthai_sdk/src/depthai_sdk/visualize/configs.py index 9d1e43a5c..8ee2b43d6 100644 --- a/depthai_sdk/src/depthai_sdk/visualize/configs.py +++ b/depthai_sdk/src/depthai_sdk/visualize/configs.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field from enum import IntEnum -from typing import Tuple +from typing import Tuple, Optional import numpy as np try: @@ -81,8 +81,10 @@ class TextConfig: font_thickness: int = 2 font_position: TextPosition = TextPosition.TOP_LEFT - bg_transparency: float = 0.5 - bg_color: Tuple[int, int, int] = (0, 0, 0) + background_color: Optional[Tuple[int, int, int]] = None + background_transparency: float = 0.5 + + outline_color: Tuple[int, int, int] = (0, 0, 0) line_type: int = 16 # cv2.LINE_AA diff --git a/depthai_sdk/src/depthai_sdk/visualize/objects.py b/depthai_sdk/src/depthai_sdk/visualize/objects.py index ba7edf607..8fe4991ee 100644 --- a/depthai_sdk/src/depthai_sdk/visualize/objects.py +++ b/depthai_sdk/src/depthai_sdk/visualize/objects.py @@ -296,6 +296,9 @@ def __init__(self, detections: List[Union[ImgDetection, dai.Tracklet]], normalizer: BoundingBox, label_map: List[Tuple[str, Tuple]] = None, + label_color: Tuple[int, int, int] = None, + label_background_color: Tuple[int, int, int] = None, + label_background_transparency: float = None, spatial_points: List[dai.Point3f] = None, is_spatial=False, parent_bbox: Union[np.ndarray, Tuple[int, int, int, int]] = None): @@ -312,6 +315,9 @@ def __init__(self, self.detections = detections self.normalizer = normalizer self.label_map = label_map + self.label_color = label_color + self.label_background_color = label_background_color + self.label_background_transparency = label_background_transparency self.spatial_points = spatial_points self.is_spatial = is_spatial self.parent_bbox = parent_bbox @@ -331,7 +337,10 @@ def serialize(self) -> dict: 'detections': [{ 'bbox': bbox.to_tuple(frame_shape=self.frame_shape) if isinstance(bbox, BoundingBox) else bbox, 'label': label, - 'color': color + 'color': color, + 'label_color': self.label_color, + 'label_background_color': self.label_background_color, + 'label_background_transparency': self.label_background_transparency } for bbox, label, color in list(self.get_detections())] } if len(self._children) > 0: @@ -385,12 +394,17 @@ def prepare(self) -> 'VisDetections': # Add spatial coordinates self.add_child(VisText(f'{spatial_coords.x}\n{spatial_coords.y}\n{spatial_coords.z}', + color=self.label_color or color, bbox=normalized_bbox, - position=TextPosition.BOTTOM_RIGHT)) + position=TextPosition.BOTTOM_RIGHT, + background_color=self.label_background_color, + background_transparency=self.label_background_transparency)) if cv2 and not detection_config.hide_label and len(label) > 0: # Place label in the bounding box - self.add_child(VisText(text=label.capitalize(), bbox=normalized_bbox, + self.add_child(VisText(text=label.capitalize(), + color=self.label_color or color, + bbox=normalized_bbox, position=detection_config.label_position, padding=detection_config.label_padding)) @@ -438,6 +452,8 @@ def __init__(self, color: Tuple[int, int, int] = None, thickness: int = None, outline: bool = True, + background_color: Tuple[int, int, int] = None, + background_transparency: float = 0.5, bbox: Union[np.ndarray, Tuple[int, int, int, int], BoundingBox] = None, position: TextPosition = TextPosition.TOP_LEFT, padding: int = 10): @@ -456,6 +472,8 @@ def __init__(self, color: Text color. thickness: Font thickness. outline: Enable outline if set to True, disable otherwise. + background_color: Background color. + background_transparency: Background transparency. bbox: Bounding box where to place text. position: Position w.r.t. to frame (or bbox if is set). padding: Padding. @@ -467,6 +485,8 @@ def __init__(self, self.color = color self.thickness = thickness self.outline = outline + self.background_color = background_color + self.background_transparency = background_transparency self.bbox = bbox self.position = position self.padding = padding @@ -479,6 +499,8 @@ def serialize(self): 'color': self.color, 'thickness': self.thickness, 'outline': self.outline, + 'background_color': self.background_color, + 'background_transparency': self.background_transparency } def prepare(self) -> 'VisText': @@ -505,7 +527,6 @@ def draw(self, frame: np.ndarray) -> None: # Extract shape of the bbox if exists if self.bbox is not None: - # shape = self.bbox[2] - self.bbox[0], self.bbox[3] - self.bbox[1] tl, br = self.bbox.denormalize(frame.shape) shape = br[0] - tl[0], br[1] - tl[1] else: @@ -519,11 +540,28 @@ def draw(self, frame: np.ndarray) -> None: font_thickness = max(1, int(font_scale * 2)) \ if text_config.auto_scale else self.thickness or text_config.font_thickness - dy = cv2.getTextSize(self.text, text_config.font_face, font_scale, font_thickness)[0][1] + 10 + dx, dy = cv2.getTextSize(self.text, text_config.font_face, font_scale, font_thickness)[0] + dy += 10 for line in self.text.splitlines(): y = self.coords[1] + background_color = self.background_color or text_config.background_color + background_transparency = self.background_transparency or text_config.background_transparency + if background_color is not None: + img_with_background = cv2.rectangle(img=frame.copy(), + pt1=(self.coords[0], y - dy), + pt2=(self.coords[0] + dx, y + 10), + color=background_color, + thickness=-1) + # take transparency into account + cv2.addWeighted(src1=img_with_background, + alpha=background_transparency, + src2=frame, + beta=1 - background_transparency, + gamma=0, + dst=frame) + if self.outline: # Background cv2.putText(img=frame, @@ -531,7 +569,7 @@ def draw(self, frame: np.ndarray) -> None: org=self.coords, fontFace=text_config.font_face, fontScale=font_scale, - color=text_config.bg_color, + color=text_config.outline_color, thickness=font_thickness + 1, lineType=text_config.line_type) diff --git a/depthai_sdk/src/depthai_sdk/visualize/visualizer.py b/depthai_sdk/src/depthai_sdk/visualize/visualizer.py index b4c257f37..67d214f69 100644 --- a/depthai_sdk/src/depthai_sdk/visualize/visualizer.py +++ b/depthai_sdk/src/depthai_sdk/visualize/visualizer.py @@ -71,6 +71,7 @@ def add_bbox(self, Args: bbox: Bounding box. label: Label for the detection. + thickness: Bounding box thickness. color: Bounding box color (RGB). bbox_style: Bounding box style (one of depthai_sdk.visualize.configs.BboxStyle). @@ -90,6 +91,9 @@ def add_detections(self, normalizer: BoundingBox = None, label_map: List[Tuple[str, Tuple]] = None, spatial_points: List[dai.Point3f] = None, + label_color: Tuple[int, int, int] = None, + label_background_color: Tuple[int, int, int] = None, + label_background_transparency: float = None, is_spatial=False, bbox: Union[np.ndarray, Tuple[int, int, int, int]] = None, ) -> 'Visualizer': @@ -101,8 +105,12 @@ def add_detections(self, normalizer: Normalizer object. label_map: List of tuples (label, color). spatial_points: List of spatial points. None if not spatial. + label_color: Color for the label. + label_background_color: Color for the label background. + label_background_transparency: Transparency for the label background. is_spatial: Flag that indicates if the detections are spatial. bbox: Bounding box, if there's a detection inside a bounding box. + Returns: self """ @@ -110,6 +118,9 @@ def add_detections(self, normalizer=normalizer, label_map=label_map, spatial_points=spatial_points, + label_color=label_color, + label_background_color=label_background_color, + label_background_transparency=label_background_transparency, is_spatial=is_spatial, parent_bbox=bbox) self.add_object(detection_overlay) @@ -122,6 +133,8 @@ def add_text(self, color: Tuple[int, int, int] = None, thickness: int = None, outline: bool = True, + background_color: Tuple[int, int, int] = None, + background_transparency: float = 0.5, bbox: Union[np.ndarray, Tuple[int, ...], BoundingBox] = None, position: TextPosition = TextPosition.TOP_LEFT, padding: int = 10) -> 'Visualizer': @@ -135,6 +148,8 @@ def add_text(self, color: Color of the text. thickness: Thickness of the text. outline: Flag that indicates if the text should be outlined. + background_color: Background color. + background_transparency: Background transparency. bbox: Bounding box. position: Position. padding: Padding. @@ -148,6 +163,8 @@ def add_text(self, color=color, thickness=thickness, outline=outline, + background_color=background_color, + background_transparency=background_transparency, bbox=bbox, position=position, padding=padding) @@ -368,8 +385,9 @@ def text(self, font_scale: float = None, font_thickness: int = None, font_position: TextPosition = None, - bg_transparency: float = None, - bg_color: Tuple[int, int, int] = None, + background_transparency: float = None, + background_color: Tuple[int, int, int] = None, + outline_color: Tuple[int, int, int] = None, line_type: int = None, auto_scale: bool = None) -> 'Visualizer': """ @@ -382,8 +400,9 @@ def text(self, font_scale: Font scale. font_thickness: Font thickness. font_position: Font position. - bg_transparency: Text background transparency. - bg_color: Text background color. + background_transparency: Text background transparency. + background_color: Text background color. + outline_color: Outline color. line_type: Line type (from cv2). auto_scale: Flag that indicates if the font scale should be automatically adjusted.