Bỏ để qua phần nội dung

Tài liệu tham khảo cho ultralytics/utils/ops.py

Ghi

Tệp này có sẵn tại https://github.com/ultralytics/ultralytics/blob/main/ultralytics/utils/ops.py. Nếu bạn phát hiện ra một vấn đề, vui lòng giúp khắc phục nó bằng cách đóng góp Yêu cầu 🛠️ kéo. Cảm ơn bạn 🙏 !



ultralytics.utils.ops.Profile

Căn cứ: ContextDecorator

YOLOv8 Lớp hồ sơ. Sử dụng như một trang trí với @Profile () hoặc như một trình quản lý ngữ cảnh với 'với Profile ():'.

Ví dụ
from ultralytics.utils.ops import Profile

with Profile(device=device) as dt:
    pass  # slow operation here

print(dt)  # prints "Elapsed time is 9.5367431640625e-07 s"
Mã nguồn trong ultralytics/utils/ops.py
class Profile(contextlib.ContextDecorator):
    """
    YOLOv8 Profile class. Use as a decorator with @Profile() or as a context manager with 'with Profile():'.

    Example:
        ```python
        from ultralytics.utils.ops import Profile

        with Profile(device=device) as dt:
            pass  # slow operation here

        print(dt)  # prints "Elapsed time is 9.5367431640625e-07 s"
        ```
    """

    def __init__(self, t=0.0, device: torch.device = None):
        """
        Initialize the Profile class.

        Args:
            t (float): Initial time. Defaults to 0.0.
            device (torch.device): Devices used for model inference. Defaults to None (cpu).
        """
        self.t = t
        self.device = device
        self.cuda = bool(device and str(device).startswith("cuda"))

    def __enter__(self):
        """Start timing."""
        self.start = self.time()
        return self

    def __exit__(self, type, value, traceback):  # noqa
        """Stop timing."""
        self.dt = self.time() - self.start  # delta-time
        self.t += self.dt  # accumulate dt

    def __str__(self):
        """Returns a human-readable string representing the accumulated elapsed time in the profiler."""
        return f"Elapsed time is {self.t} s"

    def time(self):
        """Get current time."""
        if self.cuda:
            torch.cuda.synchronize(self.device)
        return time.time()

__enter__()

Bắt đầu tính giờ.

Mã nguồn trong ultralytics/utils/ops.py
def __enter__(self):
    """Start timing."""
    self.start = self.time()
    return self

__exit__(type, value, traceback)

Dừng thời gian.

Mã nguồn trong ultralytics/utils/ops.py
def __exit__(self, type, value, traceback):  # noqa
    """Stop timing."""
    self.dt = self.time() - self.start  # delta-time
    self.t += self.dt  # accumulate dt

__init__(t=0.0, device=None)

Khởi tạo lớp Profile.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
t float

Thời gian đầu. Mặc định là 0,0.

0.0
device device

Thiết bị được sử dụng để suy luận mô hình. Mặc định là Không có (cpu).

None
Mã nguồn trong ultralytics/utils/ops.py
def __init__(self, t=0.0, device: torch.device = None):
    """
    Initialize the Profile class.

    Args:
        t (float): Initial time. Defaults to 0.0.
        device (torch.device): Devices used for model inference. Defaults to None (cpu).
    """
    self.t = t
    self.device = device
    self.cuda = bool(device and str(device).startswith("cuda"))

__str__()

Trả về một chuỗi mà con người có thể đọc được đại diện cho thời gian đã trôi qua tích lũy trong profiler.

Mã nguồn trong ultralytics/utils/ops.py
def __str__(self):
    """Returns a human-readable string representing the accumulated elapsed time in the profiler."""
    return f"Elapsed time is {self.t} s"

time()

Nhận thời gian hiện tại.

Mã nguồn trong ultralytics/utils/ops.py
def time(self):
    """Get current time."""
    if self.cuda:
        torch.cuda.synchronize(self.device)
    return time.time()



ultralytics.utils.ops.segment2box(segment, width=640, height=640)

Chuyển đổi 1 nhãn phân đoạn thành 1 nhãn hộp, áp dụng ràng buộc hình ảnh bên trong, tức là (xy1, xy2, ...) thành (xyxy).

Thông số:

Tên Kiểu Sự miêu tả Mặc định
segment Tensor

nhãn phân khúc

bắt buộc
width int

chiều rộng của hình ảnh. Mặc định là 640

640
height int

Chiều cao của hình ảnh. Mặc định là 640

640

Trở lại:

Kiểu Sự miêu tả
ndarray

giá trị x và y tối thiểu và tối đa của phân khúc.

Mã nguồn trong ultralytics/utils/ops.py
def segment2box(segment, width=640, height=640):
    """
    Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy).

    Args:
        segment (torch.Tensor): the segment label
        width (int): the width of the image. Defaults to 640
        height (int): The height of the image. Defaults to 640

    Returns:
        (np.ndarray): the minimum and maximum x and y values of the segment.
    """
    x, y = segment.T  # segment xy
    inside = (x >= 0) & (y >= 0) & (x <= width) & (y <= height)
    x = x[inside]
    y = y[inside]
    return (
        np.array([x.min(), y.min(), x.max(), y.max()], dtype=segment.dtype)
        if any(x)
        else np.zeros(4, dtype=segment.dtype)
    )  # xyxy



ultralytics.utils.ops.scale_boxes(img1_shape, boxes, img0_shape, ratio_pad=None, padding=True, xywh=False)

Thay đổi tỷ lệ các hộp giới hạn (theo định dạng xyxy theo mặc định) từ hình dạng của hình ảnh ban đầu được chỉ định trong (img1_shape) thành hình dạng của một hình ảnh khác (img0_shape).

Thông số:

Tên Kiểu Sự miêu tả Mặc định
img1_shape tuple

Hình dạng của hình ảnh mà các hộp giới hạn dành cho, theo định dạng (chiều cao, chiều rộng).

bắt buộc
boxes Tensor

các hộp giới hạn của các đối tượng trong hình ảnh, theo định dạng (x1, y1, x2, y2)

bắt buộc
img0_shape tuple

Hình dạng của hình ảnh mục tiêu, theo định dạng (chiều cao, chiều rộng).

bắt buộc
ratio_pad tuple

một bộ (tỷ lệ, pad) để chia tỷ lệ các hộp. Nếu không được cung cấp, tỷ lệ và miếng đệm sẽ là được tính toán dựa trên sự khác biệt về kích thước giữa hai hình ảnh.

None
padding bool

Nếu True, giả sử các hộp dựa trên hình ảnh được tăng cường bởi yolo phong cách. Nếu False thì làm thường xuyên thay đổi quy mô.

True
xywh bool

Định dạng hộp có phải là xywh hay không, default=False.

False

Trở lại:

Tên Kiểu Sự miêu tả
boxes Tensor

Các hộp giới hạn được chia tỷ lệ, ở định dạng (x1, y1, x2, y2)

