|
""" |
|
Based on https://pypi.org/project/pyEdgeEval/0.2.6 |
|
Cite: http://arxiv.org/abs/2304.09427 |
|
""" |
|
|
|
from typing import List |
|
|
|
import cv2 |
|
import numpy as np |
|
|
|
|
|
def mask2bdry(mask: np.ndarray, ignore_mask: np.ndarray, thickness: int, quality: int = 5) -> np.ndarray: |
|
""" |
|
Convert binary mask to boundaries. |
|
|
|
Args: |
|
mask (np.ndarray): 2D binary mask |
|
ignore_mask (np.ndarray): 2D binary mask |
|
thickness (int): boundary thickness |
|
quality (int): distance transform quality |
|
|
|
Returns: |
|
bdry (np.ndarray): 2D binary boundary mask |
|
""" |
|
inner = cv2.distanceTransform(((mask + ignore_mask) > 0).astype(np.uint8), cv2.DIST_L2, quality) |
|
outer = cv2.distanceTransform(((1.0 - mask) > 0).astype(np.uint8), cv2.DIST_L2, quality) |
|
dist = outer + inner |
|
|
|
dist[dist > thickness] = 0 |
|
bdry = (dist > 0).astype(np.uint8) |
|
return bdry |
|
|
|
|
|
def mask2sbd(mask: np.ndarray, ignore_indices: List, thickness: int = 4, quality: int = 5) -> np.ndarray: |
|
""" |
|
Convert Segmentation Mask to Semantic Boundaries. |
|
|
|
Args: |
|
mask (np.ndarray): segmentation mask |
|
ignore_indicies (List[int]): list of indices to ignore |
|
thickness (int): boundary thickness |
|
quality (int): distance transform quality |
|
|
|
Returns: |
|
bdrys (np.ndarray): 3D array containing boundaries |
|
""" |
|
assert mask.ndim == 3 |
|
num_labels, h, w = mask.shape |
|
|
|
|
|
ignore_mask = np.zeros((h, w), dtype=np.uint8) |
|
for i in ignore_indices: |
|
ignore_mask += mask[i] |
|
|
|
bdrys = np.zeros_like(mask) |
|
for label in range(num_labels): |
|
m = mask[label] |
|
|
|
if label in ignore_indices: |
|
continue |
|
|
|
|
|
if not np.count_nonzero(m): |
|
continue |
|
|
|
edge = mask2bdry( |
|
mask=m, |
|
ignore_mask=ignore_mask, |
|
thickness=thickness, |
|
quality=quality, |
|
) |
|
|
|
bdrys[label] = edge |
|
|
|
return bdrys |
|
|