Source code for tomni.transformers.mask2json.main

import cv2
import numpy as np

from ..contours2json import contours2json
from ..labels2contours import labels2contours


def get_edges(mask: np.ndarray):
    """
    Extracts and returns the edges of a binary mask image.

    This function uses the Canny edge detection algorithm to identify edges in the input binary mask image.

    Args:
        mask (np.ndarray): A binary mask represented as a NumPy array, where 1 indicates the object of interest,
            and 0 indicates the background.

    Returns:
        np.ndarray: A binary image representing the edges of the input mask. Pixels along edges are set to 1,
            while non-edge pixels are set to 0.
    """
    mask_copy = cv2.copyMakeBorder(
        mask,
        top=1,
        bottom=1,
        left=1,
        right=1,
        borderType=cv2.BORDER_CONSTANT,
        value=0,
    )
    edges = cv2.Canny(mask_copy, 50, 150)

    edges = cv2.dilate(edges, np.ones((5, 5)))

    edges = np.divide(edges, 255, dtype=np.float16)
    edges = edges.astype(np.uint8)
    edges = edges[1:-1, 1:-1]

    return edges


[docs]def mask2json( mask: np.ndarray, minimum_size_contours: int = 3, is_diagonal_connected=True, return_inner_contours: bool = False, ) -> list: """ Converts a binary mask into a list of JSON objects representing contours. Args: mask (np.ndarray): A binary mask represented as a NumPy array. minimum_size_contours (int, optional): The minimum number of points a contour should have to be included. Contours with fewer points will be excluded. Defaults to 3. is_diagonal_connected (bool, optional): If True, diagonal pixels (e.g., [[1, 0], [0, 1]]) will be considered part of the same object during contour extraction. Defaults to True. return_inner_contours (bool, optional): If True, include internal contours (holes within the shape). If False, only return the external contours (outlines of the shapes). Defaults to False. Returns: list: A list of JSON objects representing contours in the mask. Example output:: { 'type': 'polygon', 'points': [{'x': x1, 'y': y1}, {'x': x2, 'y': y2}, ...], 'innerObjects': [ { 'type': 'polygon', 'points': [{'x': x3, 'y': y3}, {'x': x4, 'y': y4}, ...], }, ], } """ connectivity = 4 if is_diagonal_connected: connectivity = 8 labels = cv2.connectedComponents(mask.astype(np.uint8), connectivity=connectivity)[ 1 ] edges = get_edges(mask) edges = edges * labels del labels contours = labels2contours(edges, return_inner_contours=return_inner_contours) if return_inner_contours: json_objects = [] for contour in contours: json_object = contours2json([contour[0]])[0] json_object["innerObjects"] = contours2json(contour[1]) json_objects.append(json_object) else: json_objects = contours2json(contours) json_objects = [ json_object for i, json_object in enumerate(json_objects) if len(json_objects[i]["points"]) >= minimum_size_contours ] return json_objects