Mã nguồn trong ultralytics/utils/ops.py
def scale_boxes(img1_shape, boxes, img0_shape, ratio_pad=None, padding=True, xywh=False):
    """
    Rescales bounding boxes (in the format of xyxy by default) from the shape of the image they were originally
    specified in (img1_shape) to the shape of a different image (img0_shape).

    Args:
        img1_shape (tuple): The shape of the image that the bounding boxes are for, in the format of (height, width).
        boxes (torch.Tensor): the bounding boxes of the objects in the image, in the format of (x1, y1, x2, y2)
        img0_shape (tuple): the shape of the target image, in the format of (height, width).
        ratio_pad (tuple): a tuple of (ratio, pad) for scaling the boxes. If not provided, the ratio and pad will be
            calculated based on the size difference between the two images.
        padding (bool): If True, assuming the boxes is based on image augmented by yolo style. If False then do regular
            rescaling.
        xywh (bool): The box format is xywh or not, default=False.

    Returns:
        boxes (torch.Tensor): The scaled bounding boxes, in the format of (x1, y1, x2, y2)
    """
    if ratio_pad is None:  # calculate from img0_shape
        gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1])  # gain  = old / new
        pad = (
            round((img1_shape[1] - img0_shape[1] * gain) / 2 - 0.1),
            round((img1_shape[0] - img0_shape[0] * gain) / 2 - 0.1),
        )  # wh padding
    else:
        gain = ratio_pad[0][0]
        pad = ratio_pad[1]

    if padding:
        boxes[..., 0] -= pad[0]  # x padding
        boxes[..., 1] -= pad[1]  # y padding
        if not xywh:
            boxes[..., 2] -= pad[0]  # x padding
            boxes[..., 3] -= pad[1]  # y padding
    boxes[..., :4] /= gain
    return clip_boxes(boxes, img0_shape)



ultralytics.utils.ops.make_divisible(x, divisor)

Trả về số gần nhất chia hết cho ước số đã cho.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x int

Con số để chia hết.

bắt buộc
divisor int | Tensor

Số chia.

bắt buộc

Trở lại:

Kiểu Sự miêu tả
int

Số gần nhất chia hết cho ước số.

Mã nguồn trong ultralytics/utils/ops.py
def make_divisible(x, divisor):
    """
    Returns the nearest number that is divisible by the given divisor.

    Args:
        x (int): The number to make divisible.
        divisor (int | torch.Tensor): The divisor.

    Returns:
        (int): The nearest number divisible by the divisor.
    """
    if isinstance(divisor, torch.Tensor):
        divisor = int(divisor.max())  # to int
    return math.ceil(x / divisor) * divisor



ultralytics.utils.ops.nms_rotated(boxes, scores, threshold=0.45)

NMS cho obbs, được cung cấp bởi probiou và fast-nms.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
boxes Tensor

(N, 5), xywhr.

bắt buộc
scores Tensor

(N,).

bắt buộc
threshold float

Ngưỡng IoU.

0.45

Trở lại:

Mã nguồn trong ultralytics/utils/ops.py
def nms_rotated(boxes, scores, threshold=0.45):
    """
    NMS for obbs, powered by probiou and fast-nms.

    Args:
        boxes (torch.Tensor): (N, 5), xywhr.
        scores (torch.Tensor): (N, ).
        threshold (float): IoU threshold.

    Returns:
    """
    if len(boxes) == 0:
        return np.empty((0,), dtype=np.int8)
    sorted_idx = torch.argsort(scores, descending=True)
    boxes = boxes[sorted_idx]
    ious = batch_probiou(boxes, boxes).triu_(diagonal=1)
    pick = torch.nonzero(ious.max(dim=0)[0] < threshold).squeeze_(-1)
    return sorted_idx[pick]



ultralytics.utils.ops.non_max_suppression(prediction, conf_thres=0.25, iou_thres=0.45, classes=None, agnostic=False, multi_label=False, labels=(), max_det=300, nc=0, max_time_img=0.05, max_nms=30000, max_wh=7680, in_place=True, rotated=False)

Thực hiện triệt tiêu không tối đa (NMS) trên một bộ hộp, với sự hỗ trợ cho mặt nạ và nhiều nhãn trên mỗi hộp.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
prediction Tensor

Một tensor hình dạng (batch_size, num_classes + 4 + num_masks, num_boxes) chứa các hộp, lớp và mặt nạ dự đoán. Các tensor nên ở định dạng đầu ra của một mô hình, chẳng hạn như YOLO.

bắt buộc
conf_thres float

Ngưỡng tin cậy dưới đó các hộp sẽ được lọc ra. Giá trị hợp lệ nằm trong khoảng từ 0,0 đến 1,0.

0.25
iou_thres float

Ngưỡng IoU bên dưới các hộp sẽ được lọc ra trong NMS. Giá trị hợp lệ nằm trong khoảng từ 0,0 đến 1,0.

0.45
classes List[int]

Một danh sách các chỉ số lớp để xem xét. Nếu Không có, tất cả các lớp sẽ được xem xét.

None
agnostic bool

Nếu True, mô hình là bất khả tri với số lượng các lớp, và tất cả Các lớp học sẽ được coi là một.

False
multi_label bool

Nếu True, mỗi hộp có thể có nhiều nhãn.

False
labels List[List[Union[int, float, Tensor]]]

Một danh sách các danh sách, trong đó mỗi bên trong Danh sách chứa các nhãn apriori cho một hình ảnh nhất định. Danh sách phải ở định dạng đầu ra bởi bộ tải dữ liệu, với mỗi nhãn là một bộ (class_index, x1, y1, x2, y2).

()
max_det int

Số lượng hộp tối đa để giữ sau NMS.

300
nc int

Số lượng lớp đầu ra theo mô hình. Bất kỳ chỉ số nào sau này sẽ được coi là mặt nạ.

0
max_time_img float

Thời gian tối đa (giây) để xử lý một hình ảnh.

0.05
max_nms int

Số lượng hộp tối đa vào torchvision.ops.nms().

30000
max_wh int

Chiều rộng và chiều cao hộp tối đa tính bằng pixel.

7680
in_place bool

Nếu True, dự đoán đầu vào tensor sẽ được sửa đổi tại chỗ.

True

Trở lại:

Kiểu Sự miêu tả
List[Tensor]

Một danh sách độ dài batch_size, trong đó mỗi phần tử là một tensor của hình dạng (num_boxes, 6 + num_masks) chứa các hộp được giữ, với các cột (x1, y1, x2, y2, tự tin, class, mask1, mask2,...).

