Loading imgutils/detect/base.py +3 −0 Original line number Diff line number Diff line from typing import Tuple import numpy as np BBoxTyping = Tuple[float, float, float, float] BBoxWithScoreAndLabel = Tuple[BBoxTyping, str, float] MaskWithScoreAndLabel = Tuple[BBoxTyping, str, float, np.ndarray] imgutils/detect/visual.py +32 −8 Original line number Diff line number Diff line Loading @@ -10,12 +10,14 @@ Overview: See :func:`imgutils.detect.head.detect_heads` and :func:`imgutils.detect.person.detect_person` for examples. """ import math from typing import List, Tuple, Optional from typing import List, Optional, Union from PIL import ImageFont, ImageDraw import numpy as np from PIL import ImageFont, ImageDraw, Image from hbutils.color import rnd_colors, Color from imgutils.data import ImageTyping, load_image from .base import BBoxWithScoreAndLabel, MaskWithScoreAndLabel from ..data import ImageTyping, load_image def _try_get_font_from_matplotlib(fp=None, fontsize: int = 12): Loading @@ -42,9 +44,10 @@ def _try_get_font_from_matplotlib(fp=None, fontsize: int = 12): return ImageFont.truetype(font, fontsize) def detection_visualize(image: ImageTyping, detection: List[Tuple[Tuple[float, float, float, float], str, float]], def detection_visualize(image: ImageTyping, detection: List[Union[BBoxWithScoreAndLabel, MaskWithScoreAndLabel]], labels: Optional[List[str]] = None, text_padding: int = 6, fontsize: int = 12, max_short_edge_size: Optional[int] = None, fp=None, no_label: bool = False): max_short_edge_size: Optional[int] = None, mask_alpha: float = 0.5, fp=None, no_label: bool = False): """ Visualize object detection results by drawing bounding boxes and labels on an image. Loading @@ -52,7 +55,7 @@ def detection_visualize(image: ImageTyping, detection: List[Tuple[Tuple[float, f :type image: ImageTyping :param detection: List of detection results, each containing ((x0, y0, x1, y1), label, confidence_score). Coordinates should be in pixels, not normalized. :type detection: List[Tuple[Tuple[float, float, float, float], str, float]] :type detection: List[Union[Tuple[Tuple[float, float, float, float], str, float], Tuple[Tuple[float, float, float, float], str, float, np.ndarray]] :param labels: List of predefined labels. If None, labels will be extracted from detection results. :type labels: Optional[List[str]] :param text_padding: Padding around label text in pixels. Loading Loading @@ -95,15 +98,36 @@ def detection_visualize(image: ImageTyping, detection: List[Tuple[Tuple[float, f draw = ImageDraw.Draw(visual_image, mode='RGBA') font = _try_get_font_from_matplotlib(fp, fontsize) or ImageFont.load_default() labels = sorted(labels or {label for _, label, _ in detection}) labels = sorted(labels or {label for _, label, *_ in detection}) _colors = list(map(str, rnd_colors(len(labels)))) _color_map = dict(zip(labels, _colors)) for _, ((x0, y0, x1, y1), label, score) in sorted(enumerate(detection), key=lambda x: (x[1][2], x[0])): for _, detect_item in sorted(enumerate(detection), key=lambda x: (x[1][2], x[0])): if len(detect_item) == 3: (x0, y0, x1, y1), label, score = detect_item mask = None else: (x0, y0, x1, y1), label, score, mask = detect_item x0, y0 = int(x0 * new_width / original_width), int(y0 * new_height / original_height) x1, y1 = int(x1 * new_width / original_width), int(y1 * new_height / original_height) box_color = _color_map[label] draw.rectangle((x0, y0, x1, y1), outline=box_color, width=2) if mask is not None: if mask.shape[0] != new_height or mask.shape[1] != new_width: mask_pil = Image.fromarray((mask * 255).astype(np.uint8)) mask_pil = mask_pil.resize((new_width, new_height), Image.BILINEAR) mask = np.array(mask_pil) / 255.0 color = Color(box_color) overlay = np.zeros((new_height, new_width, 4), dtype=np.uint8) overlay[..., 0] = int(color.rgb.red * 255) overlay[..., 1] = int(color.rgb.green * 255) overlay[..., 2] = int(color.rgb.blue * 255) overlay[..., 3] = (mask * mask_alpha * 255).astype(np.uint8) overlay_pil = Image.fromarray(overlay) visual_image.paste(overlay_pil, (0, 0), overlay_pil) if not no_label: label_text = f'{label}: {score * 100:.2f}%' _t_x0, _t_y0, _t_x1, _t_y1 = draw.textbbox((x0, y0), label_text, font=font) Loading imgutils/generic/__init__.py +1 −0 Original line number Diff line number Diff line Loading @@ -9,3 +9,4 @@ from .enhance import * from .multilabel_timm import * from .siglip import * from .yolo import * from .yoloseg import * imgutils/generic/yoloseg.py 0 → 100644 +481 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
imgutils/detect/base.py +3 −0 Original line number Diff line number Diff line from typing import Tuple import numpy as np BBoxTyping = Tuple[float, float, float, float] BBoxWithScoreAndLabel = Tuple[BBoxTyping, str, float] MaskWithScoreAndLabel = Tuple[BBoxTyping, str, float, np.ndarray]
imgutils/detect/visual.py +32 −8 Original line number Diff line number Diff line Loading @@ -10,12 +10,14 @@ Overview: See :func:`imgutils.detect.head.detect_heads` and :func:`imgutils.detect.person.detect_person` for examples. """ import math from typing import List, Tuple, Optional from typing import List, Optional, Union from PIL import ImageFont, ImageDraw import numpy as np from PIL import ImageFont, ImageDraw, Image from hbutils.color import rnd_colors, Color from imgutils.data import ImageTyping, load_image from .base import BBoxWithScoreAndLabel, MaskWithScoreAndLabel from ..data import ImageTyping, load_image def _try_get_font_from_matplotlib(fp=None, fontsize: int = 12): Loading @@ -42,9 +44,10 @@ def _try_get_font_from_matplotlib(fp=None, fontsize: int = 12): return ImageFont.truetype(font, fontsize) def detection_visualize(image: ImageTyping, detection: List[Tuple[Tuple[float, float, float, float], str, float]], def detection_visualize(image: ImageTyping, detection: List[Union[BBoxWithScoreAndLabel, MaskWithScoreAndLabel]], labels: Optional[List[str]] = None, text_padding: int = 6, fontsize: int = 12, max_short_edge_size: Optional[int] = None, fp=None, no_label: bool = False): max_short_edge_size: Optional[int] = None, mask_alpha: float = 0.5, fp=None, no_label: bool = False): """ Visualize object detection results by drawing bounding boxes and labels on an image. Loading @@ -52,7 +55,7 @@ def detection_visualize(image: ImageTyping, detection: List[Tuple[Tuple[float, f :type image: ImageTyping :param detection: List of detection results, each containing ((x0, y0, x1, y1), label, confidence_score). Coordinates should be in pixels, not normalized. :type detection: List[Tuple[Tuple[float, float, float, float], str, float]] :type detection: List[Union[Tuple[Tuple[float, float, float, float], str, float], Tuple[Tuple[float, float, float, float], str, float, np.ndarray]] :param labels: List of predefined labels. If None, labels will be extracted from detection results. :type labels: Optional[List[str]] :param text_padding: Padding around label text in pixels. Loading Loading @@ -95,15 +98,36 @@ def detection_visualize(image: ImageTyping, detection: List[Tuple[Tuple[float, f draw = ImageDraw.Draw(visual_image, mode='RGBA') font = _try_get_font_from_matplotlib(fp, fontsize) or ImageFont.load_default() labels = sorted(labels or {label for _, label, _ in detection}) labels = sorted(labels or {label for _, label, *_ in detection}) _colors = list(map(str, rnd_colors(len(labels)))) _color_map = dict(zip(labels, _colors)) for _, ((x0, y0, x1, y1), label, score) in sorted(enumerate(detection), key=lambda x: (x[1][2], x[0])): for _, detect_item in sorted(enumerate(detection), key=lambda x: (x[1][2], x[0])): if len(detect_item) == 3: (x0, y0, x1, y1), label, score = detect_item mask = None else: (x0, y0, x1, y1), label, score, mask = detect_item x0, y0 = int(x0 * new_width / original_width), int(y0 * new_height / original_height) x1, y1 = int(x1 * new_width / original_width), int(y1 * new_height / original_height) box_color = _color_map[label] draw.rectangle((x0, y0, x1, y1), outline=box_color, width=2) if mask is not None: if mask.shape[0] != new_height or mask.shape[1] != new_width: mask_pil = Image.fromarray((mask * 255).astype(np.uint8)) mask_pil = mask_pil.resize((new_width, new_height), Image.BILINEAR) mask = np.array(mask_pil) / 255.0 color = Color(box_color) overlay = np.zeros((new_height, new_width, 4), dtype=np.uint8) overlay[..., 0] = int(color.rgb.red * 255) overlay[..., 1] = int(color.rgb.green * 255) overlay[..., 2] = int(color.rgb.blue * 255) overlay[..., 3] = (mask * mask_alpha * 255).astype(np.uint8) overlay_pil = Image.fromarray(overlay) visual_image.paste(overlay_pil, (0, 0), overlay_pil) if not no_label: label_text = f'{label}: {score * 100:.2f}%' _t_x0, _t_y0, _t_x1, _t_y1 = draw.textbbox((x0, y0), label_text, font=font) Loading
imgutils/generic/__init__.py +1 −0 Original line number Diff line number Diff line Loading @@ -9,3 +9,4 @@ from .enhance import * from .multilabel_timm import * from .siglip import * from .yolo import * from .yoloseg import *
imgutils/generic/yoloseg.py 0 → 100644 +481 −0 File added.Preview size limit exceeded, changes collapsed. Show changes