Skip to content

Commit

Permalink
Merge pull request #1003 from roboflow/adding-clor-border-to-crop-ann…
Browse files Browse the repository at this point in the history
…otator

adding color border to crop annotator poc
  • Loading branch information
SkalskiP authored Mar 20, 2024
2 parents d01b636 + 8a2abe7 commit 6208013
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 44 deletions.
8 changes: 4 additions & 4 deletions docs/draw/utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ comments: true
:::supervision.draw.utils.draw_image

<div class="md-typeset">
<h2>calculate_dynamic_font_scale</h2>
<h2>calculate_optimal_font_scale</h2>
</div>

:::supervision.draw.utils.calculate_dynamic_text_scale
:::supervision.draw.utils.calculate_optimal_text_scale

<div class="md-typeset">
<h2>calculate_dynamic_line_thickness</h2>
<h2>calculate_optimal_line_thickness</h2>
</div>

:::supervision.draw.utils.calculate_dynamic_line_thickness
:::supervision.draw.utils.calculate_optimal_line_thickness
2 changes: 1 addition & 1 deletion examples/count_people_in_zone/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
gdown
inference
supervision
supervision==0.19.0
tqdm
ultralytics
2 changes: 1 addition & 1 deletion examples/heatmap_and_track/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
supervision[assets]
supervision[assets]==0.19.0
ultralytics
2 changes: 1 addition & 1 deletion examples/speed_estimation/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
supervision==0.18.0rc1
supervision==0.19.0
tqdm==4.66.1
requests
ultralytics==8.0.237
Expand Down
2 changes: 1 addition & 1 deletion examples/tracking/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
inference
supervision
supervision==0.19.0
tqdm
ultralytics
2 changes: 1 addition & 1 deletion examples/traffic_analysis/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
gdown
inference
supervision>=0.19.0rc5
supervision>=0.19.0
tqdm
ultralytics
4 changes: 2 additions & 2 deletions supervision/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@
)
from supervision.draw.color import Color, ColorPalette
from supervision.draw.utils import (
calculate_dynamic_line_thickness,
calculate_dynamic_text_scale,
calculate_optimal_line_thickness,
calculate_optimal_text_scale,
draw_filled_rectangle,
draw_image,
draw_line,
Expand Down
84 changes: 67 additions & 17 deletions supervision/annotators/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1847,24 +1847,40 @@ class CropAnnotator(BaseAnnotator):
A class for drawing scaled up crops of detections on the scene.
"""

def __init__(self, position: Position = Position.TOP_CENTER, scale_factor: int = 2):
def __init__(
self,
position: Position = Position.TOP_CENTER,
scale_factor: int = 2,
border_color: Union[Color, ColorPalette] = ColorPalette.DEFAULT,
border_thickness: int = 2,
border_color_lookup: ColorLookup = ColorLookup.CLASS,
):
"""
Args:
position (Position): The anchor position for placing the cropped and scaled
part of the detection in the scene.
scale_factor (int): The factor by which to scale the cropped image part. A
factor of 2, for example, would double the size of the cropped area,
allowing for a closer view of the detection.
border_color (Union[Color, ColorPalette]): The color or color palette to
use for annotating border around the cropped area.
border_thickness (int): The thickness of the border around the cropped area.
border_color_lookup (ColorLookup): Strategy for mapping colors to
annotations. Options are `INDEX`, `CLASS`, `TRACK`.
"""
self.position: Position = position
self.scale_factor: int = scale_factor
self.border_color: Union[Color, ColorPalette] = border_color
self.border_thickness: int = border_thickness
self.border_color_lookup: ColorLookup = border_color_lookup

@scene_to_annotator_img_type
def annotate(
self,
scene: np.ndarray,
scene: ImageType,
detections: Detections,
) -> np.ndarray:
custom_color_lookup: Optional[np.ndarray] = None,
) -> ImageType:
"""
Annotates the provided scene with scaled and cropped parts of the image based
on the provided detections. Each detection is cropped from the original scene
Expand All @@ -1873,8 +1889,12 @@ def annotate(
Args:
scene (np.ndarray): The image where cropped detection will be placed.
scene (ImageType): The image where cropped detection will be placed.
`ImageType` is a flexible type, accepting either `numpy.ndarray`
or `PIL.Image.Image`.
detections (Detections): Object detections to annotate.
custom_color_lookup (Optional[np.ndarray]): Custom color lookup array.
Allows to override the default color mapping strategy.
Returns:
The annotated image.
Expand All @@ -1901,37 +1921,67 @@ def annotate(
]
anchors = detections.get_anchors_coordinates(anchor=self.position).astype(int)

for resized_crop, anchor in zip(resized_crops, anchors):
for idx, (resized_crop, anchor) in enumerate(zip(resized_crops, anchors)):
crop_wh = resized_crop.shape[1], resized_crop.shape[0]
crop_anchor = self.calculate_crop_coordinates(
(x1, y1), (x2, y2) = self.calculate_crop_coordinates(
anchor=anchor, crop_wh=crop_wh, position=self.position
)
scene = place_image(scene=scene, image=resized_crop, anchor=crop_anchor)
scene = place_image(scene=scene, image=resized_crop, anchor=(x1, y1))
color = resolve_color(
color=self.border_color,
detections=detections,
detection_idx=idx,
color_lookup=self.border_color_lookup
if custom_color_lookup is None
else custom_color_lookup,
)
cv2.rectangle(
img=scene,
pt1=(x1, y1),
pt2=(x2, y2),
color=color.as_bgr(),
thickness=self.border_thickness,
)

return scene

@staticmethod
def calculate_crop_coordinates(
anchor: Tuple[int, int], crop_wh: Tuple[int, int], position: Position
) -> Tuple[int, int]:
) -> Tuple[Tuple[int, int], Tuple[int, int]]:
anchor_x, anchor_y = anchor
width, height = crop_wh

if position == Position.TOP_LEFT:
return anchor_x - width, anchor_y - height
return (anchor_x - width, anchor_y - height), (anchor_x, anchor_y)
elif position == Position.TOP_CENTER:
return anchor_x - width // 2, anchor_y - height
return (
(anchor_x - width // 2, anchor_y - height),
(anchor_x + width // 2, anchor_y),
)
elif position == Position.TOP_RIGHT:
return anchor_x, anchor_y - height
return (anchor_x, anchor_y - height), (anchor_x + width, anchor_y)
elif position == Position.CENTER_LEFT:
return anchor_x - width, anchor_y - height // 2
return (
(anchor_x - width, anchor_y - height // 2),
(anchor_x, anchor_y + height // 2),
)
elif position == Position.CENTER or position == Position.CENTER_OF_MASS:
return anchor_x - width // 2, anchor_y - height // 2
return (
(anchor_x - width // 2, anchor_y - height // 2),
(anchor_x + width // 2, anchor_y + height // 2),
)
elif position == Position.CENTER_RIGHT:
return anchor_x, anchor_y - height // 2
return (
(anchor_x, anchor_y - height // 2),
(anchor_x + width, anchor_y + height // 2),
)
elif position == Position.BOTTOM_LEFT:
return anchor_x - width, anchor_y
return (anchor_x - width, anchor_y), (anchor_x, anchor_y + height)
elif position == Position.BOTTOM_CENTER:
return anchor_x - width // 2, anchor_y
return (
(anchor_x - width // 2, anchor_y),
(anchor_x + width // 2, anchor_y + height),
)
elif position == Position.BOTTOM_RIGHT:
return anchor_x, anchor_y
return (anchor_x, anchor_y), (anchor_x + width, anchor_y + height)
24 changes: 8 additions & 16 deletions supervision/draw/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,39 +238,31 @@ def draw_image(
return scene


def calculate_dynamic_text_scale(resolution_wh: Tuple[int, int]) -> float:
def calculate_optimal_text_scale(resolution_wh: Tuple[int, int]) -> float:
"""
Calculate a dynamic font scale based on the resolution of an image.
Calculate font scale based on the resolution of an image.
Parameters:
resolution_wh (Tuple[int, int]): A tuple representing the width and height
of the image.
of the image.
Returns:
float: The calculated font scale factor.
"""
return min(resolution_wh) * 1e-3


def calculate_dynamic_line_thickness(resolution_wh: Tuple[int, int]) -> int:
def calculate_optimal_line_thickness(resolution_wh: Tuple[int, int]) -> int:
"""
Calculate a dynamic line thickness based on the resolution of an image.
Calculate line thickness based on the resolution of an image.
Parameters:
resolution_wh (Tuple[int, int]): A tuple representing the width and height
of the image.
of the image.
Returns:
int: The calculated line thickness in pixels.
"""
min_dimension = min(resolution_wh)
if min_dimension < 480:
if min(resolution_wh) < 1080:
return 2
if min_dimension < 720:
return 2
if min_dimension < 1080:
return 2
if min_dimension < 2160:
return 4
else:
return 4
return 4

0 comments on commit 6208013

Please sign in to comment.