Mã nguồn trong ultralytics/utils/ops.py
def non_max_suppression(
    prediction,
    conf_thres=0.25,
    iou_thres=0.45,
    classes=None,
    agnostic=False,
    multi_label=False,
    labels=(),
    max_det=300,
    nc=0,  # number of classes (optional)
    max_time_img=0.05,
    max_nms=30000,
    max_wh=7680,
    in_place=True,
    rotated=False,
):
    """
    Perform non-maximum suppression (NMS) on a set of boxes, with support for masks and multiple labels per box.

    Args:
        prediction (torch.Tensor): A tensor of shape (batch_size, num_classes + 4 + num_masks, num_boxes)
            containing the predicted boxes, classes, and masks. The tensor should be in the format
            output by a model, such as YOLO.
        conf_thres (float): The confidence threshold below which boxes will be filtered out.
            Valid values are between 0.0 and 1.0.
        iou_thres (float): The IoU threshold below which boxes will be filtered out during NMS.
            Valid values are between 0.0 and 1.0.
        classes (List[int]): A list of class indices to consider. If None, all classes will be considered.
        agnostic (bool): If True, the model is agnostic to the number of classes, and all
            classes will be considered as one.
        multi_label (bool): If True, each box may have multiple labels.
        labels (List[List[Union[int, float, torch.Tensor]]]): A list of lists, where each inner
            list contains the apriori labels for a given image. The list should be in the format
            output by a dataloader, with each label being a tuple of (class_index, x1, y1, x2, y2).
        max_det (int): The maximum number of boxes to keep after NMS.
        nc (int, optional): The number of classes output by the model. Any indices after this will be considered masks.
        max_time_img (float): The maximum time (seconds) for processing one image.
        max_nms (int): The maximum number of boxes into torchvision.ops.nms().
        max_wh (int): The maximum box width and height in pixels.
        in_place (bool): If True, the input prediction tensor will be modified in place.

    Returns:
        (List[torch.Tensor]): A list of length batch_size, where each element is a tensor of
            shape (num_boxes, 6 + num_masks) containing the kept boxes, with columns
            (x1, y1, x2, y2, confidence, class, mask1, mask2, ...).
    """
    import torchvision  # scope for faster 'import ultralytics'

    # Checks
    assert 0 <= conf_thres <= 1, f"Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0"
    assert 0 <= iou_thres <= 1, f"Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0"
    if isinstance(prediction, (list, tuple)):  # YOLOv8 model in validation model, output = (inference_out, loss_out)
        prediction = prediction[0]  # select only inference output

    bs = prediction.shape[0]  # batch size
    nc = nc or (prediction.shape[1] - 4)  # number of classes
    nm = prediction.shape[1] - nc - 4  # number of masks
    mi = 4 + nc  # mask start index
    xc = prediction[:, 4:mi].amax(1) > conf_thres  # candidates

    # Settings
    # min_wh = 2  # (pixels) minimum box width and height
    time_limit = 2.0 + max_time_img * bs  # seconds to quit after
    multi_label &= nc > 1  # multiple labels per box (adds 0.5ms/img)

    prediction = prediction.transpose(-1, -2)  # shape(1,84,6300) to shape(1,6300,84)
    if not rotated:
        if in_place:
            prediction[..., :4] = xywh2xyxy(prediction[..., :4])  # xywh to xyxy
        else:
            prediction = torch.cat((xywh2xyxy(prediction[..., :4]), prediction[..., 4:]), dim=-1)  # xywh to xyxy

    t = time.time()
    output = [torch.zeros((0, 6 + nm), device=prediction.device)] * bs
    for xi, x in enumerate(prediction):  # image index, image inference
        # Apply constraints
        # x[((x[:, 2:4] < min_wh) | (x[:, 2:4] > max_wh)).any(1), 4] = 0  # width-height
        x = x[xc[xi]]  # confidence

        # Cat apriori labels if autolabelling
        if labels and len(labels[xi]) and not rotated:
            lb = labels[xi]
            v = torch.zeros((len(lb), nc + nm + 4), device=x.device)
            v[:, :4] = xywh2xyxy(lb[:, 1:5])  # box
            v[range(len(lb)), lb[:, 0].long() + 4] = 1.0  # cls
            x = torch.cat((x, v), 0)

        # If none remain process next image
        if not x.shape[0]:
            continue

        # Detections matrix nx6 (xyxy, conf, cls)
        box, cls, mask = x.split((4, nc, nm), 1)

        if multi_label:
            i, j = torch.where(cls > conf_thres)
            x = torch.cat((box[i], x[i, 4 + j, None], j[:, None].float(), mask[i]), 1)
        else:  # best class only
            conf, j = cls.max(1, keepdim=True)
            x = torch.cat((box, conf, j.float(), mask), 1)[conf.view(-1) > conf_thres]

        # Filter by class
        if classes is not None:
            x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)]

        # Check shape
        n = x.shape[0]  # number of boxes
        if not n:  # no boxes
            continue
        if n > max_nms:  # excess boxes
            x = x[x[:, 4].argsort(descending=True)[:max_nms]]  # sort by confidence and remove excess boxes

        # Batched NMS
        c = x[:, 5:6] * (0 if agnostic else max_wh)  # classes
        scores = x[:, 4]  # scores
        if rotated:
            boxes = torch.cat((x[:, :2] + c, x[:, 2:4], x[:, -1:]), dim=-1)  # xywhr
            i = nms_rotated(boxes, scores, iou_thres)
        else:
            boxes = x[:, :4] + c  # boxes (offset by class)
            i = torchvision.ops.nms(boxes, scores, iou_thres)  # NMS
        i = i[:max_det]  # limit detections

        # # Experimental
        # merge = False  # use merge-NMS
        # if merge and (1 < n < 3E3):  # Merge NMS (boxes merged using weighted mean)
        #     # Update boxes as boxes(i,4) = weights(i,n) * boxes(n,4)
        #     from .metrics import box_iou
        #     iou = box_iou(boxes[i], boxes) > iou_thres  # IoU matrix
        #     weights = iou * scores[None]  # box weights
        #     x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True)  # merged boxes
        #     redundant = True  # require redundant detections
        #     if redundant:
        #         i = i[iou.sum(1) > 1]  # require redundancy

        output[xi] = x[i]
        if (time.time() - t) > time_limit:
            LOGGER.warning(f"WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded")
            break  # time limit exceeded

    return output



ultralytics.utils.ops.clip_boxes(boxes, shape)

Lấy một danh sách các hộp giới hạn và một hình dạng (chiều cao, chiều rộng) và kẹp các hộp giới hạn vào hình dạng.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
boxes Tensor

Các hộp giới hạn để kẹp

bắt buộc
shape tuple

Hình dạng của hình ảnh

bắt buộc

Trở lại:

Kiểu Sự miêu tả
Tensor | ndarray

Hộp cắt

Mã nguồn trong ultralytics/utils/ops.py
def clip_boxes(boxes, shape):
    """
    Takes a list of bounding boxes and a shape (height, width) and clips the bounding boxes to the shape.

    Args:
        boxes (torch.Tensor): the bounding boxes to clip
        shape (tuple): the shape of the image

    Returns:
        (torch.Tensor | numpy.ndarray): Clipped boxes
    """
    if isinstance(boxes, torch.Tensor):  # faster individually (WARNING: inplace .clamp_() Apple MPS bug)
        boxes[..., 0] = boxes[..., 0].clamp(0, shape[1])  # x1
        boxes[..., 1] = boxes[..., 1].clamp(0, shape[0])  # y1
        boxes[..., 2] = boxes[..., 2].clamp(0, shape[1])  # x2
        boxes[..., 3] = boxes[..., 3].clamp(0, shape[0])  # y2
    else:  # np.array (faster grouped)
        boxes[..., [0, 2]] = boxes[..., [0, 2]].clip(0, shape[1])  # x1, x2
        boxes[..., [1, 3]] = boxes[..., [1, 3]].clip(0, shape[0])  # y1, y2
    return boxes



ultralytics.utils.ops.clip_coords(coords, shape)

Đường clip tọa độ đến ranh giới hình ảnh.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
coords Tensor | ndarray

Danh sách tọa độ đường.

bắt buộc
shape tuple

Một bộ số nguyên đại diện cho kích thước của hình ảnh ở định dạng (chiều cao, chiều rộng).

bắt buộc

Trở lại:

Kiểu Sự miêu tả
Tensor | ndarray

Tọa độ cắt

