|
from typing import Dict, List, Tuple, Union |
|
|
|
import cv2 |
|
import numpy as np |
|
|
|
from inference.core.entities.requests.inference import ( |
|
InstanceSegmentationInferenceRequest, |
|
KeypointsDetectionInferenceRequest, |
|
ObjectDetectionInferenceRequest, |
|
) |
|
from inference.core.entities.responses.inference import ( |
|
InstanceSegmentationPrediction, |
|
Keypoint, |
|
KeypointsPrediction, |
|
ObjectDetectionInferenceResponse, |
|
ObjectDetectionPrediction, |
|
Point, |
|
) |
|
from inference.core.utils.image_utils import load_image_rgb, np_image_to_base64 |
|
|
|
|
|
def draw_detection_predictions( |
|
inference_request: Union[ |
|
ObjectDetectionInferenceRequest, |
|
InstanceSegmentationInferenceRequest, |
|
KeypointsDetectionInferenceRequest, |
|
], |
|
inference_response: Union[ |
|
ObjectDetectionInferenceResponse, |
|
InstanceSegmentationPrediction, |
|
KeypointsPrediction, |
|
], |
|
colors: Dict[str, str], |
|
) -> bytes: |
|
image = load_image_rgb(inference_request.image) |
|
for box in inference_response.predictions: |
|
color = tuple( |
|
int(colors.get(box.class_name, "#4892EA")[i : i + 2], 16) for i in (1, 3, 5) |
|
) |
|
image = draw_bbox( |
|
image=image, |
|
box=box, |
|
color=color, |
|
thickness=inference_request.visualization_stroke_width, |
|
) |
|
if hasattr(box, "points"): |
|
image = draw_instance_segmentation_points( |
|
image=image, |
|
points=box.points, |
|
color=color, |
|
thickness=inference_request.visualization_stroke_width, |
|
) |
|
if hasattr(box, "keypoints"): |
|
draw_keypoints( |
|
image=image, |
|
keypoints=box.keypoints, |
|
color=color, |
|
thickness=inference_request.visualization_stroke_width, |
|
) |
|
if inference_request.visualization_labels: |
|
image = draw_labels( |
|
image=image, |
|
box=box, |
|
color=color, |
|
) |
|
return np_image_to_base64(image=image) |
|
|
|
|
|
def draw_bbox( |
|
image: np.ndarray, |
|
box: ObjectDetectionPrediction, |
|
color: Tuple[int, ...], |
|
thickness: int, |
|
) -> np.ndarray: |
|
left_top, right_bottom = bbox_to_points(box=box) |
|
return cv2.rectangle( |
|
image, |
|
left_top, |
|
right_bottom, |
|
color=color, |
|
thickness=thickness, |
|
) |
|
|
|
|
|
def draw_instance_segmentation_points( |
|
image: np.ndarray, |
|
points: List[Point], |
|
color: Tuple[int, ...], |
|
thickness: int, |
|
) -> np.ndarray: |
|
points_array = np.array([(int(p.x), int(p.y)) for p in points], np.int32) |
|
if len(points) > 2: |
|
image = cv2.polylines( |
|
image, |
|
[points_array], |
|
isClosed=True, |
|
color=color, |
|
thickness=thickness, |
|
) |
|
return image |
|
|
|
|
|
def draw_keypoints( |
|
image: np.ndarray, |
|
keypoints: List[Keypoint], |
|
color: Tuple[int, ...], |
|
thickness: int, |
|
) -> None: |
|
for keypoint in keypoints: |
|
center_coordinates = (round(keypoint.x), round(keypoint.y)) |
|
image = cv2.circle( |
|
image, |
|
center_coordinates, |
|
thickness, |
|
color, |
|
-1, |
|
) |
|
|
|
|
|
def draw_labels( |
|
image: np.ndarray, |
|
box: Union[ObjectDetectionPrediction, InstanceSegmentationPrediction], |
|
color: Tuple[int, ...], |
|
) -> np.ndarray: |
|
(x1, y1), _ = bbox_to_points(box=box) |
|
text = f"{box.class_name} {box.confidence:.2f}" |
|
(text_width, text_height), _ = cv2.getTextSize( |
|
text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1 |
|
) |
|
button_size = (text_width + 20, text_height + 20) |
|
button_img = np.full( |
|
(button_size[1], button_size[0], 3), color[::-1], dtype=np.uint8 |
|
) |
|
cv2.putText( |
|
button_img, |
|
text, |
|
(10, 10 + text_height), |
|
cv2.FONT_HERSHEY_SIMPLEX, |
|
0.5, |
|
(255, 255, 255), |
|
1, |
|
) |
|
end_x = min(x1 + button_size[0], image.shape[1]) |
|
end_y = min(y1 + button_size[1], image.shape[0]) |
|
image[y1:end_y, x1:end_x] = button_img[: end_y - y1, : end_x - x1] |
|
return image |
|
|
|
|
|
def bbox_to_points( |
|
box: Union[ObjectDetectionPrediction, InstanceSegmentationPrediction], |
|
) -> Tuple[Tuple[int, int], Tuple[int, int]]: |
|
x1 = int(box.x - box.width / 2) |
|
x2 = int(box.x + box.width / 2) |
|
y1 = int(box.y - box.height / 2) |
|
y2 = int(box.y + box.height / 2) |
|
return (x1, y1), (x2, y2) |
|
|