Create a :class:`CompactMask` from a dense ``(N, H, W)`` bool array. Bounding boxes are clipped to image bounds and interpreted in the supervision ``xyxy`` convention (inclusive max coordinates). A box with invalid ordering (``x2 < x1`` or ``y2 < y1``) is replaced by
(
cls,
masks: npt.NDArray[np.bool_],
xyxy: npt.NDArray[Any],
image_shape: tuple[int, int],
)
| 474 | |
| 475 | @classmethod |
| 476 | def from_dense( |
| 477 | cls, |
| 478 | masks: npt.NDArray[np.bool_], |
| 479 | xyxy: npt.NDArray[Any], |
| 480 | image_shape: tuple[int, int], |
| 481 | ) -> CompactMask: |
| 482 | """Create a :class:`CompactMask` from a dense ``(N, H, W)`` bool array. |
| 483 | |
| 484 | Bounding boxes are clipped to image bounds and interpreted in the |
| 485 | supervision ``xyxy`` convention (inclusive max coordinates). A |
| 486 | box with invalid ordering (``x2 < x1`` or ``y2 < y1``) is replaced by |
| 487 | a ``1x1`` all-False crop to avoid degenerate RLE. |
| 488 | |
| 489 | Args: |
| 490 | masks: Dense boolean mask array of shape ``(N, H, W)``. |
| 491 | xyxy: Bounding boxes of shape ``(N, 4)`` in ``[x1, y1, x2, y2]`` |
| 492 | format. |
| 493 | image_shape: ``(H, W)`` of the full image. |
| 494 | |
| 495 | Returns: |
| 496 | A new :class:`CompactMask` instance. |
| 497 | |
| 498 | Examples: |
| 499 | ```pycon |
| 500 | >>> import numpy as np |
| 501 | >>> from supervision.detection.compact_mask import CompactMask |
| 502 | >>> masks = np.zeros((1, 100, 100), dtype=bool) |
| 503 | >>> masks[0, 10:20, 10:20] = True |
| 504 | >>> xyxy = np.array([[10, 10, 19, 19]], dtype=np.float32) |
| 505 | >>> cm = CompactMask.from_dense(masks, xyxy, image_shape=(100, 100)) |
| 506 | >>> cm.shape |
| 507 | (1, 100, 100) |
| 508 | |
| 509 | ``` |
| 510 | """ |
| 511 | img_h, img_w = image_shape |
| 512 | num_masks = len(masks) |
| 513 | |
| 514 | if num_masks == 0: |
| 515 | return cls( |
| 516 | [], |
| 517 | np.empty((0, 2), dtype=np.int32), |
| 518 | np.empty((0, 2), dtype=np.int32), |
| 519 | image_shape, |
| 520 | ) |
| 521 | |
| 522 | rles: list[npt.NDArray[np.int32]] = [] |
| 523 | crop_shapes_list: list[tuple[int, int]] = [] |
| 524 | offsets_list: list[tuple[int, int]] = [] |
| 525 | |
| 526 | for mask_idx in range(num_masks): |
| 527 | x1, y1, x2, y2 = xyxy[mask_idx] |
| 528 | x1c = int(max(0, min(int(x1), img_w - 1))) |
| 529 | y1c = int(max(0, min(int(y1), img_h - 1))) |
| 530 | x2c = int(max(0, min(int(x2), img_w - 1))) |
| 531 | y2c = int(max(0, min(int(y2), img_h - 1))) |
| 532 | crop: npt.NDArray[np.bool_] |
| 533 |