Mã nguồn trong ultralytics/utils/ops.py
def clip_coords(coords, shape):
    """
    Clip line coordinates to the image boundaries.

    Args:
        coords (torch.Tensor | numpy.ndarray): A list of line coordinates.
        shape (tuple): A tuple of integers representing the size of the image in the format (height, width).

    Returns:
        (torch.Tensor | numpy.ndarray): Clipped coordinates
    """
    if isinstance(coords, torch.Tensor):  # faster individually (WARNING: inplace .clamp_() Apple MPS bug)
        coords[..., 0] = coords[..., 0].clamp(0, shape[1])  # x
        coords[..., 1] = coords[..., 1].clamp(0, shape[0])  # y
    else:  # np.array (faster grouped)
        coords[..., 0] = coords[..., 0].clip(0, shape[1])  # x
        coords[..., 1] = coords[..., 1].clip(0, shape[0])  # y
    return coords



ultralytics.utils.ops.scale_image(masks, im0_shape, ratio_pad=None)

Lấy mặt nạ và thay đổi kích thước thành kích thước hình ảnh gốc.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
masks ndarray

Mặt nạ/hình ảnh được thay đổi kích thước và đệm, [h, w, num]/[h, w, 3].

bắt buộc
im0_shape tuple

Hình dạng hình ảnh gốc

bắt buộc
ratio_pad tuple

tỷ lệ của phần đệm so với hình ảnh gốc.

None

Trở lại:

Tên Kiểu Sự miêu tả
masks Tensor

Những chiếc mặt nạ đang được trả lại.

Mã nguồn trong ultralytics/utils/ops.py
def scale_image(masks, im0_shape, ratio_pad=None):
    """
    Takes a mask, and resizes it to the original image size.

    Args:
        masks (np.ndarray): resized and padded masks/images, [h, w, num]/[h, w, 3].
        im0_shape (tuple): the original image shape
        ratio_pad (tuple): the ratio of the padding to the original image.

    Returns:
        masks (torch.Tensor): The masks that are being returned.
    """
    # Rescale coordinates (xyxy) from im1_shape to im0_shape
    im1_shape = masks.shape
    if im1_shape[:2] == im0_shape[:2]:
        return masks
    if ratio_pad is None:  # calculate from im0_shape
        gain = min(im1_shape[0] / im0_shape[0], im1_shape[1] / im0_shape[1])  # gain  = old / new
        pad = (im1_shape[1] - im0_shape[1] * gain) / 2, (im1_shape[0] - im0_shape[0] * gain) / 2  # wh padding
    else:
        # gain = ratio_pad[0][0]
        pad = ratio_pad[1]
    top, left = int(pad[1]), int(pad[0])  # y, x
    bottom, right = int(im1_shape[0] - pad[1]), int(im1_shape[1] - pad[0])

    if len(masks.shape) < 2:
        raise ValueError(f'"len of masks shape" should be 2 or 3, but got {len(masks.shape)}')
    masks = masks[top:bottom, left:right]
    masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]))
    if len(masks.shape) == 2:
        masks = masks[:, :, None]

    return masks



ultralytics.utils.ops.xyxy2xywh(x)

Chuyển đổi tọa độ hộp giới hạn từ định dạng (x1, y1, x2, y2) sang định dạng (x, y, chiều rộng, chiều cao) trong đó (x1, y1) là góc trên cùng bên trái và (x2, y2) là góc dưới cùng bên phải.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

Tọa độ hộp giới hạn đầu vào ở định dạng (x1, y1, x2, y2).

bắt buộc

Trở lại:

Tên Kiểu Sự miêu tả
y ndarray | Tensor

Hộp giới hạn tọa độ theo định dạng (x, y, chiều rộng, chiều cao).

Mã nguồn trong ultralytics/utils/ops.py
def xyxy2xywh(x):
    """
    Convert bounding box coordinates from (x1, y1, x2, y2) format to (x, y, width, height) format where (x1, y1) is the
    top-left corner and (x2, y2) is the bottom-right corner.

    Args:
        x (np.ndarray | torch.Tensor): The input bounding box coordinates in (x1, y1, x2, y2) format.

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in (x, y, width, height) format.
    """
    assert x.shape[-1] == 4, f"input shape last dimension expected 4 but input shape is {x.shape}"
    y = torch.empty_like(x) if isinstance(x, torch.Tensor) else np.empty_like(x)  # faster than clone/copy
    y[..., 0] = (x[..., 0] + x[..., 2]) / 2  # x center
    y[..., 1] = (x[..., 1] + x[..., 3]) / 2  # y center
    y[..., 2] = x[..., 2] - x[..., 0]  # width
    y[..., 3] = x[..., 3] - x[..., 1]  # height
    return y



ultralytics.utils.ops.xywh2xyxy(x)

Convert bounding box coordinates from (x, y, width, height) format to (x1, y1, x2, y2) format where (x1, y1) is the top-left corner and (x2, y2) is the bottom-right corner. Note: ops per 2 channels faster than per channel.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

Hộp giới hạn đầu vào tọa độ theo định dạng (x, y, chiều rộng, chiều cao).

bắt buộc

Trở lại:

Tên Kiểu Sự miêu tả
y ndarray | Tensor

Tọa độ hộp giới hạn theo định dạng (x1, y1, x2, y2).

Mã nguồn trong ultralytics/utils/ops.py
def xywh2xyxy(x):
    """
    Convert bounding box coordinates from (x, y, width, height) format to (x1, y1, x2, y2) format where (x1, y1) is the
    top-left corner and (x2, y2) is the bottom-right corner. Note: ops per 2 channels faster than per channel.

    Args:
        x (np.ndarray | torch.Tensor): The input bounding box coordinates in (x, y, width, height) format.

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in (x1, y1, x2, y2) format.
    """
    assert x.shape[-1] == 4, f"input shape last dimension expected 4 but input shape is {x.shape}"
    y = torch.empty_like(x) if isinstance(x, torch.Tensor) else np.empty_like(x)  # faster than clone/copy
    xy = x[..., :2]  # centers
    wh = x[..., 2:] / 2  # half width-height
    y[..., :2] = xy - wh  # top left xy
    y[..., 2:] = xy + wh  # bottom right xy
    return y



ultralytics.utils.ops.xywhn2xyxy(x, w=640, h=640, padw=0, padh=0)

Chuyển đổi tọa độ hộp giới hạn chuẩn hóa thành tọa độ pixel.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

Tọa độ hộp giới hạn.

bắt buộc
w int

Chiều rộng của hình ảnh. Mặc định là 640

640
h int

Chiều cao của hình ảnh. Mặc định là 640

640
padw int

Chiều rộng đệm. Mặc định là 0

0
padh int

Chiều cao đệm. Mặc định là 0

0

Trở lại: y (np.ndarray | torch.Tensor): Tọa độ của hộp giới hạn ở định dạng [x1, y1, x2, y2] trong đó x1, y1 là góc trên cùng bên trái, x2, y2 là góc dưới cùng bên phải của hộp giới hạn.

