CoolFace
Apppublic

VerokeAI/Object_tracking_boxmot

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
ops.py189 linesDownload Raw Back to utils
1# Mikel Broström 🔥 Yolo Tracking 🧾 AGPL-3.0 license2 3import numpy as np4import torch5import cv26from typing import Tuple, Union7 8 9def xyxy2xywh(x):10    """11    Convert bounding box coordinates from (x1, y1, x2, y2) format to (x, y, width, height) format.12 13    Args:14        x (np.ndarray) or (torch.Tensor): The input bounding box coordinates in (x1, y1, x2, y2) format.15    Returns:16       y (np.ndarray) or (torch.Tensor): The bounding box coordinates in (x, y, width, height) format.17    """18    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)19    y[..., 0] = (x[..., 0] + x[..., 2]) / 2  # x center20    y[..., 1] = (x[..., 1] + x[..., 3]) / 2  # y center21    y[..., 2] = x[..., 2] - x[..., 0]  # width22    y[..., 3] = x[..., 3] - x[..., 1]  # height23    return y24 25 26def xywh2xyxy(x):27    """28    Convert bounding box coordinates from (x_c, y_c, width, height) format to29    (x1, y1, x2, y2) format where (x1, y1) is the top-left corner and (x2, y2)30    is the bottom-right corner.31 32    Args:33        x (np.ndarray) or (torch.Tensor): The input bounding box coordinates in (x, y, width, height) format.34    Returns:35        y (np.ndarray) or (torch.Tensor): The bounding box coordinates in (x1, y1, x2, y2) format.36    """37    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)38    y[..., 0] = x[..., 0] - x[..., 2] / 2  # top left x39    y[..., 1] = x[..., 1] - x[..., 3] / 2  # top left y40    y[..., 2] = x[..., 0] + x[..., 2] / 2  # bottom right x41    y[..., 3] = x[..., 1] + x[..., 3] / 2  # bottom right y42    return y43 44 45def xywh2tlwh(x):46    """47    Convert bounding box coordinates from (x c, y c, w, h) format to (t, l, w, h) format where (t, l) is the48    top-left corner and (w, h) is width and height.49 50    Args:51        x (np.ndarray) or (torch.Tensor): The input bounding box coordinates in (x, y, width, height) format.52    Returns:53        y (np.ndarray) or (torch.Tensor): The bounding box coordinates in (x1, y1, x2, y2) format.54    """55    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)56    y[..., 0] = x[..., 0] - x[..., 2] / 2.0  # xc --> t57    y[..., 1] = x[..., 1] - x[..., 3] / 2.0  # yc --> l58    y[..., 2] = x[..., 2]                    # width59    y[..., 3] = x[..., 3]                    # height60    return y61 62 63def tlwh2xyxy(x):64    """65    Convert bounding box coordinates from (t, l ,w ,h) format to (t, l, w, h) format where (t, l) is the66    top-left corner and (w, h) is width and height.67    """68    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)69    y[..., 0] = x[..., 0]70    y[..., 1] = x[..., 1]71    y[..., 2] = x[..., 0] + x[..., 2]72    y[..., 3] = x[..., 1] + x[..., 3]73    return y74 75 76def xyxy2tlwh(x):77    """78    Convert bounding box coordinates from (t, l ,w ,h) format to (t, l, w, h) format where (t, l) is the79    top-left corner and (w, h) is width and height.80    """81    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)82    y[..., 0] = x[..., 0]83    y[..., 1] = x[..., 1]84    y[..., 2] = x[..., 2] - x[..., 0]85    y[..., 3] = x[..., 3] - x[..., 1]86    return y87 88 89def tlwh2xyah(x):90    """91    Convert bounding box coordinates from (t, l ,w ,h)92    to (center x, center y, aspect ratio, height)`, where the aspect ratio is `width / height`.93    """94    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)95    y[..., 0] = x[..., 0] + (x[..., 2] / 2)96    y[..., 1] = x[..., 1] + (x[..., 3] / 2)97    y[..., 2] = x[..., 2] / x[..., 3]98    y[..., 3] = x[..., 3]99    return y100 101 102def xyxy2xysr(x):103    """104    Converts bounding box coordinates from (x1, y1, x2, y2) format to (x, y, s, r) format.105 106    Args:107        bbox (np.ndarray) or (torch.Tensor): The input bounding box coordinates in (x1, y1, x2, y2) format.108    Returns:109        z (np.ndarray) or (torch.Tensor): The bounding box coordinates in (x, y, s, r) format, where110                                          x, y is the center of the box,111                                          s is the scale (area), and112                                          r is the aspect ratio.113    """114    x = x[0:4]115    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)116    w = y[..., 2] - y[..., 0]  # width117    h = y[..., 3] - y[..., 1]  # height118    y[..., 0] = y[..., 0] + w / 2.0            # x center119    y[..., 1] = y[..., 1] + h / 2.0            # y center120    y[..., 2] = w * h                                  # scale (area)121    y[..., 3] = w / (h + 1e-6)                         # aspect ratio122    y = y.reshape((4, 1))123    return y124 125 126def letterbox(127    img: np.ndarray,128    new_shape: Union[int, Tuple[int, int]] = (640, 640),129    color: Tuple[int, int, int] = (114, 114, 114),130    auto: bool = True,131    scaleFill: bool = False,132    scaleup: bool = True133) -> Tuple[np.ndarray, Tuple[float, float], Tuple[float, float]]:134    """135    Resizes an image to a new shape while maintaining aspect ratio, padding with color if needed.136 137    Args:138        img (np.ndarray): The original image in BGR format.139        new_shape (Union[int, Tuple[int, int]], optional): Desired size as an integer (e.g., 640) 140            or tuple (width, height). Default is (640, 640).141        color (Tuple[int, int, int], optional): Padding color in BGR format. Default is (114, 114, 114).142        auto (bool, optional): If True, adjusts padding to be a multiple of 32. Default is True.143        scaleFill (bool, optional): If True, stretches the image to fill the new shape. Default is False.144        scaleup (bool, optional): If True, allows scaling up; otherwise, only scales down. Default is True.145 146    Returns:147        Tuple[np.ndarray, Tuple[float, float], Tuple[float, float]]:148            - Resized and padded image as np.ndarray.149            - Scaling ratio used for width and height as (width_ratio, height_ratio).150            - Padding applied to width and height as (width_padding, height_padding).151    """152    shape = img.shape[:2]  # current shape [height, width]153 154    # Ensure new_shape is a tuple (width, height)155    if isinstance(new_shape, int):156        new_shape = (new_shape, new_shape)157 158    # Calculate scale ratio159    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])160    if not scaleup:161        r = min(r, 1.0)  # only scale down162 163    # Calculate new dimensions and padding164    ratio = (r, r)165    new_unpad = (int(round(shape[1] * r)), int(round(shape[0] * r)))166    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]167 168    if auto:  # minimum rectangle169        dw, dh = np.mod(dw, 32), np.mod(dh, 32)170    elif scaleFill:  # stretch to fill171        dw, dh = 0.0, 0.0172        new_unpad = new_shape173        ratio = (new_shape[1] / shape[1], new_shape[0] / shape[0])174 175    # Divide padding by 2 for even distribution176    dw /= 2177    dh /= 2178 179    # Resize image if necessary180    if shape[::-1] != new_unpad:181        img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)182 183    # Add border to the image184    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))185    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))186    img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)187 188    return img, ratio, (dw, dh)189