Mã nguồn trong ultralytics/utils/ops.py
def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0):
    """
    Convert normalized bounding box coordinates to pixel coordinates.

    Args:
        x (np.ndarray | torch.Tensor): The bounding box coordinates.
        w (int): Width of the image. Defaults to 640
        h (int): Height of the image. Defaults to 640
        padw (int): Padding width. Defaults to 0
        padh (int): Padding height. Defaults to 0
    Returns:
        y (np.ndarray | torch.Tensor): The coordinates of the bounding box in the format [x1, y1, x2, y2] where
            x1,y1 is the top-left corner, x2,y2 is the bottom-right corner of the bounding box.
    """
    assert x.shape[-1] == 4, f"input shape last dimension expected 4 but input shape is {x.shape}"
    y = torch.empty_like(x) if isinstance(x, torch.Tensor) else np.empty_like(x)  # faster than clone/copy
    y[..., 0] = w * (x[..., 0] - x[..., 2] / 2) + padw  # top left x
    y[..., 1] = h * (x[..., 1] - x[..., 3] / 2) + padh  # top left y
    y[..., 2] = w * (x[..., 0] + x[..., 2] / 2) + padw  # bottom right x
    y[..., 3] = h * (x[..., 1] + x[..., 3] / 2) + padh  # bottom right y
    return y



ultralytics.utils.ops.xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0)

Chuyển đổi tọa độ hộp giới hạn từ định dạng (x1, y1, x2, y2) sang định dạng (x, y, chiều rộng, chiều cao, chuẩn hóa). x, y, Chiều rộng và chiều cao được chuẩn hóa theo kích thước hình ảnh.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

Tọa độ hộp giới hạn đầu vào ở định dạng (x1, y1, x2, y2).

bắt buộc
w int

Chiều rộng của hình ảnh. Mặc định là 640

640
h int

Chiều cao của hình ảnh. Mặc định là 640

640
clip bool

Nếu True, các hộp sẽ được cắt theo ranh giới hình ảnh. Mặc định là False

False
eps float

Giá trị tối thiểu của chiều rộng và chiều cao của hộp. Mặc định là 0,0

0.0

Trở lại:

Tên Kiểu Sự miêu tả
y ndarray | Tensor

Tọa độ hộp giới hạn theo định dạng (x, y, chiều rộng, chiều cao, chuẩn hóa)

Mã nguồn trong ultralytics/utils/ops.py
def xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0):
    """
    Convert bounding box coordinates from (x1, y1, x2, y2) format to (x, y, width, height, normalized) format. x, y,
    width and height are normalized to image dimensions.

    Args:
        x (np.ndarray | torch.Tensor): The input bounding box coordinates in (x1, y1, x2, y2) format.
        w (int): The width of the image. Defaults to 640
        h (int): The height of the image. Defaults to 640
        clip (bool): If True, the boxes will be clipped to the image boundaries. Defaults to False
        eps (float): The minimum value of the box's width and height. Defaults to 0.0

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in (x, y, width, height, normalized) format
    """
    if clip:
        x = clip_boxes(x, (h - eps, w - eps))
    assert x.shape[-1] == 4, f"input shape last dimension expected 4 but input shape is {x.shape}"
    y = torch.empty_like(x) if isinstance(x, torch.Tensor) else np.empty_like(x)  # faster than clone/copy
    y[..., 0] = ((x[..., 0] + x[..., 2]) / 2) / w  # x center
    y[..., 1] = ((x[..., 1] + x[..., 3]) / 2) / h  # y center
    y[..., 2] = (x[..., 2] - x[..., 0]) / w  # width
    y[..., 3] = (x[..., 3] - x[..., 1]) / h  # height
    return y



ultralytics.utils.ops.xywh2ltwh(x)

Chuyển đổi định dạng hộp giới hạn từ [x, y, w, h] thành [x1, y1, w, h], trong đó x1, y1 là tọa độ trên cùng bên trái.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

Đầu vào tensor với tọa độ hộp giới hạn ở định dạng XYWH

bắt buộc

Trở lại:

Tên Kiểu Sự miêu tả
y ndarray | Tensor

Tọa độ hộp giới hạn theo định dạng xyltwh

Mã nguồn trong ultralytics/utils/ops.py
def xywh2ltwh(x):
    """
    Convert the bounding box format from [x, y, w, h] to [x1, y1, w, h], where x1, y1 are the top-left coordinates.

    Args:
        x (np.ndarray | torch.Tensor): The input tensor with the bounding box coordinates in the xywh format

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in the xyltwh format
    """
    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
    y[..., 0] = x[..., 0] - x[..., 2] / 2  # top left x
    y[..., 1] = x[..., 1] - x[..., 3] / 2  # top left y
    return y



ultralytics.utils.ops.xyxy2ltwh(x)

Chuyển đổi các hộp giới hạn nx4 từ [x1, y1, x2, y2] thành [x1, y1, w, h], trong đó xy1 = trên cùng bên trái, xy2 = dưới cùng bên phải.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

Đầu vào tensor với tọa độ các hộp giới hạn theo định dạng XYXY

bắt buộc

Trở lại:

Tên Kiểu Sự miêu tả
y ndarray | Tensor

Tọa độ hộp giới hạn theo định dạng xyltwh.

Mã nguồn trong ultralytics/utils/ops.py
def xyxy2ltwh(x):
    """
    Convert nx4 bounding boxes from [x1, y1, x2, y2] to [x1, y1, w, h], where xy1=top-left, xy2=bottom-right.

    Args:
        x (np.ndarray | torch.Tensor): The input tensor with the bounding boxes coordinates in the xyxy format

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in the xyltwh format.
    """
    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
    y[..., 2] = x[..., 2] - x[..., 0]  # width
    y[..., 3] = x[..., 3] - x[..., 1]  # height
    return y



ultralytics.utils.ops.ltwh2xywh(x)

Chuyển đổi hộp nx4 từ [x1, y1, w, h] thành [x, y, w, h] trong đó xy1 = trên cùng bên trái, xy = trung tâm.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x Tensor

Đầu vào tensor

bắt buộc

Trở lại:

Tên Kiểu Sự miêu tả
y ndarray | Tensor

Tọa độ hộp giới hạn theo định dạng xywh.

Mã nguồn trong ultralytics/utils/ops.py
def ltwh2xywh(x):
    """
    Convert nx4 boxes from [x1, y1, w, h] to [x, y, w, h] where xy1=top-left, xy=center.

    Args:
        x (torch.Tensor): the input tensor

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in the xywh format.
    """
    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
    y[..., 0] = x[..., 0] + x[..., 2] / 2  # center x
    y[..., 1] = x[..., 1] + x[..., 3] / 2  # center y
    return y



ultralytics.utils.ops.xyxyxyxy2xywhr(x)

Chuyển đổi các hộp giới hạn định hướng hàng loạt (OBB) từ [xy1, xy2, xy3, xy4] thành [xywh, xoay]. Giá trị xoay là: dự kiến ở độ từ 0 đến 90.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

Input box corners [xy1, xy2, xy3, xy4] of shape (n, 8).

bắt buộc

Trở lại:

Kiểu Sự miêu tả
ndarray | Tensor

Dữ liệu được chuyển đổi ở định dạng [cx, cy, w, h, xoay] của hình dạng (n, 5).

Mã nguồn trong ultralytics/utils/ops.py
def xyxyxyxy2xywhr(x):
    """
    Convert batched Oriented Bounding Boxes (OBB) from [xy1, xy2, xy3, xy4] to [xywh, rotation]. Rotation values are
    expected in degrees from 0 to 90.

    Args:
        x (numpy.ndarray | torch.Tensor): Input box corners [xy1, xy2, xy3, xy4] of shape (n, 8).

    Returns:
        (numpy.ndarray | torch.Tensor): Converted data in [cx, cy, w, h, rotation] format of shape (n, 5).
    """
    is_torch = isinstance(x, torch.Tensor)
    points = x.cpu().numpy() if is_torch else x
    points = points.reshape(len(x), -1, 2)
    rboxes = []
    for pts in points:
        # NOTE: Use cv2.minAreaRect to get accurate xywhr,
        # especially some objects are cut off by augmentations in dataloader.
        (cx, cy), (w, h), angle = cv2.minAreaRect(pts)
        rboxes.append([cx, cy, w, h, angle / 180 * np.pi])
    return torch.tensor(rboxes, device=x.device, dtype=x.dtype) if is_torch else np.asarray(rboxes)



ultralytics.utils.ops.xywhr2xyxyxyxy(x)

Chuyển đổi các hộp giới hạn định hướng hàng loạt (OBB) từ [xywh, xoay] sang [xy1, xy2, xy3, xy4]. Giá trị xoay nên ở độ từ 0 đến 90.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

Các hộp ở định dạng [cx, cy, w, h, xoay] có hình dạng (n, 5) hoặc (b, n, 5).

bắt buộc

Trở lại:

Kiểu Sự miêu tả
ndarray | Tensor

Các điểm góc được chuyển đổi có hình dạng (n, 4, 2) hoặc (b, n, 4, 2).

Mã nguồn trong ultralytics/utils/ops.py
def xywhr2xyxyxyxy(x):
    """
    Convert batched Oriented Bounding Boxes (OBB) from [xywh, rotation] to [xy1, xy2, xy3, xy4]. Rotation values should
    be in degrees from 0 to 90.

    Args:
        x (numpy.ndarray | torch.Tensor): Boxes in [cx, cy, w, h, rotation] format of shape (n, 5) or (b, n, 5).

    Returns:
        (numpy.ndarray | torch.Tensor): Converted corner points of shape (n, 4, 2) or (b, n, 4, 2).
    """
    cos, sin, cat, stack = (
        (torch.cos, torch.sin, torch.cat, torch.stack)
        if isinstance(x, torch.Tensor)
        else (np.cos, np.sin, np.concatenate, np.stack)
    )

    ctr = x[..., :2]
    w, h, angle = (x[..., i : i + 1] for i in range(2, 5))
    cos_value, sin_value = cos(angle), sin(angle)
    vec1 = [w / 2 * cos_value, w / 2 * sin_value]
    vec2 = [-h / 2 * sin_value, h / 2 * cos_value]
    vec1 = cat(vec1, -1)
    vec2 = cat(vec2, -1)
    pt1 = ctr + vec1 + vec2
    pt2 = ctr + vec1 - vec2
    pt3 = ctr - vec1 - vec2
    pt4 = ctr - vec1 + vec2
    return stack([pt1, pt2, pt3, pt4], -2)



ultralytics.utils.ops.ltwh2xyxy(x)

Nó chuyển đổi hộp giới hạn từ [x1, y1, w, h] thành [x1, y1, x2, y2] trong đó xy1 = trên cùng bên trái, xy2 = dưới cùng bên phải.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
x ndarray | Tensor

hình ảnh đầu vào

bắt buộc

Trở lại:

Tên Kiểu Sự miêu tả
y ndarray | Tensor

tọa độ xyxy của các hộp giới hạn.

Mã nguồn trong ultralytics/utils/ops.py
def ltwh2xyxy(x):
    """
    It converts the bounding box from [x1, y1, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right.

    Args:
        x (np.ndarray | torch.Tensor): the input image

    Returns:
        y (np.ndarray | torch.Tensor): the xyxy coordinates of the bounding boxes.
    """
    y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x)
    y[..., 2] = x[..., 2] + x[..., 0]  # width
    y[..., 3] = x[..., 3] + x[..., 1]  # height
    return y



ultralytics.utils.ops.segments2boxes(segments)

Nó chuyển đổi nhãn phân đoạn thành nhãn hộp, tức là (cls, xy1, xy2, ...) thành (cls, xywh)

Thông số:

Tên Kiểu Sự miêu tả Mặc định
segments list

Danh sách các đoạn, mỗi đoạn là một danh sách các điểm, mỗi điểm là một danh sách tọa độ x, y

bắt buộc

Trở lại:

Kiểu Sự miêu tả
ndarray

tọa độ XYWH của các hộp giới hạn.

Mã nguồn trong ultralytics/utils/ops.py
def segments2boxes(segments):
    """
    It converts segment labels to box labels, i.e. (cls, xy1, xy2, ...) to (cls, xywh)

    Args:
        segments (list): list of segments, each segment is a list of points, each point is a list of x, y coordinates

    Returns:
        (np.ndarray): the xywh coordinates of the bounding boxes.
    """
    boxes = []
    for s in segments:
        x, y = s.T  # segment xy
        boxes.append([x.min(), y.min(), x.max(), y.max()])  # cls, xyxy
    return xyxy2xywh(np.array(boxes))  # cls, xywh



ultralytics.utils.ops.resample_segments(segments, n=1000)

Nhập danh sách các phân đoạn (n,2) và trả về danh sách các phân đoạn (n,2) được lấy mẫu lên đến n điểm mỗi đoạn.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
segments list

Một danh sách các mảng (n,2), trong đó n là số điểm trong đoạn.

bắt buộc
n int

số điểm để lấy mẫu lại phân đoạn đến. Mặc định là 1000

1000

Trở lại:

Tên Kiểu Sự miêu tả
segments list

các phân đoạn được lấy mẫu lại.

Mã nguồn trong ultralytics/utils/ops.py
def resample_segments(segments, n=1000):
    """
    Inputs a list of segments (n,2) and returns a list of segments (n,2) up-sampled to n points each.

    Args:
        segments (list): a list of (n,2) arrays, where n is the number of points in the segment.
        n (int): number of points to resample the segment to. Defaults to 1000

    Returns:
        segments (list): the resampled segments.
    """
    for i, s in enumerate(segments):
        s = np.concatenate((s, s[0:1, :]), axis=0)
        x = np.linspace(0, len(s) - 1, n)
        xp = np.arange(len(s))
        segments[i] = (
            np.concatenate([np.interp(x, xp, s[:, i]) for i in range(2)], dtype=np.float32).reshape(2, -1).T
        )  # segment xy
    return segments



ultralytics.utils.ops.crop_mask(masks, boxes)

Nó lấy một mặt nạ và một hộp giới hạn, và trả về một mặt nạ được cắt vào hộp giới hạn.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
masks Tensor

[n, h, w] tensor Số lượng mặt nạ

bắt buộc
boxes Tensor

[n, 4] tensor của tọa độ bbox ở dạng điểm tương đối

bắt buộc

Trở lại:

Kiểu Sự miêu tả
Tensor

Các mặt nạ đang được cắt vào hộp giới hạn.

Mã nguồn trong ultralytics/utils/ops.py
def crop_mask(masks, boxes):
    """
    It takes a mask and a bounding box, and returns a mask that is cropped to the bounding box.

    Args:
        masks (torch.Tensor): [n, h, w] tensor of masks
        boxes (torch.Tensor): [n, 4] tensor of bbox coordinates in relative point form

    Returns:
        (torch.Tensor): The masks are being cropped to the bounding box.
    """
    _, h, w = masks.shape
    x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1)  # x1 shape(n,1,1)
    r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :]  # rows shape(1,1,w)
    c = torch.arange(h, device=masks.device, dtype=x1.dtype)[None, :, None]  # cols shape(1,h,1)

    return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))



ultralytics.utils.ops.process_mask_upsample(protos, masks_in, bboxes, shape)

Lấy đầu ra của đầu mặt nạ và áp dụng mặt nạ vào các hộp giới hạn. Điều này tạo ra mặt nạ chất lượng cao hơn nhưng chậm hơn.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
protos Tensor

[mask_dim, mask_h, mask_w]

bắt buộc
masks_in Tensor

[n, mask_dim], n là số mặt nạ sau nms

bắt buộc
bboxes Tensor

[n, 4], n là số mặt nạ sau nms

bắt buộc
shape tuple

Kích thước của hình ảnh đầu vào (H, W)

bắt buộc

Trở lại:

Kiểu Sự miêu tả
Tensor

Những chiếc khẩu trang được lấy mẫu.

Mã nguồn trong ultralytics/utils/ops.py
def process_mask_upsample(protos, masks_in, bboxes, shape):
    """
    Takes the output of the mask head, and applies the mask to the bounding boxes. This produces masks of higher quality
    but is slower.

    Args:
        protos (torch.Tensor): [mask_dim, mask_h, mask_w]
        masks_in (torch.Tensor): [n, mask_dim], n is number of masks after nms
        bboxes (torch.Tensor): [n, 4], n is number of masks after nms
        shape (tuple): the size of the input image (h,w)

    Returns:
        (torch.Tensor): The upsampled masks.
    """
    c, mh, mw = protos.shape  # CHW
    masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw)
    masks = F.interpolate(masks[None], shape, mode="bilinear", align_corners=False)[0]  # CHW
    masks = crop_mask(masks, bboxes)  # CHW
    return masks.gt_(0.5)



ultralytics.utils.ops.process_mask(protos, masks_in, bboxes, shape, upsample=False)

Áp dụng mặt nạ vào các hộp giới hạn bằng cách sử dụng đầu ra của đầu mặt nạ.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
protos Tensor

Một tensor của hình dạng [mask_dim, mask_h, mask_w].

bắt buộc
masks_in Tensor

Một tensor có hình dạng [n, mask_dim], trong đó n là số mặt nạ sau NMS.

bắt buộc
bboxes Tensor

Một tensor có hình dạng [n, 4], trong đó n là số mặt nạ sau NMS.

bắt buộc
shape tuple

Một bộ số nguyên đại diện cho kích thước của hình ảnh đầu vào ở định dạng (h, w).

bắt buộc
upsample bool

Một lá cờ để cho biết có nên lấy mẫu mặt nạ về kích thước hình ảnh gốc hay không. Mặc định là False.

False

Trở lại:

Kiểu Sự miêu tả
Tensor

Mặt nạ nhị phân tensor có hình dạng [n, h, w], trong đó n là số mặt nạ sau NMS, và h và w là chiều cao và chiều rộng của hình ảnh đầu vào. Mặt nạ được áp dụng cho các hộp giới hạn.

Mã nguồn trong ultralytics/utils/ops.py
def process_mask(protos, masks_in, bboxes, shape, upsample=False):
    """
    Apply masks to bounding boxes using the output of the mask head.

    Args:
        protos (torch.Tensor): A tensor of shape [mask_dim, mask_h, mask_w].
        masks_in (torch.Tensor): A tensor of shape [n, mask_dim], where n is the number of masks after NMS.
        bboxes (torch.Tensor): A tensor of shape [n, 4], where n is the number of masks after NMS.
        shape (tuple): A tuple of integers representing the size of the input image in the format (h, w).
        upsample (bool): A flag to indicate whether to upsample the mask to the original image size. Default is False.

    Returns:
        (torch.Tensor): A binary mask tensor of shape [n, h, w], where n is the number of masks after NMS, and h and w
            are the height and width of the input image. The mask is applied to the bounding boxes.
    """

    c, mh, mw = protos.shape  # CHW
    ih, iw = shape
    masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw)  # CHW
    width_ratio = mw / iw
    height_ratio = mh / ih

    downsampled_bboxes = bboxes.clone()
    downsampled_bboxes[:, 0] *= width_ratio
    downsampled_bboxes[:, 2] *= width_ratio
    downsampled_bboxes[:, 3] *= height_ratio
    downsampled_bboxes[:, 1] *= height_ratio

    masks = crop_mask(masks, downsampled_bboxes)  # CHW
    if upsample:
        masks = F.interpolate(masks[None], shape, mode="bilinear", align_corners=False)[0]  # CHW
    return masks.gt_(0.5)



ultralytics.utils.ops.process_mask_native(protos, masks_in, bboxes, shape)

Nó lấy đầu ra của đầu mặt nạ và cắt nó sau khi lấy mẫu lên các hộp giới hạn.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
protos Tensor

[mask_dim, mask_h, mask_w]

bắt buộc
masks_in Tensor

[n, mask_dim], n là số mặt nạ sau nms

bắt buộc
bboxes Tensor

[n, 4], n là số mặt nạ sau nms

bắt buộc
shape tuple

Kích thước của hình ảnh đầu vào (H, W)

bắt buộc

Trở lại:

Tên Kiểu Sự miêu tả
masks Tensor

Mặt nạ trả lại có kích thước [h, w, n]

Mã nguồn trong ultralytics/utils/ops.py
def process_mask_native(protos, masks_in, bboxes, shape):
    """
    It takes the output of the mask head, and crops it after upsampling to the bounding boxes.

    Args:
        protos (torch.Tensor): [mask_dim, mask_h, mask_w]
        masks_in (torch.Tensor): [n, mask_dim], n is number of masks after nms
        bboxes (torch.Tensor): [n, 4], n is number of masks after nms
        shape (tuple): the size of the input image (h,w)

    Returns:
        masks (torch.Tensor): The returned masks with dimensions [h, w, n]
    """
    c, mh, mw = protos.shape  # CHW
    masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw)
    masks = scale_masks(masks[None], shape)[0]  # CHW
    masks = crop_mask(masks, bboxes)  # CHW
    return masks.gt_(0.5)



ultralytics.utils.ops.scale_masks(masks, shape, padding=True)

Thay đổi tỷ lệ mặt nạ phân đoạn để định hình.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
masks Tensor

(N, C, H, W).

bắt buộc
shape tuple

Chiều cao và chiều rộng.

bắt buộc
padding bool

Nếu True, giả sử các hộp dựa trên hình ảnh được tăng cường bởi yolo phong cách. Nếu False thì làm thường xuyên thay đổi quy mô.

True
Mã nguồn trong ultralytics/utils/ops.py
def scale_masks(masks, shape, padding=True):
    """
    Rescale segment masks to shape.

    Args:
        masks (torch.Tensor): (N, C, H, W).
        shape (tuple): Height and width.
        padding (bool): If True, assuming the boxes is based on image augmented by yolo style. If False then do regular
            rescaling.
    """
    mh, mw = masks.shape[2:]
    gain = min(mh / shape[0], mw / shape[1])  # gain  = old / new
    pad = [mw - shape[1] * gain, mh - shape[0] * gain]  # wh padding
    if padding:
        pad[0] /= 2
        pad[1] /= 2
    top, left = (int(pad[1]), int(pad[0])) if padding else (0, 0)  # y, x
    bottom, right = (int(mh - pad[1]), int(mw - pad[0]))
    masks = masks[..., top:bottom, left:right]

    masks = F.interpolate(masks, shape, mode="bilinear", align_corners=False)  # NCHW
    return masks



ultralytics.utils.ops.scale_coords(img1_shape, coords, img0_shape, ratio_pad=None, normalize=False, padding=True)

Thay đổi tỷ lệ tọa độ phân đoạn (xy) từ img1_shape thành img0_shape.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
img1_shape tuple

Hình dạng của hình ảnh mà tọa độ đến từ.

bắt buộc
coords Tensor

Các tọa độ được chia tỷ lệ hình n,2.

bắt buộc
img0_shape tuple

hình dạng của hình ảnh mà phân đoạn đang được áp dụng.

bắt buộc
ratio_pad tuple

tỷ lệ giữa kích thước hình ảnh với kích thước hình ảnh đệm.

None
normalize bool

Nếu True, tọa độ sẽ được chuẩn hóa thành phạm vi [0, 1]. Mặc định là False.

False
padding bool

Nếu True, giả sử các hộp dựa trên hình ảnh được tăng cường bởi yolo phong cách. Nếu False thì làm thường xuyên thay đổi quy mô.

True

Trở lại:

Tên Kiểu Sự miêu tả
coords Tensor

Các tọa độ được chia tỷ lệ.

Mã nguồn trong ultralytics/utils/ops.py
def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None, normalize=False, padding=True):
    """
    Rescale segment coordinates (xy) from img1_shape to img0_shape.

    Args:
        img1_shape (tuple): The shape of the image that the coords are from.
        coords (torch.Tensor): the coords to be scaled of shape n,2.
        img0_shape (tuple): the shape of the image that the segmentation is being applied to.
        ratio_pad (tuple): the ratio of the image size to the padded image size.
        normalize (bool): If True, the coordinates will be normalized to the range [0, 1]. Defaults to False.
        padding (bool): If True, assuming the boxes is based on image augmented by yolo style. If False then do regular
            rescaling.

    Returns:
        coords (torch.Tensor): The scaled coordinates.
    """
    if ratio_pad is None:  # calculate from img0_shape
        gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1])  # gain  = old / new
        pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2  # wh padding
    else:
        gain = ratio_pad[0][0]
        pad = ratio_pad[1]

    if padding:
        coords[..., 0] -= pad[0]  # x padding
        coords[..., 1] -= pad[1]  # y padding
    coords[..., 0] /= gain
    coords[..., 1] /= gain
    coords = clip_coords(coords, img0_shape)
    if normalize:
        coords[..., 0] /= img0_shape[1]  # width
        coords[..., 1] /= img0_shape[0]  # height
    return coords



ultralytics.utils.ops.regularize_rboxes(rboxes)

Thường xuyên hóa các hộp xoay trong phạm vi [0, pi / 2].

Thông số:

Tên Kiểu Sự miêu tả Mặc định
rboxes Tensor

Input boxes of shape(N, 5) in xywhr format.

bắt buộc

Trở lại:

Kiểu Sự miêu tả
Tensor

Các hộp thông thường.

Mã nguồn trong ultralytics/utils/ops.py
def regularize_rboxes(rboxes):
    """
    Regularize rotated boxes in range [0, pi/2].

    Args:
        rboxes (torch.Tensor): Input boxes of shape(N, 5) in xywhr format.

    Returns:
        (torch.Tensor): The regularized boxes.
    """
    x, y, w, h, t = rboxes.unbind(dim=-1)
    # Swap edge and angle if h >= w
    w_ = torch.where(w > h, w, h)
    h_ = torch.where(w > h, h, w)
    t = torch.where(w > h, t, t + math.pi / 2) % math.pi
    return torch.stack([x, y, w_, h_, t], dim=-1)  # regularized boxes



ultralytics.utils.ops.masks2segments(masks, strategy='largest')

Nó lấy một danh sách các mặt nạ (n, h, w) và trả về một danh sách các phân đoạn (n, xy)

Thông số:

Tên Kiểu Sự miêu tả Mặc định
masks Tensor

đầu ra của mô hình, đó là một tensor Hình dạng (batch_size, 160, 160)

bắt buộc
strategy str

'concat' hoặc 'lớn nhất'. Mặc định là lớn nhất

'largest'

Trở lại:

Tên Kiểu Sự miêu tả
segments List

Danh sách mặt nạ phân đoạn

Mã nguồn trong ultralytics/utils/ops.py
def masks2segments(masks, strategy="largest"):
    """
    It takes a list of masks(n,h,w) and returns a list of segments(n,xy)

    Args:
        masks (torch.Tensor): the output of the model, which is a tensor of shape (batch_size, 160, 160)
        strategy (str): 'concat' or 'largest'. Defaults to largest

    Returns:
        segments (List): list of segment masks
    """
    segments = []
    for x in masks.int().cpu().numpy().astype("uint8"):
        c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
        if c:
            if strategy == "concat":  # concatenate all segments
                c = np.concatenate([x.reshape(-1, 2) for x in c])
            elif strategy == "largest":  # select largest segment
                c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
        else:
            c = np.zeros((0, 2))  # no segments found
        segments.append(c.astype("float32"))
    return segments



ultralytics.utils.ops.convert_torch2numpy_batch(batch)

Chuyển đổi một lô FP32 torch tensor (0.0-1.0) thành mảng uint8 NumPy (0-255), thay đổi từ bố cục BCHW sang BHWC.

Thông số:

Tên Kiểu Sự miêu tả Mặc định
batch Tensor

Nhập tensor lô hình dạng (Batch, Channel, Height, Width) và dtype torch.float32.

bắt buộc

Trở lại:

Kiểu Sự miêu tả
ndarray

Đầu ra hàng loạt mảng NumPy có hình dạng (Batch, Height, Width, Channels) và dtype uint8.

Mã nguồn trong ultralytics/utils/ops.py
def convert_torch2numpy_batch(batch: torch.Tensor) -> np.ndarray:
    """
    Convert a batch of FP32 torch tensors (0.0-1.0) to a NumPy uint8 array (0-255), changing from BCHW to BHWC layout.

    Args:
        batch (torch.Tensor): Input tensor batch of shape (Batch, Channels, Height, Width) and dtype torch.float32.

    Returns:
        (np.ndarray): Output NumPy array batch of shape (Batch, Height, Width, Channels) and dtype uint8.
    """
    return (batch.permute(0, 2, 3, 1).contiguous() * 255).clamp(0, 255).to(torch.uint8).cpu().numpy()



ultralytics.utils.ops.clean_str(s)

Làm sạch chuỗi bằng cách thay thế các ký tự đặc biệt bằng dấu gạch dưới _

Thông số:

Tên Kiểu Sự miêu tả Mặc định
s str

một chuỗi cần thay thế các ký tự đặc biệt

bắt buộc

Trở lại:

Kiểu Sự miêu tả
str

một chuỗi có các ký tự đặc biệt được thay thế bằng dấu gạch dưới _

Mã nguồn trong ultralytics/utils/ops.py
def clean_str(s):
    """
    Cleans a string by replacing special characters with underscore _

    Args:
        s (str): a string needing special characters replaced

    Returns:
        (str): a string with special characters replaced by an underscore _
    """
    return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s)





Created 2023-11-12, Updated 2024-06-02
Authors: glenn-jocher (6), Burhan-Q (1), Laughing-q (1)